Astro Guide
Astro is a edge friendly rendering framework commonly deployed with Altitude. Astro promotes a powerful combination of an client-side island architecture that efficiently tree-shakes your chosen UI framework.
Get started
You can find full documentation on Astro’s website.
A common way to get started is to run:
npm create astro@latest
Adapter
Altitude requires the use of Astro’s cloudflare adapter to deploy.
You can install this adapter with this command:
npx astro add cloudflare
Helpful Plugins
Tailwind (Optional)
npx astro add tailwind
GraphQL (Optional)
A Rollup plugin which Converts .gql/.graphql(s) files to ES6 modules.
npm i @rollup/plugin-graphql
export default defineConfig({ //... vite: { plugins: [graphql()], }, //...});
Integration
The Astro Integration package facilitates the efficient management of multi-tenancy and single-tenancy setups for commerce sites. The integration offers an enhanced layer of middleware abstraction, removing tech debt of managing common patterns and functions required to build and run sites into a single easy to use package.
Endpoints
When requesting our commerce, blog or tracking APIs in Astro.
Commerce API Endpoint
By utilising Astro Endpoints you can create an API endpoint to act as the proxy for request to GraphQL APIs.
Here is an example of a Commerce API (Horizon) focused GraphQL proxy. This proxy also ensures that required headers are passed to Horizon and that cookies set by Horizon are also set in the browser.
import axios from "axios";export async function POST({ request, locals }) { const { tenantConfig } = locals; const opaqueCookieDomain = "yourdomain.com"; const horizonEndpoint = "https://horizon-api.www.allsole.com";
let response; let cookieHeaders;
const runtime = locals.runtime;
if (import.meta.env.DEV) { const data = await request.json(); response = await axios({ method: "post", url: `${horizonEndpoint}/graphql`, data, headers: { cookie: request.headers.get("cookie"), "user-agent": request.headers.get("user-agent"), }, });
cookieHeaders = response.headers.get("set-cookie"); response = new Response(JSON.stringify(response.data), response); } else { const clientIp = request.headers.get("fastly-client-ip"); let newRequest = request.clone(); const init = { headers: { ...Object.fromEntries(newRequest.headers), ...{ "X-Trusted-Client-Ip": clientIp }, ...{ "X-Trust-Client-Ip-Key": runtime.env.HORIZON_KEY_TO_TRUST_PROVIDED_CLIENT_IP, }, }, method: newRequest.method, body: newRequest.body, };
response = await fetch(`${horizonEndpoint}/graphql`, init); cookieHeaders = response.headers.getSetCookie(); response = new Response(response.body, response); }
if (response.headers.get("set-cookie")) { let domainReplacement = opaqueCookieDomain ? `domain=${opaqueCookieDomain}` : "";
response.headers.delete("set-cookie"); for (const header of cookieHeaders) { if (header.indexOf("domain") === -1 && header.indexOf("Domain") === -1) { response.headers.append( "set-cookie", `${header}; ${domainReplacement}` ); } else { response.headers.append( "set-cookie", header.replace(/domain=[^;]+/gi, domainReplacement) ); } } }
return response;}
Once this is implemented you can send your client-side GraphQL queries via the /api/horizon/
URL in the browser.
Dynamic Robots Endpoint
Here is an example of how to create an endpoint that dynamically creates a robots.txt
file. This can be useful when developing a multi-tenancy codebase where robots.txt
files change by domain/tenant.
import getRobots from "../../local/getRobots";
export async function GET({ locals }) { return new Response(getRobots(locals.tenantKey));}
Optimisations
Disable Streaming
Astro has a streaming behaviour which doesn’t work well with Cloudflare runtimes (and by proxy Altitude) a significant latency overhead as a result. We suggest disabling streaming by using a suspense pattern. This pattern when used in your layout file will force Astro to wait for the entire HTML response of its contents before responding.
Create a suspense component:
---let html = ''
if (Astro.slots.has('default')) { html = await Astro.slots.render('default')}---
<Fragment set:html={html} />
This can be used to wrap child components using a <slot />
:
---import Suspense from '@components/Suspense.astro'---
<Suspense> <slot /></Suspense>
Set HTTP Cache Headers
HTTP cache stores web content to reduce server load, decrease loading times, and enhance overall web browsing efficiency for users.
Within Astro you can do this by setting the header on the response.
Astro.response.headers.set("Cache-Control", `max-age=0; s-maxage=${cacheTTL}`);
Routing
Internationalisation (i18N)
For single tenant commerce websites you will be able to utilise Astro’s built in build time i18N methods to define your localised routes. Refer to the guide below for how to set this up.
For multi-tenancy platforms, as localisation varys per tenant and tenancy is often calculated at runtime. Achieving internationalisation requires an alternative approach.