Skip to content

MicroWebStacks/astro-examples

main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

showcase examples for isolated simple usage patterns

01_basics

./01_basics

This is a minimal example that shows the node version running

Open in StackBlitz open in Codesandbox open in Gitpod

02_ssr-counter

./02_ssr-counter

shared global var demo. reload the page to increment the counter. All pages share the same counter

Open in StackBlitz open in Codesandbox open in Gitpod

03_sse-counter

./03_sse-counter

SSE: Server Sent Events. global var using a timer and Emitter

Server keeps couter state. reloading the page has no effect on the counter

requires Node18 Node18 for ReadableStream(), currently only on Gitpod

open in Gitpod

04_client-counters

./04_client-counters

A simple approach for multiple instances of a component. A <script> is included once. It initiates all components of a class on page load without requiring unique identification

Open in StackBlitz open in Codesandbox open in Gitpod

05_client-uid-counters

./05_client-uid-counters

Decentralized scoping js execution on an Astro component used mutiple times on the same page

Constraints :

  • decentralized : not conflicting with multiple integrations using the same concept
  • no global state management : which is not easy to fulfill when using components from different sources
  • multi instances used on the same page
  • components handle their own js scripts
  • each component has a lifecylce independence and its js only handles its own html and not one of other instances

Alternatives:

  • It is always possible to initialize all components from the top page js, but sometimes the js component code is preferrably placed within the component itself.
  • It is also possible within the component to have the code run on all components in the page of the same type, but this does not fit with lazy loading where each component has to be initialize separately
  • It is still possible to keep a component state in the window or as html attribute and still run init on all components everytime a new one wakes up, but this might incur incompatibilities when mixing versions
  • A centralized approach is also demonstrated but not recommend due to flaws that might happen when the sequence_uid function gets multiple instances for some reason such as being budled separately.

Optionally:

  • a hash function could be used if an unidentifieable id is desired that does not reflect the user input (using counting numbers or names,...), if the input data is too big such as complete file or if the uid is required to always have the same consistent format e.g. number of characters which the user cannot guarantee.

Open in StackBlitz open in Codesandbox open in Gitpod

06_astro-xelement

./06_astro-xelement

Using unified config for all of astro.config.mjs, .astro and .js server files

Open in StackBlitz open in Codesandbox open in Gitpod

07_env-config

./07_env-config

using environment variables from file in astro.config.mjs and .js server files

  • integration : @astrojs/node

  • adapter : node-standalone

  • dotenv

  • todo test with loadEnv from 'vite'

Open in StackBlitz open in Codesandbox open in Gitpod

08_404-error-handling

./08_404-error-handling

Page not found redirect to 404

Open in StackBlitz open in Codesandbox open in Gitpod

custom 404 page from : https://codepen.io/Stephane/pen/Jdozrp

09_dynamic-imports

./09_dynamic-imports

  • integration : @astrojs/node
  • adapter : node-standalone
  • Deferr loading of js on event or timeout
    • setTimeout
    • Dynamic import()
    • Spinner while waiting : Astro Component with animated SVG

This is about dynamically importing a js script only when the component logic decides to do it. In this case, after 2 seconds from window load.

Not only <Card title="Test" client:visible/> is not supported by astro as directive reserved for framework components only, but also, it does not give fine granularity to decide exactly when to load a js script.

Note: Testing this example only makes sense in production mode (with build and run). Only gitpod left because it has a shell script that builds and runs by default while the others (StackBliz and Codesandbox) run in preview mode.

open in Gitpod

10_prerender

./10_prerender

This example uses the experimental prerender feature. index page '/' is prerendered while '/rerender' page is server side rendered on every fetch

Open in StackBlitz

11_deno-env

./11_deno-env

  • integration : deno
  • adapter : deno

Testing environment variables in deno and deno.deploy

live demo : https://astro-env.deno.dev/

project : https://dash.deno.com/projects/astro-env

open in Codesandbox open in Gitpod

12_content-collections

./12_content-collections

Open in StackBlitz open in Codesandbox open in Gitpod

13_client-cookie-counter

./13_client-cookie-counter

This counter uses a cookie counter=1 to persist through pages relaod despite being a client counter.

For Astro SSR there is a simplicity advantage for using a cookie over using client sotrage :

  • Automatically sent with every client request
  • No display flicker
  • no need to create a server endpoint to submit the client updated value (to avoid the flicker)

Note : Only a single counter is used in this example given that a single cookie is used

Note : For a demo using cookies, the Astro.cookies could only be read in Gitpod

open in Gitpod

references

14_client-storage-counter

./14_client-storage-counter

  • This counter is using sessionStorage for client side persistency, and therefore avoids cookies.
  • For UI sensitive elements (such as menu, sidebar, modal,...) it is important to prevent flicker. Such Flicker can happen when the server sends a default value upon page refresh and then javascript adjusts the value after reading it from the session sotrage. To prevent that, every time the client changes the value, the server state needs to be updated through a put request to a server endpoint
  • For the server to know which client has whic counter, a counters map for each session_id is stored
  • The session ID is created by the server when a request URL does not contain session_id parameter, it is passed to the client within the html components, the client takes it upon page load and use it in case no sessionStorage session_id available. Then stick it to the URL parameters for future queries

Note : this implementation is for demo purpose only and suffers from memory leak as old session_id's are not deleted.

Open in StackBlitz open in Codesandbox open in Gitpod

references

15_server-cookie-counter

./15_server-cookie-counter

  • adapter : node-standalone

Counts the pages load for a specific client with cookies. This examples shows how to get and set a cookie from a .astro page while example 13 gets the cookie from the server and set it from the client.

Open in StackBlitz open in Codesandbox open in Gitpod

16_html-string

./16_html-string

example to show how to generate an html string out of a component using a Wrapper and Astro.slots.render()

Open in StackBlitz open in Codesandbox open in Gitpod

references

17_dynamic-javascript

./17_dynamic-javascript

Generate javascript that can be executed on the client. The UID set by the server, is fetched by the client inside a javascript file

Note : although functional, this method is not recommended due to Vite complaning about dynamic import and security risk it implies.

Open in StackBlitz open in Codesandbox open in Gitpod

18_simple-integration

./18_simple-integration

example using astrojs/image integration

Open in StackBlitz open in Codesandbox open in Gitpod

19_images-integration

./19_images-integration

  • adapter : node-standalone
  • integration : image

example using astrojs/image integration

Open in StackBlitz open in Codesandbox open in Gitpod

20_ssr-cache-proxy

./20_ssr-cache-proxy

  • adapter : node-standalone

  • proxy : express

  • cache event-drive content

  • call purge method

  • put pass througn

Running mode :

  • astro starts with pnpm run preview listens on port 4000
  • express starts with pnpm run proxy listens on port 3000
  • first client page load from proxy : cache miss, proxy fetches data from SSR
  • SSR generates the page and and on creation assigns a page hash
  • for the example purpose a 2 seconds timeout is added to a page render
  • the page hash is updated on the proxy (in the example through a shared hashes.json but could be with a db or API)
  • when the proxy fetches the page it identifies the cached page with its hash (as it is always actual on the hashes.json)
  • follow up request checks if page is available and if hash is fresh
  • when the user updates the data, the server updates the page hash
  • follow up requests on the proxy show the page to be stale due to old cached page, the proxy fetches the page with the new hash

Open in StackBlitz open in Codesandbox open in Gitpod

21_ssr-cache-middleware

./21_ssr-cache-middleware

Same concept as the previous example but here the cache proxy and Astro SSR are combined in the same express App with Astro running in middleware mode

  • once a request is fetched from the SSR server, the response contains an ETag with the hash to ensure immediate page update with the just produced hash value

Open in StackBlitz open in Codesandbox open in Gitpod

22_mdx-svg

./22_mdx-svg

Example for testing SVG usage within .astro, .md and .mdx

This highlights incompatibility of inlined SVG when injected from remark/rehype plugins in an mdx file

  • attributes with ':' e.g. xmlns:xlink gets treated as .jsx and converted to xmlnsXlink, xmlns or xmlnsxlink, all of which break the SVG rendering

Note :

  • html comments not supported
  • html empty new lines of spaces also break the html parsing as indentation takes precendence

Open in StackBlitz open in Codesandbox open in Gitpod

references

23_remote-markdown

./23_remote-markdown

  • adapter : node-standalone

features

  • astro-remote works with astr v2 but not an official integration
  • Passing default components only Heading, CodeBlock, CodeSpan, Note no mapping of custom components, e.g. images,...

Open in StackBlitz open in Codesandbox open in Gitpod

references

24_api-proxy

./24_api-proxy

4 Locations where to alter server config

  • /vite.config.js
  • /astro.config.mjs:server.port,proxy
  • /astro.config.mjs:site.server.port,proxy
  • /src/libs/inetgration-test.js:config_setup().update_config()

summary

  • can Astro proxy a service with the Vite server.proxy feature ?
    • No, Astro does not forward server.proxy to Vite
  • does Astro need a proxy to access a different port running on the same host ?
    • No, because Astro frontmatter runs on the server so has access to localhost ports

Open in StackBlitz open in Codesandbox open in Gitpod

references

25_markdown-scale

./25_markdown-scale

Benchmark results charts : https://microwebstacks.github.io/astro-examples/

  • scalability stress test and limiting facrors (e.g. 15000 pages)
  • markdown pages generator
    • pages markdown
    • pages mdx
    • local markdown in .astro
    • local mdx in .astro
    • remote markdown

Open in StackBlitz open in Codesandbox open in Gitpod

References

26_serverless-counter-netlify

./26_serverless-counter-netlify

shared global var demo. reload the page to increment the counter. All pages share the same counter

Note ! in serverless deployment, the in-memory state only persistes temporarily until a different instance is started

27_serverless-counter-cloudflare

./27_serverless-counter-cloudflare

  • integration : cloudflare
  • adapter : cloudflare
  • NODE_VERSION : 16.19.1
  • cannot rename deployment url after creation

shared global var demo. reload the page to increment the counter. All pages share the same counter

Note ! in serverless deployment, the in-memory state only persistes temporarily until a different instance is started

28_serverless-counter-vercel

./28_serverless-counter-vercel

  • integration : vercel
  • adapter : vercel
  • free account does not deploy from github organization

shared global var demo. reload the page to increment the counter. All pages share the same counter

Note ! in serverless deployment, the in-memory state only persistes temporarily until a different instance is started

29_serverless-counter-denodeploy

./29_serverless-counter-denodeploy

  • integration : deno
  • adapter : deno
  • deployment from command line

shared global var demo. reload the page to increment the counter. All pages share the same counter

Note ! in serverless deployment, the in-memory state only persistes temporarily until a different instance is started

.env not taken has to manually inject env var DENO_DEPLOY_TOKEN

30_serverless-counter-deno-redis

./30_serverless-counter-deno-redis

  • integration : deno
  • adapter : deno
  • database : redis
  • Deno.version not working resulting in crash on deploy

demo for variable persisted on redis database. reload the page to increment the counter. All pages share the same counter.

expected environment variables

  • local DENO_DEPLOY_TOKEN : to be manually injected in the env before calling deploy

  • your redis credentials, needed both locally to be injected manually and on deploy entered on the project settings

    • REDIS_URL=******.redislabs.com
    • REDIS_PORT=*****
    • REDIS_PASSWORD=***********
  • live demo in deno deploy : https://astro-redis-counter.deno.dev/

31_collections-markdoc

./31_collections-markdoc

Status

  • render : OK
  • custom components - nodes : OK
  • custom components - tags : wip

Open in StackBlitz open in Codesandbox open in Gitpod

32_cms-storyblok

./32_cms-storyblok

  • integration : @storyblok/astro
  • env variable in .env file STORYBLOK_TOKEN loaded with vite loadEnv in config.js
  • test with story.http using VSCode REST Client and dotenv from .env

Status

  • render : WIP

Open in StackBlitz open in Codesandbox open in Gitpod

Upcoming

More Astro examples

astro-big doc

Main features :

  • Clean Markdown without js pollution : Layout injected from .astro files
  • Free Path selection : can be placed anywhere within the repo
  • Relative assets management : uses relative assets located in the same directory as the Markdown file
  • Enhancement with Astro components : standard tags can be replaced with an Astro component without touching the Markdown files
  • Modal Images and Gallery Components
  • Nav Bar, Hierarchical menu, Table of Content with scroll spy,...

screenshot :

astro-home-control

Main features :

  • Home Automation MQTT Client running on Astro as SSR
  • Client page update with Server Sent Events
  • Custom switches with feedback and custom sliders with animated SVG

screenshot :

astro-lottie