diff options
author | 2024-06-10 17:48:38 +0200 | |
---|---|---|
committer | 2024-06-10 17:48:38 +0200 | |
commit | 976a24c66d8dc329dc90624a7ad52eff315b2bbf (patch) | |
tree | 954e16476f395a709ddaab3eb20b146ea5fcad71 | |
parent | 41f1321c088592a429b785f935fd5c6c49c405a0 (diff) | |
download | astro-976a24c66d8dc329dc90624a7ad52eff315b2bbf.tar.gz astro-976a24c66d8dc329dc90624a7ad52eff315b2bbf.tar.zst astro-976a24c66d8dc329dc90624a7ad52eff315b2bbf.zip |
feat(cloudflare): support astro:env (#258)
Co-authored-by: Alexander Niebuhr <alexander@nbhr.io>
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
13 files changed, 181 insertions, 1 deletions
diff --git a/packages/integrations/cloudflare/.gitignore b/packages/integrations/cloudflare/.gitignore index 27d65797e..45f8ec847 100644 --- a/packages/integrations/cloudflare/.gitignore +++ b/packages/integrations/cloudflare/.gitignore @@ -2,3 +2,4 @@ functions .mf .wrangler +.astro
\ No newline at end of file diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index f5b5079a6..9e10988af 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@astrojs/test-utils": "workspace:*", - "astro": "^4.5.8", + "astro": "^4.10.1", "astro-scripts": "workspace:*", "cheerio": "1.0.0-rc.12", "execa": "^8.0.1", diff --git a/packages/integrations/cloudflare/src/entrypoints/server.ts b/packages/integrations/cloudflare/src/entrypoints/server.ts index af4106b4e..e17dd6a25 100644 --- a/packages/integrations/cloudflare/src/entrypoints/server.ts +++ b/packages/integrations/cloudflare/src/entrypoints/server.ts @@ -5,8 +5,10 @@ import type { } from '@cloudflare/workers-types'; import type { SSRManifest } from 'astro'; import { App } from 'astro/app'; +import { createGetEnv } from '../utils/env.js'; type Env = { + [key: string]: unknown; ASSETS: { fetch: (req: Request | string) => Promise<Response> }; ASTRO_STUDIO_APP_TOKEN?: string; }; @@ -69,6 +71,9 @@ export function createExports(manifest: SSRManifest) { }, }, }; + // Won't throw if the virtual module is not available because it's not supported in + // the users's astro version or if astro:env is not enabled in the project + await import('astro/env/setup').then((mod) => mod.setGetEnv(createGetEnv(env))).catch(() => {}); const response = await app.render(request, { routeData, locals }); diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index a0f3d8ba1..6ded561dd 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -19,6 +19,7 @@ import { type CloudflareModulePluginExtra, cloudflareModuleLoader, } from './utils/cloudflare-module-loader.js'; +import { createGetEnv } from './utils/env.js'; import { createRoutesFile, getParts } from './utils/generate-routes-json.js'; import { setImageConfig } from './utils/image-config.js'; import { mutateDynamicPageImportsInPlace, mutatePageMapInPlace } from './utils/index.js'; @@ -191,6 +192,7 @@ export default function createIntegration(args?: Options): AstroIntegration { isSharpCompatible: false, isSquooshCompatible: false, }, + envGetSecret: 'experimental', }, }); }, @@ -202,6 +204,17 @@ export default function createIntegration(args?: Options): AstroIntegration { persist: args.platformProxy.persist ?? true, }); + const getEnv = createGetEnv(platformProxy.env); + + if (_config.experimental.env?.schema) { + for (const key of Object.keys(_config.experimental.env.schema)) { + const value = getEnv(key); + if (value !== undefined) { + process.env[key] = value; + } + } + } + const clientLocalsSymbol = Symbol.for('astro.locals'); server.middlewares.use(async function middleware(req, res, next) { diff --git a/packages/integrations/cloudflare/src/utils/env.ts b/packages/integrations/cloudflare/src/utils/env.ts new file mode 100644 index 000000000..e450038eb --- /dev/null +++ b/packages/integrations/cloudflare/src/utils/env.ts @@ -0,0 +1,15 @@ +import type { GetEnv } from 'astro/env/setup'; + +export const createGetEnv = + (env: Record<string, unknown>): GetEnv => + (key) => { + const v = env[key]; + if (typeof v === 'undefined' || typeof v === 'string') { + return v; + } + if (typeof v === 'boolean' || typeof v === 'number') { + // let astro:env handle the validation and transformation + return v.toString(); + } + return undefined; + }; diff --git a/packages/integrations/cloudflare/test/astro-env.test.js b/packages/integrations/cloudflare/test/astro-env.test.js new file mode 100644 index 000000000..786583be8 --- /dev/null +++ b/packages/integrations/cloudflare/test/astro-env.test.js @@ -0,0 +1,65 @@ +import * as assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import { fileURLToPath } from 'node:url'; +import * as cheerio from 'cheerio'; +import { astroCli, wranglerCli } from './_test-utils.js'; + +const root = new URL('./fixtures/astro-env/', import.meta.url); + +describe('AstroEnv', () => { + let wrangler; + + before(async () => { + process.env.PUBLIC_API_URL = 'https://google.de'; + process.env.PUBLIC_PORT = '4322'; + await astroCli(fileURLToPath(root), 'build'); + + wrangler = wranglerCli(fileURLToPath(root)); + await new Promise((resolve) => { + wrangler.stdout.on('data', (data) => { + // console.log('[stdout]', data.toString()); + if (data.toString().includes('http://127.0.0.1:8788')) resolve(); + }); + wrangler.stderr.on('data', (data) => { + // console.log('[stderr]', data.toString()); + }); + }); + }); + + after((done) => { + wrangler.kill(); + }); + + it('runtime', async () => { + const res = await fetch('http://127.0.0.1:8788/'); + const html = await res.text(); + const $ = cheerio.load(html); + assert.equal( + $('#runtime').text().includes('https://google.de') && + $('#runtime').text().includes('4322') && + $('#runtime').text().includes('123456789'), + true + ); + }); + + it('client', async () => { + const res = await fetch('http://127.0.0.1:8788/'); + const html = await res.text(); + const $ = cheerio.load(html); + assert.equal($('#client').text().includes('https://google.de'), true); + }); + + it('server', async () => { + const res = await fetch('http://127.0.0.1:8788/'); + const html = await res.text(); + const $ = cheerio.load(html); + assert.equal($('#server').text().includes('4322'), true); + }); + + it('secret', async () => { + const res = await fetch('http://127.0.0.1:8788/'); + const html = await res.text(); + const $ = cheerio.load(html); + assert.equal($('#secret').text().includes('123456789'), true); + }); +}); diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars b/packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars new file mode 100644 index 000000000..3cf69c1f5 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars @@ -0,0 +1 @@ +API_SECRET=123456789 diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts b/packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts new file mode 100644 index 000000000..dd4485488 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts @@ -0,0 +1,21 @@ +import cloudflare from '@astrojs/cloudflare'; +import { defineConfig, envField } from 'astro/config'; + +export default defineConfig({ + experimental: { + rewriting: false, + env: { + schema: { + PUBLIC_API_URL: envField.string({ context: 'client', access: 'public', optional: true }), + PUBLIC_PORT: envField.number({ context: 'server', access: 'public', default: 4321 }), + // API_SECRET: envField.string({ context: 'server', access: 'secret' }), + }, + }, + }, + adapter: cloudflare({ + platformProxy: { + enabled: true, + }, + }), + output: 'server', +}); diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/package.json b/packages/integrations/cloudflare/test/fixtures/astro-env/package.json new file mode 100644 index 000000000..79ed90bc6 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/package.json @@ -0,0 +1,12 @@ +{ + "name": "@test/astro-cloudflare-astro-env", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/cloudflare": "workspace:*", + "astro": "^4.10.1" + }, + "devDependencies": { + "wrangler": "^3.15.0" + } +} diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts b/packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts new file mode 100644 index 000000000..2265a9fb3 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts @@ -0,0 +1,12 @@ +/// <reference path="../.astro/env.d.ts" /> +/// <reference types="astro/client" /> + +type Runtime = import('@astrojs/cloudflare').Runtime; + +declare namespace App { + interface Locals extends Runtime { + otherLocals: { + test: string; + }; + } +}
\ No newline at end of file diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro b/packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro new file mode 100644 index 000000000..7cd24e234 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro @@ -0,0 +1,27 @@ +--- +import { PUBLIC_API_URL } from "astro:env/client" +import { PUBLIC_PORT, getSecret } from "astro:env/server" + +const runtime = Astro.locals.runtime; +--- +<html> + <head> + <title>Astro Env</title> + </head> + <body> + <h1>Astro Env</h1> + <pre id="runtime">{JSON.stringify(runtime.env, null, 2)}</pre> + <div> + <span>PUBLIC_API_URL</span> + <span id="client">{PUBLIC_API_URL}</span> + </div> + <div> + <span>PUBLIC_PORT</span> + <span id="server">{PUBLIC_PORT}</span> + </div> + <div> + <span>getSecret</span> + <span id="secret">{getSecret("API_SECRET")}</span> + </div> + </body> +</html> diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json b/packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json new file mode 100644 index 000000000..c02b48a37 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "astro/tsconfigs/strict" +}
\ No newline at end of file diff --git a/packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml b/packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml new file mode 100644 index 000000000..9db14996b --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml @@ -0,0 +1,5 @@ +name = "astro-env" + +[vars] +PUBLIC_API_URL = "https://google.de" +PUBLIC_PORT = 4322 |