aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexander Niebuhr <alexander@nbhr.io> 2024-06-10 17:48:38 +0200
committerGravatar GitHub <noreply@github.com> 2024-06-10 17:48:38 +0200
commit976a24c66d8dc329dc90624a7ad52eff315b2bbf (patch)
tree954e16476f395a709ddaab3eb20b146ea5fcad71
parent41f1321c088592a429b785f935fd5c6c49c405a0 (diff)
downloadastro-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>
-rw-r--r--packages/integrations/cloudflare/.gitignore1
-rw-r--r--packages/integrations/cloudflare/package.json2
-rw-r--r--packages/integrations/cloudflare/src/entrypoints/server.ts5
-rw-r--r--packages/integrations/cloudflare/src/index.ts13
-rw-r--r--packages/integrations/cloudflare/src/utils/env.ts15
-rw-r--r--packages/integrations/cloudflare/test/astro-env.test.js65
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars1
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts21
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/package.json12
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts12
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro27
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json3
-rw-r--r--packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml5
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