Skip to content
This repository has been archived by the owner on Feb 10, 2025. It is now read-only.

Commit

Permalink
feat(cloudflare): support astro:env (#258)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Niebuhr <alexander@nbhr.io>
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
  • Loading branch information
alexanderniebuhr and florian-lefebvre authored Jun 10, 2024
1 parent 4a28bf6 commit 033847d
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/purple-trainers-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/cloudflare': minor
---

Adds support for experimental `astro:env` released in Astro 4.10
1 change: 1 addition & 0 deletions packages/cloudflare/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
functions
.mf
.wrangler
.astro
2 changes: 1 addition & 1 deletion packages/cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions packages/cloudflare/src/entrypoints/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 });

Expand Down
13 changes: 13 additions & 0 deletions packages/cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -191,6 +192,7 @@ export default function createIntegration(args?: Options): AstroIntegration {
isSharpCompatible: false,
isSquooshCompatible: false,
},
envGetSecret: 'experimental',
},
});
},
Expand All @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions packages/cloudflare/src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 65 additions & 0 deletions packages/cloudflare/test/astro-env.test.js
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions packages/cloudflare/test/fixtures/astro-env/.dev.vars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
API_SECRET=123456789
21 changes: 21 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/astro.config.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/package.json
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 27 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}
5 changes: 5 additions & 0 deletions packages/cloudflare/test/fixtures/astro-env/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = "astro-env"

[vars]
PUBLIC_API_URL = "https://google.de"
PUBLIC_PORT = 4322
1 change: 0 additions & 1 deletion packages/netlify/src/types.d.ts

This file was deleted.

18 changes: 17 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 033847d

Please sign in to comment.