@astrojs/cloudflare 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- @astrojs/cloudflare:build: cache hit, replaying output 90a638f6bf8ef71a
2
- @astrojs/cloudflare:build: 
3
- @astrojs/cloudflare:build: > @astrojs/cloudflare@4.0.0 build /home/runner/work/astro/astro/packages/integrations/cloudflare
4
- @astrojs/cloudflare:build: > astro-scripts build "src/**/*.ts" && tsc
5
- @astrojs/cloudflare:build: 
1
+ @astrojs/cloudflare:build: cache hit, replaying output 5b4d4f8481cf8489
2
+ @astrojs/cloudflare:build: 
3
+ @astrojs/cloudflare:build: > @astrojs/cloudflare@4.1.0 build /home/runner/work/astro/astro/packages/integrations/cloudflare
4
+ @astrojs/cloudflare:build: > astro-scripts build "src/**/*.ts" && tsc
5
+ @astrojs/cloudflare:build: 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @astrojs/cloudflare
2
2
 
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#5347](https://github.com/withastro/astro/pull/5347) [`743000cc7`](https://github.com/withastro/astro/commit/743000cc70274a2d2fed01c72e2ac51aa6b876a6) Thanks [@AirBorne04](https://github.com/AirBorne04)! - Now building for Cloudflare directory mode takes advantage of the standard asset handling from Cloudflare Pages, and therefore does not call a function script to deliver static assets anymore.
8
+ Also supports the use of `_routes.json`, `_redirects` and `_headers` files when placed into the `public` folder.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [[`936c1e411`](https://github.com/withastro/astro/commit/936c1e411d77c69b2b60a061c54704200716800a), [`4b188132e`](https://github.com/withastro/astro/commit/4b188132ef68f8d9951cec86418ef50bb4df4a96), [`f5ed630bc`](https://github.com/withastro/astro/commit/f5ed630bca05ebbfcc6ac994ced3911e41daedcc)]:
13
+ - astro@1.6.11
14
+
15
+ ## 4.0.1
16
+
17
+ ### Patch Changes
18
+
19
+ - [#5301](https://github.com/withastro/astro/pull/5301) [`a79a37cad`](https://github.com/withastro/astro/commit/a79a37cad549b21f91599ff86899e456d9dcc7df) Thanks [@bluwy](https://github.com/bluwy)! - Fix environment variables usage in worker output and warn if environment variables are accessedd too early
20
+
21
+ - Updated dependencies [[`88c1bbe3a`](https://github.com/withastro/astro/commit/88c1bbe3a71f85e92f42f13d0f310c6b2a264ade), [`a79a37cad`](https://github.com/withastro/astro/commit/a79a37cad549b21f91599ff86899e456d9dcc7df)]:
22
+ - astro@1.6.5
23
+
3
24
  ## 4.0.0
4
25
 
5
26
  ### Major Changes
package/README.md CHANGED
@@ -25,7 +25,8 @@ npm install @astrojs/cloudflare
25
25
 
26
26
  2. Add the following to your `astro.config.mjs` file:
27
27
 
28
- ```js title="astro.config.mjs" ins={2, 5-6}
28
+ ```js ins={3, 6-7}
29
+ // astro.config.mjs
29
30
  import { defineConfig } from 'astro/config';
30
31
  import cloudflare from '@astrojs/cloudflare';
31
32
 
@@ -66,7 +67,7 @@ In order for preview to work you must install `wrangler`
66
67
  $ pnpm install wrangler --save-dev
67
68
  ```
68
69
 
69
- It's then possible to update the preview script in your `package.json` to `"preview": "wrangler pages dev ./dist"`.This will allow you run your entire application locally with [Wrangler](https://github.com/cloudflare/wrangler2), which supports secrets, environment variables, KV namespaces, Durable Objects and [all other supported Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/#adding-bindings).
70
+ It's then possible to update the preview script in your `package.json` to `"preview": "wrangler pages dev ./dist"`. This will allow you run your entire application locally with [Wrangler](https://github.com/cloudflare/wrangler2), which supports secrets, environment variables, KV namespaces, Durable Objects and [all other supported Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/#adding-bindings).
70
71
 
71
72
  ## Access to the Cloudflare runtime
72
73
 
@@ -92,19 +93,29 @@ To do this:
92
93
 
93
94
  ## Environment Variables
94
95
 
95
- As Cloudflare Pages Functions [provides environment variables differently](https://developers.cloudflare.com/pages/platform/functions/#adding-environment-variables-locally), private environment variables needs to be set through [`vite.define`](https://vitejs.dev/config/shared-options.html#define) to work in builds.
96
+ As Cloudflare Pages Functions [provides environment variables per request](https://developers.cloudflare.com/pages/platform/functions/#adding-environment-variables-locally), you can only access private environment variables when a request has happened. Usually, this means moving environment variable access inside a function.
96
97
 
97
98
  ```js
98
- // astro.config.mjs
99
- export default {
100
- vite: {
101
- define: {
102
- 'process.env.MY_SECRET': JSON.stringify(process.env.MY_SECRET),
103
- },
104
- },
99
+ // pages/[id].json.js
100
+
101
+ export function get({ params }) {
102
+ // Access environment variables per request inside a function
103
+ const serverUrl = import.meta.env.SERVER_URL;
104
+ const result = await fetch(serverUrl + "/user/" + params.id);
105
+ return {
106
+ body: await result.text(),
107
+ };
105
108
  }
106
109
  ```
107
110
 
111
+ ## Headers, Redirects and function invocation routes
112
+
113
+ Cloudflare has support for adding custom [headers](https://developers.cloudflare.com/pages/platform/headers/), configuring static [redirects](https://developers.cloudflare.com/pages/platform/redirects/) and defining which routes should [invoke functions](https://developers.cloudflare.com/pages/platform/functions/routing/#function-invocation-routes). Cloudflare looks for `_headers`, `_redirects`, and `_routes.json` files in your build output directory to configure these features. This means they should be placed in your Astro project’s `public/` directory.
114
+
115
+ ### Custom `_routes.json`
116
+
117
+ By default, `@astrojs/cloudflare` will generate a `_routes.json` file that lists all files from your `dist/` folder and redirects from the `_redirects` file in the `exclude` array. This will enable Cloudflare to serve files and process static redirects without a function invocation. Creating a custom `_routes.json` will override this automatic optimization and, if not configured manually, cause function invocations that will count against the request limits of your Cloudflare plan.
118
+
108
119
  ## Troubleshooting
109
120
 
110
121
  For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import esbuild from "esbuild";
2
2
  import * as fs from "fs";
3
+ import * as os from "os";
4
+ import glob from "tiny-glob";
3
5
  import { fileURLToPath } from "url";
4
6
  function getAdapter(isModeDirectory) {
5
7
  return isModeDirectory ? {
@@ -16,6 +18,7 @@ const SHIM = `globalThis.process = {
16
18
  argv: [],
17
19
  env: {},
18
20
  };`;
21
+ const SERVER_BUILD_FOLDER = "/$server_build/";
19
22
  function createIntegration(args) {
20
23
  let _config;
21
24
  let _buildConfig;
@@ -28,8 +31,8 @@ function createIntegration(args) {
28
31
  needsBuildConfig = !config.build.client;
29
32
  updateConfig({
30
33
  build: {
31
- client: new URL("./static/", config.outDir),
32
- server: new URL("./", config.outDir),
34
+ client: new URL(`.${config.base}`, config.outDir),
35
+ server: new URL(`.${SERVER_BUILD_FOLDER}`, config.outDir),
33
36
  serverEntry: "_worker.js"
34
37
  }
35
38
  });
@@ -44,6 +47,10 @@ function createIntegration(args) {
44
47
 
45
48
  `);
46
49
  }
50
+ if (config.base === SERVER_BUILD_FOLDER) {
51
+ throw new Error(`
52
+ [@astrojs/cloudflare] \`base: "${SERVER_BUILD_FOLDER}"\` is not allowed. Please change your \`base\` config to something else.`);
53
+ }
47
54
  },
48
55
  "astro:build:setup": ({ vite, target }) => {
49
56
  if (target === "server") {
@@ -63,19 +70,18 @@ function createIntegration(args) {
63
70
  },
64
71
  "astro:build:start": ({ buildConfig }) => {
65
72
  if (needsBuildConfig) {
66
- buildConfig.client = new URL("./static/", _config.outDir);
67
- buildConfig.server = new URL("./", _config.outDir);
73
+ buildConfig.client = new URL(`.${_config.base}`, _config.outDir);
74
+ buildConfig.server = new URL(`.${SERVER_BUILD_FOLDER}`, _config.outDir);
68
75
  buildConfig.serverEntry = "_worker.js";
69
76
  }
70
77
  },
71
78
  "astro:build:done": async () => {
72
- const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server);
73
- const pkg = fileURLToPath(entryUrl);
79
+ const entryPath = fileURLToPath(new URL(_buildConfig.serverEntry, _buildConfig.server)), entryUrl = new URL(_buildConfig.serverEntry, _config.outDir), buildPath = fileURLToPath(entryUrl);
74
80
  await esbuild.build({
75
81
  target: "es2020",
76
82
  platform: "browser",
77
- entryPoints: [pkg],
78
- outfile: pkg,
83
+ entryPoints: [entryPath],
84
+ outfile: buildPath,
79
85
  allowOverwrite: true,
80
86
  format: "esm",
81
87
  bundle: true,
@@ -84,8 +90,55 @@ function createIntegration(args) {
84
90
  js: SHIM
85
91
  }
86
92
  });
87
- const chunksUrl = new URL("./chunks", _buildConfig.server);
88
- await fs.promises.rm(chunksUrl, { recursive: true, force: true });
93
+ const serverUrl = new URL(_buildConfig.server);
94
+ await fs.promises.rm(serverUrl, { recursive: true, force: true });
95
+ const cloudflareSpecialFiles = ["_headers", "_redirects", "_routes.json"];
96
+ if (_config.base !== "/") {
97
+ for (const file of cloudflareSpecialFiles) {
98
+ try {
99
+ await fs.promises.rename(
100
+ new URL(file, _buildConfig.client),
101
+ new URL(file, _config.outDir)
102
+ );
103
+ } catch (e) {
104
+ }
105
+ }
106
+ }
107
+ const routesExists = await fs.promises.stat(new URL("./_routes.json", _config.outDir)).then((stat) => stat.isFile()).catch(() => false);
108
+ if (!routesExists) {
109
+ const staticPathList = (await glob(`${fileURLToPath(_buildConfig.client)}/**/*`, {
110
+ cwd: fileURLToPath(_config.outDir),
111
+ filesOnly: true
112
+ })).filter((file) => cloudflareSpecialFiles.indexOf(file) < 0).map((file) => `/${file}`);
113
+ const redirectsExists = await fs.promises.stat(new URL("./_redirects", _config.outDir)).then((stat) => stat.isFile()).catch(() => false);
114
+ if (redirectsExists) {
115
+ const redirects = (await fs.promises.readFile(new URL("./_redirects", _config.outDir), "utf-8")).split(os.EOL).map((line) => {
116
+ const parts = line.split(" ");
117
+ if (parts.length < 2) {
118
+ return null;
119
+ } else {
120
+ return parts[0].replace(/\/:.*?(?=\/|$)/g, "/*").replace(/\?.*$/, "");
121
+ }
122
+ }).filter(
123
+ (line, index, arr) => line !== null && arr.indexOf(line) === index
124
+ );
125
+ if (redirects.length > 0) {
126
+ staticPathList.push(...redirects);
127
+ }
128
+ }
129
+ await fs.promises.writeFile(
130
+ new URL("./_routes.json", _config.outDir),
131
+ JSON.stringify(
132
+ {
133
+ version: 1,
134
+ include: ["/*"],
135
+ exclude: staticPathList
136
+ },
137
+ null,
138
+ 2
139
+ )
140
+ );
141
+ }
89
142
  if (isModeDirectory) {
90
143
  const functionsUrl = new URL(`file://${process.cwd()}/functions/`);
91
144
  await fs.promises.mkdir(functionsUrl, { recursive: true });
@@ -1,4 +1,3 @@
1
- import './shim.js';
2
1
  import type { SSRManifest } from 'astro';
3
2
  declare type Env = {
4
3
  ASSETS: {
@@ -1,12 +1,13 @@
1
- import "./shim.js";
2
1
  import { App } from "astro/app";
2
+ import { getProcessEnvProxy } from "./util.js";
3
+ process.env = getProcessEnvProxy();
3
4
  function createExports(manifest) {
4
5
  const app = new App(manifest, false);
5
6
  const fetch = async (request, env, context) => {
6
- const { origin, pathname } = new URL(request.url);
7
+ process.env = env;
8
+ const { pathname } = new URL(request.url);
7
9
  if (manifest.assets.has(pathname)) {
8
- const assetRequest = new Request(`${origin}/static/${app.removeBase(pathname)}`, request);
9
- return env.ASSETS.fetch(assetRequest);
10
+ return env.ASSETS.fetch(request);
10
11
  }
11
12
  let routeData = app.match(request, { matchNotFound: true });
12
13
  if (routeData) {
@@ -1,4 +1,3 @@
1
- import './shim.js';
2
1
  import type { SSRManifest } from 'astro';
3
2
  export declare function createExports(manifest: SSRManifest): {
4
3
  onRequest: ({ request, next, ...runtimeEnv }: {
@@ -1,5 +1,6 @@
1
- import "./shim.js";
2
1
  import { App } from "astro/app";
2
+ import { getProcessEnvProxy } from "./util.js";
3
+ process.env = getProcessEnvProxy();
3
4
  function createExports(manifest) {
4
5
  const app = new App(manifest, false);
5
6
  const onRequest = async ({
@@ -7,10 +8,10 @@ function createExports(manifest) {
7
8
  next,
8
9
  ...runtimeEnv
9
10
  }) => {
10
- const { origin, pathname } = new URL(request.url);
11
+ process.env = runtimeEnv.env;
12
+ const { pathname } = new URL(request.url);
11
13
  if (manifest.assets.has(pathname)) {
12
- const assetRequest = new Request(`${origin}/static/${app.removeBase(pathname)}`, request);
13
- return next(assetRequest);
14
+ return next(request);
14
15
  }
15
16
  let routeData = app.match(request, { matchNotFound: true });
16
17
  if (routeData) {
package/dist/util.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function getProcessEnvProxy(): {};
package/dist/util.js ADDED
@@ -0,0 +1,15 @@
1
+ function getProcessEnvProxy() {
2
+ return new Proxy(
3
+ {},
4
+ {
5
+ get: (target, prop) => {
6
+ console.warn(
7
+ `Unable to access \`import.meta\0.env.${prop.toString()}\` on initialization as the Cloudflare platform only provides the environment variables per request. Please move the environment variable access inside a function that's only called after a request has been received.`
8
+ );
9
+ }
10
+ }
11
+ );
12
+ }
13
+ export {
14
+ getProcessEnvProxy
15
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/cloudflare",
3
3
  "description": "Deploy your site to cloudflare workers or cloudflare pages",
4
- "version": "4.0.0",
4
+ "version": "4.1.0",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "author": "withastro",
@@ -28,13 +28,14 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "dependencies": {
31
- "esbuild": "^0.14.42"
31
+ "esbuild": "^0.14.42",
32
+ "tiny-glob": "^0.2.9"
32
33
  },
33
34
  "peerDependencies": {
34
- "astro": "^1.6.4"
35
+ "astro": "^1.6.11"
35
36
  },
36
37
  "devDependencies": {
37
- "astro": "1.6.4",
38
+ "astro": "1.6.11",
38
39
  "astro-scripts": "0.0.9",
39
40
  "chai": "^4.3.6",
40
41
  "cheerio": "^1.0.0-rc.11",
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { AstroAdapter, AstroConfig, AstroIntegration } from 'astro';
2
2
  import esbuild from 'esbuild';
3
3
  import * as fs from 'fs';
4
+ import * as os from 'os';
5
+ import glob from 'tiny-glob';
4
6
  import { fileURLToPath } from 'url';
5
7
 
6
8
  type Options = {
@@ -32,6 +34,8 @@ const SHIM = `globalThis.process = {
32
34
  env: {},
33
35
  };`;
34
36
 
37
+ const SERVER_BUILD_FOLDER = '/$server_build/';
38
+
35
39
  export default function createIntegration(args?: Options): AstroIntegration {
36
40
  let _config: AstroConfig;
37
41
  let _buildConfig: BuildConfig;
@@ -45,8 +49,8 @@ export default function createIntegration(args?: Options): AstroIntegration {
45
49
  needsBuildConfig = !config.build.client;
46
50
  updateConfig({
47
51
  build: {
48
- client: new URL('./static/', config.outDir),
49
- server: new URL('./', config.outDir),
52
+ client: new URL(`.${config.base}`, config.outDir),
53
+ server: new URL(`.${SERVER_BUILD_FOLDER}`, config.outDir),
50
54
  serverEntry: '_worker.js',
51
55
  },
52
56
  });
@@ -62,6 +66,11 @@ export default function createIntegration(args?: Options): AstroIntegration {
62
66
 
63
67
  `);
64
68
  }
69
+
70
+ if (config.base === SERVER_BUILD_FOLDER) {
71
+ throw new Error(`
72
+ [@astrojs/cloudflare] \`base: "${SERVER_BUILD_FOLDER}"\` is not allowed. Please change your \`base\` config to something else.`);
73
+ }
65
74
  },
66
75
  'astro:build:setup': ({ vite, target }) => {
67
76
  if (target === 'server') {
@@ -84,19 +93,20 @@ export default function createIntegration(args?: Options): AstroIntegration {
84
93
  'astro:build:start': ({ buildConfig }) => {
85
94
  // Backwards compat
86
95
  if (needsBuildConfig) {
87
- buildConfig.client = new URL('./static/', _config.outDir);
88
- buildConfig.server = new URL('./', _config.outDir);
96
+ buildConfig.client = new URL(`.${_config.base}`, _config.outDir);
97
+ buildConfig.server = new URL(`.${SERVER_BUILD_FOLDER}`, _config.outDir);
89
98
  buildConfig.serverEntry = '_worker.js';
90
99
  }
91
100
  },
92
101
  'astro:build:done': async () => {
93
- const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server);
94
- const pkg = fileURLToPath(entryUrl);
102
+ const entryPath = fileURLToPath(new URL(_buildConfig.serverEntry, _buildConfig.server)),
103
+ entryUrl = new URL(_buildConfig.serverEntry, _config.outDir),
104
+ buildPath = fileURLToPath(entryUrl);
95
105
  await esbuild.build({
96
106
  target: 'es2020',
97
107
  platform: 'browser',
98
- entryPoints: [pkg],
99
- outfile: pkg,
108
+ entryPoints: [entryPath],
109
+ outfile: buildPath,
100
110
  allowOverwrite: true,
101
111
  format: 'esm',
102
112
  bundle: true,
@@ -107,8 +117,90 @@ export default function createIntegration(args?: Options): AstroIntegration {
107
117
  });
108
118
 
109
119
  // throw the server folder in the bin
110
- const chunksUrl = new URL('./chunks', _buildConfig.server);
111
- await fs.promises.rm(chunksUrl, { recursive: true, force: true });
120
+ const serverUrl = new URL(_buildConfig.server);
121
+ await fs.promises.rm(serverUrl, { recursive: true, force: true });
122
+
123
+ // move cloudflare specific files to the root
124
+ const cloudflareSpecialFiles = ['_headers', '_redirects', '_routes.json'];
125
+ if (_config.base !== '/') {
126
+ for (const file of cloudflareSpecialFiles) {
127
+ try {
128
+ await fs.promises.rename(
129
+ new URL(file, _buildConfig.client),
130
+ new URL(file, _config.outDir)
131
+ );
132
+ } catch (e) {
133
+ // ignore
134
+ }
135
+ }
136
+ }
137
+
138
+ const routesExists = await fs.promises
139
+ .stat(new URL('./_routes.json', _config.outDir))
140
+ .then((stat) => stat.isFile())
141
+ .catch(() => false);
142
+
143
+ // this creates a _routes.json, in case there is none present to enable
144
+ // cloudflare to handle static files and support _redirects configuration
145
+ // (without calling the function)
146
+ if (!routesExists) {
147
+ const staticPathList: Array<string> = (
148
+ await glob(`${fileURLToPath(_buildConfig.client)}/**/*`, {
149
+ cwd: fileURLToPath(_config.outDir),
150
+ filesOnly: true,
151
+ })
152
+ )
153
+ .filter((file: string) => cloudflareSpecialFiles.indexOf(file) < 0)
154
+ .map((file: string) => `/${file}`);
155
+
156
+ const redirectsExists = await fs.promises
157
+ .stat(new URL('./_redirects', _config.outDir))
158
+ .then((stat) => stat.isFile())
159
+ .catch(() => false);
160
+
161
+ // convert all redirect source paths into a list of routes
162
+ // and add them to the static path
163
+ if (redirectsExists) {
164
+ const redirects = (
165
+ await fs.promises.readFile(new URL('./_redirects', _config.outDir), 'utf-8')
166
+ )
167
+ .split(os.EOL)
168
+ .map((line) => {
169
+ const parts = line.split(' ');
170
+ if (parts.length < 2) {
171
+ return null;
172
+ } else {
173
+ // convert /products/:id to /products/*
174
+ return (
175
+ parts[0]
176
+ .replace(/\/:.*?(?=\/|$)/g, '/*')
177
+ // remove query params as they are not supported by cloudflare
178
+ .replace(/\?.*$/, '')
179
+ );
180
+ }
181
+ })
182
+ .filter(
183
+ (line, index, arr) => line !== null && arr.indexOf(line) === index
184
+ ) as string[];
185
+
186
+ if (redirects.length > 0) {
187
+ staticPathList.push(...redirects);
188
+ }
189
+ }
190
+
191
+ await fs.promises.writeFile(
192
+ new URL('./_routes.json', _config.outDir),
193
+ JSON.stringify(
194
+ {
195
+ version: 1,
196
+ include: ['/*'],
197
+ exclude: staticPathList,
198
+ },
199
+ null,
200
+ 2
201
+ )
202
+ );
203
+ }
112
204
 
113
205
  if (isModeDirectory) {
114
206
  const functionsUrl = new URL(`file://${process.cwd()}/functions/`);
@@ -1,7 +1,8 @@
1
- import './shim.js';
2
-
3
1
  import type { SSRManifest } from 'astro';
4
2
  import { App } from 'astro/app';
3
+ import { getProcessEnvProxy } from './util.js';
4
+
5
+ process.env = getProcessEnvProxy();
5
6
 
6
7
  type Env = {
7
8
  ASSETS: { fetch: (req: Request) => Promise<Response> };
@@ -12,12 +13,13 @@ export function createExports(manifest: SSRManifest) {
12
13
  const app = new App(manifest, false);
13
14
 
14
15
  const fetch = async (request: Request, env: Env, context: any) => {
15
- const { origin, pathname } = new URL(request.url);
16
+ process.env = env as any;
17
+
18
+ const { pathname } = new URL(request.url);
16
19
 
17
- // static assets
20
+ // static assets fallback, in case default _routes.json is not used
18
21
  if (manifest.assets.has(pathname)) {
19
- const assetRequest = new Request(`${origin}/static/${app.removeBase(pathname)}`, request);
20
- return env.ASSETS.fetch(assetRequest);
22
+ return env.ASSETS.fetch(request);
21
23
  }
22
24
 
23
25
  let routeData = app.match(request, { matchNotFound: true });
@@ -1,7 +1,8 @@
1
- import './shim.js';
2
-
3
1
  import type { SSRManifest } from 'astro';
4
2
  import { App } from 'astro/app';
3
+ import { getProcessEnvProxy } from './util.js';
4
+
5
+ process.env = getProcessEnvProxy();
5
6
 
6
7
  export function createExports(manifest: SSRManifest) {
7
8
  const app = new App(manifest, false);
@@ -14,11 +15,12 @@ export function createExports(manifest: SSRManifest) {
14
15
  request: Request;
15
16
  next: (request: Request) => void;
16
17
  } & Record<string, unknown>) => {
17
- const { origin, pathname } = new URL(request.url);
18
- // static assets
18
+ process.env = runtimeEnv.env as any;
19
+
20
+ const { pathname } = new URL(request.url);
21
+ // static assets fallback, in case default _routes.json is not used
19
22
  if (manifest.assets.has(pathname)) {
20
- const assetRequest = new Request(`${origin}/static/${app.removeBase(pathname)}`, request);
21
- return next(assetRequest);
23
+ return next(request);
22
24
  }
23
25
 
24
26
  let routeData = app.match(request, { matchNotFound: true });
package/src/util.ts ADDED
@@ -0,0 +1,16 @@
1
+ export function getProcessEnvProxy() {
2
+ return new Proxy(
3
+ {},
4
+ {
5
+ get: (target, prop) => {
6
+ console.warn(
7
+ // NOTE: \0 prevents Vite replacement
8
+ `Unable to access \`import.meta\0.env.${prop.toString()}\` on initialization ` +
9
+ `as the Cloudflare platform only provides the environment variables per request. ` +
10
+ `Please move the environment variable access inside a function ` +
11
+ `that's only called after a request has been received.`
12
+ );
13
+ },
14
+ }
15
+ );
16
+ }
@@ -24,6 +24,7 @@ describe.skip('Basic app', () => {
24
24
  let html = await res.text();
25
25
  let $ = cheerio.load(html);
26
26
  expect($('h1').text()).to.equal('Testing');
27
+ expect($('#env').text()).to.equal('secret');
27
28
  } finally {
28
29
  stop();
29
30
  }
@@ -1,6 +1,9 @@
1
1
  import { defineConfig } from 'astro/config';
2
2
  import cloudflare from '@astrojs/cloudflare';
3
3
 
4
+ // test env var
5
+ process.env.SECRET_STUFF = 'secret'
6
+
4
7
  export default defineConfig({
5
8
  adapter: cloudflare(),
6
9
  output: 'server',
@@ -4,5 +4,6 @@
4
4
  </head>
5
5
  <body>
6
6
  <h1>Testing</h1>
7
+ <div id="env">{import.meta.env.SECRET_STUFF}</div>
7
8
  </body>
8
9
  </html>
@@ -0,0 +1,4 @@
1
+ # for tests only
2
+
3
+ [vars]
4
+ SECRET_STUFF = "secret"
package/dist/shim.d.ts DELETED
File without changes
package/dist/shim.js DELETED
@@ -1,4 +0,0 @@
1
- globalThis.process = {
2
- argv: [],
3
- env: {}
4
- };
package/src/shim.ts DELETED
@@ -1,4 +0,0 @@
1
- (globalThis as any).process = {
2
- argv: [],
3
- env: {},
4
- };