Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ import cloudflare from '@astrojs/cloudflare';
import graphql from '@rollup/plugin-graphql';
import sitemap from '@astrojs/sitemap';
import Sonda from 'sonda/astro';
import type { PluginOption } from 'vite';
import { loadEnv, type PluginOption } from 'vite';
import pkg from './package.json';
import { isPreview } from './config/preview';
import { output } from './config/output';
import serviceWorker from './config/astro/service-worker-integration.ts';

// Astro build/dev prerenders in Cloudflare's `workerd` runtime, which reads
// local secrets from `.dev.vars`, not `.env`. To keep `.env` the single source
// of truth, we load it here and feed the values into the `astro:env` defaults below.
// In CI (Workers Builds) no `.env` file exists, so `process.env` — populated by the CI — wins.
const dotEnv = loadEnv(process.env.NODE_ENV ?? 'development', process.cwd(), '');
const env = (key: string) => process.env[key] ?? dotEnv[key];

const isAnalyseMode = process.env.ANALYZE === 'true';
// Vitest loads this config via `getViteConfig`. The Cloudflare adapter's Vite
// plugin (v13+) rejects the Node.js `resolve.external` list Astro sets on the
// SSR environment, so we skip the adapter during tests, which don't render pages.
const isTest = process.env.VITEST === 'true';
const productionUrl = `https://${pkg.name}.voorhoede.workers.dev`; // overwrite if you have a custom domain
const localhostPort = 4323; // 4323 is "head" in T9

Expand All @@ -21,23 +32,22 @@ export const siteUrl = process.env.WORKERS_CI

// https://astro.build/config
export default defineConfig({
adapter: cloudflare({
imageService: 'compile',
platformProxy: {
enabled: true,
},
}),
adapter: isTest
? undefined
: cloudflare({
imageService: 'compile',
}),
env: {
schema: {
DATOCMS_READONLY_API_TOKEN: envField.string({
context: 'server',
access: 'secret',
default: process.env.DATOCMS_READONLY_API_TOKEN
default: env('DATOCMS_READONLY_API_TOKEN')
}),
HEAD_START_PREVIEW_SECRET: envField.string({
context: 'server',
access: 'secret',
default: process.env.HEAD_START_PREVIEW_SECRET
default: env('HEAD_START_PREVIEW_SECRET')
}),
HEAD_START_PREVIEW: envField.boolean({
context: 'server',
Expand All @@ -51,6 +61,14 @@ export default defineConfig({
})
}
},
fonts: [{
name: 'Archivo',
cssVariable: '--font-archivo',
provider: fontProviders.fontsource(),
weights: [400, 600],
styles: ['normal'],
subsets: ['latin'],
}],
integrations: [
serviceWorker(),
sitemap(),
Expand All @@ -60,7 +78,7 @@ export default defineConfig({
server: true,
}),
],
output: isPreview ? 'server' : output, // @see `/config/output.ts``
output: (isPreview && !isTest) ? 'server' : output, // @see `/config/output.ts``
server: { port: localhostPort },
site: siteUrl,
vite: {
Expand All @@ -74,15 +92,4 @@ export default defineConfig({
exclude: ['msw'],
}
},
experimental: {
// @note this can be moved out of experimental when we updated astro to v6.0
fonts: [{
name: 'Archivo',
cssVariable: '--font-archivo',
provider: fontProviders.fontsource(),
weights: [400, 600],
styles: ['normal'],
subsets: ['latin'],
}]
},
});
72 changes: 45 additions & 27 deletions config/astro/service-worker-integration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { APIRoute, AstroIntegration } from 'astro';
import type { AstroIntegration } from 'astro';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import * as esbuild from 'esbuild';
import type { Plugin } from 'vite';

const filenamePath = (filename: string) => fileURLToPath(new URL(join('../../', filename), import.meta.url));
const srcFilename = filenamePath('src/assets/service-worker.ts');
Expand All @@ -17,22 +18,55 @@ const buildConfig = {
sourcemap: true,
};

/**
* Serves `/service-worker.js` during `astro dev`.
*
* We run esbuild in a Vite dev middleware rather than an on-demand Astro route
* because, since Astro 6 + `@astrojs/cloudflare` v13, dev routes execute in the
* Cloudflare `workerd` runtime. esbuild relies on Node APIs (e.g. `__filename`)
* that don't exist there. Vite's dev server middleware still runs in Node.
*/
function serviceWorkerDevPlugin(): Plugin {
return {
name: 'service-worker-dev',
apply: 'serve',
enforce: 'pre',
configureServer(server) {
server.watcher.add(srcFilename);
const handle = async (
_req: unknown,
res: import('node:http').ServerResponse,
next: (err?: unknown) => void,
) => {
try {
const output = await esbuild.build({
...buildConfig,
write: false,
minify: false,
sourcemap: false,
});
res.setHeader('Content-Type', 'application/javascript');
res.end(output.outputFiles[0].text);
} catch (e) {
next(e);
}
};
// Prepend to the middleware stack so this runs before the Cloudflare
// plugin's catch-all, which otherwise forwards `/service-worker.js` to
// `workerd` and 404s.
server.middlewares.stack.unshift({ route: '/service-worker.js', handle });
},
};
}

export default function serviceWorkerIntegration(): AstroIntegration {
return {
name: 'service-worker',
hooks: {
'astro:config:setup': async ({
command,
injectRoute,
addWatchFile,
}) => {
'astro:config:setup': async ({ command, updateConfig }) => {
const isDevelopment = command === 'dev';
if (isDevelopment) {
addWatchFile(srcFilename);
injectRoute({
pattern: '/service-worker.js',
entrypoint: import.meta.url,
});
updateConfig({ vite: { plugins: [serviceWorkerDevPlugin()] } });
}
},
'astro:build:done': async () => {
Expand All @@ -50,19 +84,3 @@ export default function serviceWorkerIntegration(): AstroIntegration {
},
};
}

export const GET: APIRoute = async () => {
const output = await esbuild.build({
...buildConfig,
write: false,
minify: false,
sourcemap: false,
});

return new Response(output.outputFiles[0].text, {
status: 200,
headers: {
'Content-Type': 'application/javascript',
},
});
};
Loading
Loading