mirror of
https://github.com/withastro/astro.git
synced 2025-03-10 23:01:26 -05:00
feat(cloudflare): support astro:env (#258)
Co-authored-by: Alexander Niebuhr <alexander@nbhr.io> Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
This commit is contained in:
parent
41f1321c08
commit
976a24c66d
13 changed files with 181 additions and 1 deletions
1
packages/integrations/cloudflare/.gitignore
vendored
1
packages/integrations/cloudflare/.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
functions
|
||||
.mf
|
||||
.wrangler
|
||||
.astro
|
|
@ -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",
|
||||
|
|
|
@ -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 });
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
15
packages/integrations/cloudflare/src/utils/env.ts
Normal file
15
packages/integrations/cloudflare/src/utils/env.ts
Normal file
|
@ -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;
|
||||
};
|
65
packages/integrations/cloudflare/test/astro-env.test.js
Normal file
65
packages/integrations/cloudflare/test/astro-env.test.js
Normal file
|
@ -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);
|
||||
});
|
||||
});
|
1
packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars
vendored
Normal file
1
packages/integrations/cloudflare/test/fixtures/astro-env/.dev.vars
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
API_SECRET=123456789
|
21
packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts
vendored
Normal file
21
packages/integrations/cloudflare/test/fixtures/astro-env/astro.config.ts
vendored
Normal file
|
@ -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',
|
||||
});
|
12
packages/integrations/cloudflare/test/fixtures/astro-env/package.json
vendored
Normal file
12
packages/integrations/cloudflare/test/fixtures/astro-env/package.json
vendored
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
12
packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts
vendored
Normal file
12
packages/integrations/cloudflare/test/fixtures/astro-env/src/env.d.ts
vendored
Normal file
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
27
packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro
vendored
Normal file
27
packages/integrations/cloudflare/test/fixtures/astro-env/src/pages/index.astro
vendored
Normal file
|
@ -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>
|
3
packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json
vendored
Normal file
3
packages/integrations/cloudflare/test/fixtures/astro-env/tsconfig.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict"
|
||||
}
|
5
packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml
vendored
Normal file
5
packages/integrations/cloudflare/test/fixtures/astro-env/wrangler.toml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
name = "astro-env"
|
||||
|
||||
[vars]
|
||||
PUBLIC_API_URL = "https://google.de"
|
||||
PUBLIC_PORT = 4322
|
Loading…
Add table
Reference in a new issue