chore(cloudflare): refactor structure, optimize patterns (#8654)
--------- Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> Co-authored-by: 100gle <loogle.space@gmail.com>
This commit is contained in:
parent
23e7b259eb
commit
f6ba533df6
13 changed files with 313 additions and 308 deletions
5
.changeset/olive-jeans-reply.md
Normal file
5
.changeset/olive-jeans-reply.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/cloudflare': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Refactor codebase to enhance code readability and structure, to prioritize maintainability for long-term.
|
|
@ -25,7 +25,7 @@ npm install @astrojs/cloudflare
|
||||||
|
|
||||||
2. Add the following to your `astro.config.mjs` file:
|
2. Add the following to your `astro.config.mjs` file:
|
||||||
|
|
||||||
```diff lang="ts"
|
```diff lang="js"
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
+ import cloudflare from '@astrojs/cloudflare';
|
+ import cloudflare from '@astrojs/cloudflare';
|
||||||
|
@ -38,30 +38,29 @@ npm install @astrojs/cloudflare
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
### Mode
|
### `mode`
|
||||||
|
|
||||||
`mode: "advanced" | "directory"`
|
`mode: "advanced" | "directory"`
|
||||||
|
|
||||||
default `"advanced"`
|
default `"advanced"`
|
||||||
|
|
||||||
Cloudflare Pages has 2 different modes for deploying functions, `advanced` mode which picks up the `_worker.js` in `dist`, or a directory mode where pages will compile the worker out of a functions folder in the project root. For most projects the adapter default of `advanced` will be sufficient; the `dist` folder will contain your compiled project.
|
This configuration option defines how your Astro project is deployed to Cloudflare Pages.
|
||||||
|
|
||||||
#### `mode:directory`
|
- `advanced` mode picks up the `_worker.js` file in the `dist` folder
|
||||||
|
- `directory` mode picks up the files in the `functions` folder, by default only one `[[path]].js` file is generated
|
||||||
|
|
||||||
Switching to directory mode allows you to use [pages plugins](https://developers.cloudflare.com/pages/platform/functions/plugins/) such as [Sentry](https://developers.cloudflare.com/pages/platform/functions/plugins/sentry/) or write custom code to enable logging.
|
Switching to directory mode allows you to add additional files manually such as [Cloudflare Pages Plugins](https://developers.cloudflare.com/pages/platform/functions/plugins/), [Cloudflare Pages Middleware](https://developers.cloudflare.com/pages/platform/functions/middleware/) or custom functions using [Cloudflare Pages Functions Routing](https://developers.cloudflare.com/pages/platform/functions/routing/).
|
||||||
|
|
||||||
```ts
|
```js
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
adapter: cloudflare({ mode: 'directory' }),
|
adapter: cloudflare({ mode: 'directory' }),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
In `directory` mode, the adapter will compile the client-side part of your app the same way as in `advanced` mode by default, but moves the worker script into a `functions` folder in the project root. In this case, the adapter will only ever place a `[[path]].js` in that folder, allowing you to add additional plugins and pages middleware which can be checked into version control.
|
To compile a separate bundle for each page, set the `functionPerRoute` option in your Cloudflare adapter config. This option requires some manual maintenance of the `functions` folder. Files emitted by Astro will overwrite existing files with identical names in the `functions` folder, so you must choose unique file names for each file you manually add. Additionally, the adapter will never empty the `functions` folder of outdated files, so you must clean up the folder manually when you remove pages.
|
||||||
|
|
||||||
To instead compile a separate bundle for each page, set the `functionPerPath` option in your Cloudflare adapter config. This option requires some manual maintenance of the `functions` folder. Files emitted by Astro will overwrite existing `functions` files with identical names, so you must choose unique file names for each file you manually add. Additionally, the adapter will never empty the `functions` folder of outdated files, so you must clean up the folder manually when you remove pages.
|
```diff lang="js"
|
||||||
|
|
||||||
```diff lang="ts"
|
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
import {defineConfig} from "astro/config";
|
import {defineConfig} from "astro/config";
|
||||||
import cloudflare from '@astrojs/cloudflare';
|
import cloudflare from '@astrojs/cloudflare';
|
||||||
|
@ -74,9 +73,9 @@ To instead compile a separate bundle for each page, set the `functionPerPath` op
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that this adapter does not support using [Cloudflare Pages Middleware](https://developers.cloudflare.com/pages/platform/functions/middleware/). Astro will bundle the [Astro middleware](https://docs.astro.build/en/guides/middleware/) into each page.
|
This adapter doesn't support the [`edgeMiddleware`](https://docs.astro.build/en/reference/adapter-reference/#edgemiddleware) option.
|
||||||
|
|
||||||
### routes.strategy
|
### `routes.strategy`
|
||||||
|
|
||||||
`routes.strategy: "auto" | "include" | "exclude"`
|
`routes.strategy: "auto" | "include" | "exclude"`
|
||||||
|
|
||||||
|
@ -130,16 +129,14 @@ There are three options available:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### routes.include
|
### `routes.include`
|
||||||
|
|
||||||
`routes.include: string[]`
|
`routes.include: string[]`
|
||||||
|
|
||||||
default `[]`
|
default `[]`
|
||||||
|
|
||||||
If you want to use the automatic `_routes.json` generation, but want to include additional routes (e.g. when having custom functions in the `functions` folder), you can use the `routes.include` option to add additional routes to the `include` array.
|
If you want to use the automatic `_routes.json` generation, but want to include additional routes (e.g. when having custom functions in the `functions` folder), you can use the `routes.include` option to add additional routes to the `include` array.
|
||||||
|
|
||||||
### routes.exclude
|
### `routes.exclude`
|
||||||
|
|
||||||
`routes.exclude: string[]`
|
`routes.exclude: string[]`
|
||||||
|
|
||||||
default `[]`
|
default `[]`
|
||||||
|
@ -148,7 +145,7 @@ If you want to use the automatic `_routes.json` generation, but want to exclude
|
||||||
|
|
||||||
The following example automatically generates `_routes.json` while including and excluding additional routes. Note that that is only necessary if you have custom functions in the `functions` folder that are not handled by Astro.
|
The following example automatically generates `_routes.json` while including and excluding additional routes. Note that that is only necessary if you have custom functions in the `functions` folder that are not handled by Astro.
|
||||||
|
|
||||||
```diff lang="ts"
|
```diff lang="js"
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
adapter: cloudflare({
|
adapter: cloudflare({
|
||||||
|
@ -162,133 +159,17 @@ The following example automatically generates `_routes.json` while including and
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Enabling Preview
|
### `wasmModuleImports`
|
||||||
|
|
||||||
In order for preview to work you must install `wrangler`
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm install wrangler --save-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
It's then possible to update the preview script in your `package.json` to `"preview": "wrangler pages dev ./dist"`. This will allow you to 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).
|
|
||||||
|
|
||||||
## Access to the Cloudflare runtime
|
|
||||||
|
|
||||||
You can access all the Cloudflare bindings and environment variables from Astro components and API routes through `Astro.locals`.
|
|
||||||
|
|
||||||
If you're inside an `.astro` file, you access the runtime using the `Astro.locals` global:
|
|
||||||
|
|
||||||
```astro
|
|
||||||
const env = Astro.locals.runtime.env;
|
|
||||||
```
|
|
||||||
|
|
||||||
From an endpoint:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// src/pages/api/someFile.js
|
|
||||||
export function GET(context) {
|
|
||||||
const runtime = context.locals.runtime;
|
|
||||||
|
|
||||||
return new Response('Some body');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Depending on your adapter mode (advanced = worker, directory = pages), the runtime object will look a little different due to differences in the Cloudflare API.
|
|
||||||
|
|
||||||
If you're using the `advanced` runtime, you can type the `runtime` object as following:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// src/env.d.ts
|
|
||||||
/// <reference types="astro/client" />
|
|
||||||
import type { AdvancedRuntime } from '@astrojs/cloudflare';
|
|
||||||
|
|
||||||
type ENV = {
|
|
||||||
SERVER_URL: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare namespace App {
|
|
||||||
interface Locals extends AdvancedRuntime<ENV> {
|
|
||||||
user: {
|
|
||||||
name: string;
|
|
||||||
surname: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're using the `directory` runtime, you can type the `runtime` object as following:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// src/env.d.ts
|
|
||||||
/// <reference types="astro/client" />
|
|
||||||
import type { DirectoryRuntime } from '@astrojs/cloudflare';
|
|
||||||
|
|
||||||
type ENV = {
|
|
||||||
SERVER_URL: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare namespace App {
|
|
||||||
interface Locals extends DirectoryRuntime<ENV> {
|
|
||||||
user: {
|
|
||||||
name: string;
|
|
||||||
surname: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
See Cloudflare's documentation for [working with environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables).
|
|
||||||
|
|
||||||
```js
|
|
||||||
// pages/[id].json.js
|
|
||||||
|
|
||||||
export function GET({ params }) {
|
|
||||||
// Access environment variables per request inside a function
|
|
||||||
const serverUrl = import.meta.env.SERVER_URL;
|
|
||||||
const result = await fetch(serverUrl + "/user/" + params.id);
|
|
||||||
return {
|
|
||||||
body: await result.text(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `cloudflare.runtime`
|
|
||||||
|
|
||||||
`runtime: "off" | "local" | "remote"`
|
|
||||||
default `"off"`
|
|
||||||
|
|
||||||
This optional flag enables the Astro dev server to populate environment variables and the Cloudflare Request Object, avoiding the need for Wrangler.
|
|
||||||
|
|
||||||
- `local`: environment variables are available, but the request object is populated from a static placeholder value.
|
|
||||||
- `remote`: environment variables and the live, fetched request object are available.
|
|
||||||
- `off`: the Astro dev server will populate neither environment variables nor the request object. Use Wrangler to access Cloudflare bindings and environment variables.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// astro.config.mjs
|
|
||||||
import { defineConfig } from 'astro/config';
|
|
||||||
import cloudflare from '@astrojs/cloudflare';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
output: 'server',
|
|
||||||
adapter: cloudflare({
|
|
||||||
runtime: 'off' | 'local' | 'remote',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Wasm module imports
|
|
||||||
|
|
||||||
`wasmModuleImports: boolean`
|
`wasmModuleImports: boolean`
|
||||||
|
|
||||||
default: `false`
|
default: `false`
|
||||||
|
|
||||||
Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration).
|
Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration) using the `.wasm?module` import syntax.
|
||||||
|
|
||||||
Add `wasmModuleImports: true` to `astro.config.mjs` to enable in both the Cloudflare build and the Astro dev server.
|
Add `wasmModuleImports: true` to `astro.config.mjs` to enable this functionality in both the Cloudflare build and the Astro dev server. [Read more](#use-wasm-modules)
|
||||||
|
|
||||||
```diff lang="ts"
|
```diff lang="js"
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
import {defineConfig} from "astro/config";
|
import {defineConfig} from "astro/config";
|
||||||
import cloudflare from '@astrojs/cloudflare';
|
import cloudflare from '@astrojs/cloudflare';
|
||||||
|
@ -301,7 +182,128 @@ Add `wasmModuleImports: true` to `astro.config.mjs` to enable in both the Cloudf
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Once enabled, you can import a web assembly module in Astro with a `.wasm?module` import.
|
### `runtime`
|
||||||
|
|
||||||
|
`runtime: "off" | "local" | "remote"`
|
||||||
|
|
||||||
|
default `"off"`
|
||||||
|
|
||||||
|
Determines whether and how the Cloudflare Runtime is added to `astro dev`.
|
||||||
|
|
||||||
|
The Cloudflare Runtime includes [Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/bindings), [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables), and the [cf object](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties). Read more about [accessing the Cloudflare Runtime](#access-to-the-cloudflare-runtime).
|
||||||
|
|
||||||
|
- `local`: uses bindings mocking and locally static placeholdes
|
||||||
|
- `remote`: uses remote bindings and a live fetched cf object
|
||||||
|
- `off`: no access to the Cloudflare runtime using `astro dev`. You can alternatively use [Preview with Wrangler](#preview-with-wrangler)
|
||||||
|
|
||||||
|
```diff lang="js"
|
||||||
|
// astro.config.mjs
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import cloudflare from '@astrojs/cloudflare';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
|
adapter: cloudflare({
|
||||||
|
+ runtime: 'local',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloudflare runtime
|
||||||
|
|
||||||
|
Gives you access to [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables).
|
||||||
|
|
||||||
|
You can access the runtime from Astro components through `Astro.locals` inside any .astro` file.
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
// src/pages/index.astro
|
||||||
|
const runtime = Astro.locals.runtime;
|
||||||
|
---
|
||||||
|
<pre>{JSON.stringify(runtime.env)}</pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can access the runtime from API endpoints through `context.locals`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// src/pages/api/someFile.js
|
||||||
|
export function GET(context) {
|
||||||
|
const runtime = context.locals.runtime;
|
||||||
|
|
||||||
|
return new Response('Some body');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Typing
|
||||||
|
|
||||||
|
If you have configured `mode: advanced`, you can type the `runtime` object using `AdvancedRuntime`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/env.d.ts
|
||||||
|
/// <reference types="astro/client" />
|
||||||
|
|
||||||
|
type KVNamespace = import('@cloudflare/workers-types/experimental').KVNamespace;
|
||||||
|
type ENV = {
|
||||||
|
SERVER_URL: string;
|
||||||
|
KV_BINDING: KVNamespace;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Runtime = import('@astrojs/cloudflare').AdvancedRuntime<ENV>;
|
||||||
|
|
||||||
|
declare namespace App {
|
||||||
|
interface Locals extends Runtime {
|
||||||
|
user: {
|
||||||
|
name: string;
|
||||||
|
surname: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have configured `mode: directory`, you can type the `runtime` object using `DirectoryRuntime`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/env.d.ts
|
||||||
|
/// <reference types="astro/client" />
|
||||||
|
|
||||||
|
type KVNamespace = import('@cloudflare/workers-types/experimental').KVNamespace;
|
||||||
|
type ENV = {
|
||||||
|
SERVER_URL: string;
|
||||||
|
KV_BINDING: KVNamespace;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Runtime = import('@astrojs/cloudflare').DirectoryRuntime<ENV>;
|
||||||
|
|
||||||
|
declare namespace App {
|
||||||
|
interface Locals extends Runtime {
|
||||||
|
user: {
|
||||||
|
name: string;
|
||||||
|
surname: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform
|
||||||
|
|
||||||
|
### Headers
|
||||||
|
|
||||||
|
You can attach [custom headers](https://developers.cloudflare.com/pages/platform/headers/) to your responses by adding a `_headers` file in your Astro project's `public/` folder. This file will be copied to your build output directory.
|
||||||
|
|
||||||
|
### Redirects
|
||||||
|
|
||||||
|
You can declare [custom redirects](https://developers.cloudflare.com/pages/platform/redirects/) using Cloudflare Pages. This allows you to redirect requests to a different URL. You can add a `_redirects` file in your Astro project's `public/` folder. This file will be copied to your build output directory.
|
||||||
|
|
||||||
|
### Routes
|
||||||
|
|
||||||
|
You can define which routes are invoking functions and which are static assets, using [Cloudflare routing](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes) via a `_routes.json` file. This file is automatically generated by Astro.
|
||||||
|
|
||||||
|
#### Custom `_routes.json`
|
||||||
|
|
||||||
|
By default, `@astrojs/cloudflare` will generate a `_routes.json` file with `include` and `exclude` rules based on your applications's dynamic and static routes.
|
||||||
|
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. See [Cloudflare's documentation on creating a custom `routes.json`](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) for more details.
|
||||||
|
|
||||||
|
## Use Wasm modules
|
||||||
|
|
||||||
The following is an example of importing a Wasm module that then responds to requests by adding the request's number parameters together.
|
The following is an example of importing a Wasm module that then responds to requests by adding the request's number parameters together.
|
||||||
|
|
||||||
|
@ -321,17 +323,6 @@ export async function GET(context) {
|
||||||
|
|
||||||
While this example is trivial, Wasm can be used to accelerate computationally intensive operations which do not involve significant I/O such as embedding an image processing library.
|
While this example is trivial, Wasm can be used to accelerate computationally intensive operations which do not involve significant I/O such as embedding an image processing library.
|
||||||
|
|
||||||
## Headers, Redirects and function invocation routes
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Custom `_routes.json`
|
|
||||||
|
|
||||||
By default, `@astrojs/cloudflare` will generate a `_routes.json` file with `include` and `exclude` rules based on your applications's dynamic and static routes.
|
|
||||||
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.
|
|
||||||
|
|
||||||
See [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) for more details.
|
|
||||||
|
|
||||||
## Node.js compatibility
|
## Node.js compatibility
|
||||||
|
|
||||||
Astro's Cloudflare adapter allows you to use any Node.js runtime API supported by Cloudflare:
|
Astro's Cloudflare adapter allows you to use any Node.js runtime API supported by Cloudflare:
|
||||||
|
@ -355,15 +346,18 @@ export const prerender = false;
|
||||||
import { Buffer } from 'node:buffer';
|
import { Buffer } from 'node:buffer';
|
||||||
```
|
```
|
||||||
|
|
||||||
Additionally, you'll need to enable the Compatibility Flag in Cloudflare. The configuration for this flag may vary based on where you deploy your Astro site.
|
Additionally, you'll need to enable the Compatibility Flag in Cloudflare. The configuration for this flag may vary based on where you deploy your Astro site. For detailed guidance, please refer to the [Cloudflare documentation on enabling Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs).
|
||||||
|
|
||||||
For detailed guidance, please refer to the [Cloudflare documentation](https://developers.cloudflare.com/workers/runtime-apis/nodejs).
|
## Preview with Wrangler
|
||||||
|
|
||||||
## Troubleshooting
|
To use [`wrangler`](https://developers.cloudflare.com/workers/wrangler/) to run your application locally, update the preview script:
|
||||||
|
|
||||||
For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
|
```json
|
||||||
|
//package.json
|
||||||
|
"preview": "wrangler pages dev ./dist"
|
||||||
|
```
|
||||||
|
|
||||||
You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
|
[`wrangler`](https://developers.cloudflare.com/workers/wrangler/) gives you access to [Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/bindings), [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables), and the [cf object](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties). Getting hot reloading or the astro dev server to work with Wrangler might require custom setup. See [community examples](https://github.com/withastro/roadmap/discussions/590).
|
||||||
|
|
||||||
### Meaningful error messages
|
### Meaningful error messages
|
||||||
|
|
||||||
|
@ -383,6 +377,12 @@ Currently, errors during running your application in Wrangler are not very usefu
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
|
||||||
|
|
||||||
|
You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
|
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
|
||||||
|
|
|
@ -19,17 +19,12 @@
|
||||||
"homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/",
|
"homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.js",
|
".": "./dist/index.js",
|
||||||
"./runtime": {
|
"./entrypoints/server.advanced.js": "./dist/entrypoints/server.advanced.js",
|
||||||
"types": "./runtime.d.ts",
|
"./entrypoints/server.directory.js": "./dist/entrypoints/server.directory.js",
|
||||||
"default": "./dist/runtime.js"
|
|
||||||
},
|
|
||||||
"./server.advanced.js": "./dist/server.advanced.js",
|
|
||||||
"./server.directory.js": "./dist/server.directory.js",
|
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist"
|
||||||
"runtime.d.ts"
|
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Request as CFRequest, ExecutionContext } from '@cloudflare/workers-types';
|
import type { Request as CFRequest, ExecutionContext } from '@cloudflare/workers-types';
|
||||||
import type { SSRManifest } from 'astro';
|
import type { SSRManifest } from 'astro';
|
||||||
import { App } from 'astro/app';
|
import { App } from 'astro/app';
|
||||||
import { getProcessEnvProxy, isNode } from './util.js';
|
import { getProcessEnvProxy, isNode } from '../util.js';
|
||||||
|
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
process.env = getProcessEnvProxy();
|
process.env = getProcessEnvProxy();
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Request as CFRequest, EventContext } from '@cloudflare/workers-types';
|
import type { Request as CFRequest, EventContext } from '@cloudflare/workers-types';
|
||||||
import type { SSRManifest } from 'astro';
|
import type { SSRManifest } from 'astro';
|
||||||
import { App } from 'astro/app';
|
import { App } from 'astro/app';
|
||||||
import { getProcessEnvProxy, isNode } from './util.js';
|
import { getProcessEnvProxy, isNode } from '../util.js';
|
||||||
|
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
process.env = getProcessEnvProxy();
|
process.env = getProcessEnvProxy();
|
40
packages/integrations/cloudflare/src/getAdapter.ts
Normal file
40
packages/integrations/cloudflare/src/getAdapter.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import type { AstroAdapter, AstroFeatureMap } from 'astro';
|
||||||
|
|
||||||
|
export function getAdapter({
|
||||||
|
isModeDirectory,
|
||||||
|
functionPerRoute,
|
||||||
|
}: {
|
||||||
|
isModeDirectory: boolean;
|
||||||
|
functionPerRoute: boolean;
|
||||||
|
}): AstroAdapter {
|
||||||
|
const astroFeatures = {
|
||||||
|
hybridOutput: 'stable',
|
||||||
|
staticOutput: 'unsupported',
|
||||||
|
serverOutput: 'stable',
|
||||||
|
assets: {
|
||||||
|
supportKind: 'stable',
|
||||||
|
isSharpCompatible: false,
|
||||||
|
isSquooshCompatible: false,
|
||||||
|
},
|
||||||
|
} satisfies AstroFeatureMap;
|
||||||
|
|
||||||
|
if (isModeDirectory) {
|
||||||
|
return {
|
||||||
|
name: '@astrojs/cloudflare',
|
||||||
|
serverEntrypoint: '@astrojs/cloudflare/entrypoints/server.directory.js',
|
||||||
|
exports: ['onRequest', 'manifest'],
|
||||||
|
adapterFeatures: {
|
||||||
|
functionPerRoute,
|
||||||
|
edgeMiddleware: false,
|
||||||
|
},
|
||||||
|
supportedAstroFeatures: astroFeatures,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: '@astrojs/cloudflare',
|
||||||
|
serverEntrypoint: '@astrojs/cloudflare/entrypoints/server.advanced.js',
|
||||||
|
exports: ['default'],
|
||||||
|
supportedAstroFeatures: astroFeatures,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import type { IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
|
import type { AstroConfig, AstroIntegration, RouteData } from 'astro';
|
||||||
import type { AstroAdapter, AstroConfig, AstroIntegration, RouteData } from 'astro';
|
|
||||||
|
|
||||||
import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects';
|
import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects';
|
||||||
import { CacheStorage } from '@miniflare/cache';
|
import { CacheStorage } from '@miniflare/cache';
|
||||||
|
@ -9,14 +8,19 @@ import { AstroError } from 'astro/errors';
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as os from 'node:os';
|
import * as os from 'node:os';
|
||||||
import { basename, dirname, relative, sep } from 'node:path';
|
import { dirname, relative, sep } from 'node:path';
|
||||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import glob from 'tiny-glob';
|
import glob from 'tiny-glob';
|
||||||
import { getEnvVars } from './parser.js';
|
import { getAdapter } from './getAdapter.js';
|
||||||
import { wasmModuleLoader } from './wasm-module-loader.js';
|
import { deduplicatePatterns } from './utils/deduplicatePatterns.js';
|
||||||
|
import { getCFObject } from './utils/getCFObject.js';
|
||||||
|
import { getEnvVars } from './utils/parser.js';
|
||||||
|
import { prependForwardSlash } from './utils/prependForwardSlash.js';
|
||||||
|
import { rewriteWasmImportPath } from './utils/rewriteWasmImportPath.js';
|
||||||
|
import { wasmModuleLoader } from './utils/wasm-module-loader.js';
|
||||||
|
|
||||||
export type { AdvancedRuntime } from './server.advanced.js';
|
export type { AdvancedRuntime } from './entrypoints/server.advanced.js';
|
||||||
export type { DirectoryRuntime } from './server.directory.js';
|
export type { DirectoryRuntime } from './entrypoints/server.directory.js';
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
mode?: 'directory' | 'advanced';
|
mode?: 'directory' | 'advanced';
|
||||||
|
@ -62,134 +66,13 @@ class StorageFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAdapter({
|
|
||||||
isModeDirectory,
|
|
||||||
functionPerRoute,
|
|
||||||
}: {
|
|
||||||
isModeDirectory: boolean;
|
|
||||||
functionPerRoute: boolean;
|
|
||||||
}): AstroAdapter {
|
|
||||||
return isModeDirectory
|
|
||||||
? {
|
|
||||||
name: '@astrojs/cloudflare',
|
|
||||||
serverEntrypoint: '@astrojs/cloudflare/server.directory.js',
|
|
||||||
exports: ['onRequest', 'manifest'],
|
|
||||||
adapterFeatures: {
|
|
||||||
functionPerRoute,
|
|
||||||
edgeMiddleware: false,
|
|
||||||
},
|
|
||||||
supportedAstroFeatures: {
|
|
||||||
hybridOutput: 'stable',
|
|
||||||
staticOutput: 'unsupported',
|
|
||||||
serverOutput: 'stable',
|
|
||||||
assets: {
|
|
||||||
supportKind: 'stable',
|
|
||||||
isSharpCompatible: false,
|
|
||||||
isSquooshCompatible: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
name: '@astrojs/cloudflare',
|
|
||||||
serverEntrypoint: '@astrojs/cloudflare/server.advanced.js',
|
|
||||||
exports: ['default'],
|
|
||||||
supportedAstroFeatures: {
|
|
||||||
hybridOutput: 'stable',
|
|
||||||
staticOutput: 'unsupported',
|
|
||||||
serverOutput: 'stable',
|
|
||||||
assets: {
|
|
||||||
supportKind: 'stable',
|
|
||||||
isSharpCompatible: false,
|
|
||||||
isSquooshCompatible: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getCFObject(runtimeMode: string): Promise<IncomingRequestCfProperties | void> {
|
|
||||||
const CF_ENDPOINT = 'https://workers.cloudflare.com/cf.json';
|
|
||||||
const CF_FALLBACK: IncomingRequestCfProperties = {
|
|
||||||
asOrganization: '',
|
|
||||||
asn: 395747,
|
|
||||||
colo: 'DFW',
|
|
||||||
city: 'Austin',
|
|
||||||
region: 'Texas',
|
|
||||||
regionCode: 'TX',
|
|
||||||
metroCode: '635',
|
|
||||||
postalCode: '78701',
|
|
||||||
country: 'US',
|
|
||||||
continent: 'NA',
|
|
||||||
timezone: 'America/Chicago',
|
|
||||||
latitude: '30.27130',
|
|
||||||
longitude: '-97.74260',
|
|
||||||
clientTcpRtt: 0,
|
|
||||||
httpProtocol: 'HTTP/1.1',
|
|
||||||
requestPriority: 'weight=192;exclusive=0',
|
|
||||||
tlsCipher: 'AEAD-AES128-GCM-SHA256',
|
|
||||||
tlsVersion: 'TLSv1.3',
|
|
||||||
tlsClientAuth: {
|
|
||||||
certPresented: '0',
|
|
||||||
certVerified: 'NONE',
|
|
||||||
certRevoked: '0',
|
|
||||||
certIssuerDN: '',
|
|
||||||
certSubjectDN: '',
|
|
||||||
certIssuerDNRFC2253: '',
|
|
||||||
certSubjectDNRFC2253: '',
|
|
||||||
certIssuerDNLegacy: '',
|
|
||||||
certSubjectDNLegacy: '',
|
|
||||||
certSerial: '',
|
|
||||||
certIssuerSerial: '',
|
|
||||||
certSKI: '',
|
|
||||||
certIssuerSKI: '',
|
|
||||||
certFingerprintSHA1: '',
|
|
||||||
certFingerprintSHA256: '',
|
|
||||||
certNotBefore: '',
|
|
||||||
certNotAfter: '',
|
|
||||||
},
|
|
||||||
edgeRequestKeepAliveStatus: 0,
|
|
||||||
hostMetadata: undefined,
|
|
||||||
clientTrustScore: 99,
|
|
||||||
botManagement: {
|
|
||||||
corporateProxy: false,
|
|
||||||
verifiedBot: false,
|
|
||||||
ja3Hash: '25b4882c2bcb50cd6b469ff28c596742',
|
|
||||||
staticResource: false,
|
|
||||||
detectionIds: [],
|
|
||||||
score: 99,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (runtimeMode === 'local') {
|
|
||||||
return CF_FALLBACK;
|
|
||||||
} else if (runtimeMode === 'remote') {
|
|
||||||
try {
|
|
||||||
const res = await fetch(CF_ENDPOINT);
|
|
||||||
const cfText = await res.text();
|
|
||||||
const storedCf = JSON.parse(cfText);
|
|
||||||
return storedCf;
|
|
||||||
} catch (e: any) {
|
|
||||||
return CF_FALLBACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SHIM = `globalThis.process = {
|
|
||||||
argv: [],
|
|
||||||
env: {},
|
|
||||||
};`;
|
|
||||||
|
|
||||||
const SERVER_BUILD_FOLDER = '/$server_build/';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These route types are candiates for being part of the `_routes.json` `include` array.
|
|
||||||
*/
|
|
||||||
const potentialFunctionRouteTypes = ['endpoint', 'page'];
|
|
||||||
|
|
||||||
export default function createIntegration(args?: Options): AstroIntegration {
|
export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
let _config: AstroConfig;
|
let _config: AstroConfig;
|
||||||
let _buildConfig: BuildConfig;
|
let _buildConfig: BuildConfig;
|
||||||
let _entryPoints = new Map<RouteData, URL>();
|
let _entryPoints = new Map<RouteData, URL>();
|
||||||
|
|
||||||
|
const SERVER_BUILD_FOLDER = '/$server_build/';
|
||||||
|
|
||||||
const isModeDirectory = args?.mode === 'directory';
|
const isModeDirectory = args?.mode === 'directory';
|
||||||
const functionPerRoute = args?.functionPerRoute ?? false;
|
const functionPerRoute = args?.functionPerRoute ?? false;
|
||||||
const runtimeMode = args?.runtime ?? 'off';
|
const runtimeMode = args?.runtime ?? 'off';
|
||||||
|
@ -221,13 +104,13 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
_config = config;
|
_config = config;
|
||||||
_buildConfig = config.build;
|
_buildConfig = config.build;
|
||||||
|
|
||||||
if (config.output === 'static') {
|
if (_config.output === 'static') {
|
||||||
throw new AstroError(
|
throw new AstroError(
|
||||||
'[@astrojs/cloudflare] `output: "server"` or `output: "hybrid"` is required to use this adapter. Otherwise, this adapter is not necessary to deploy a static site to Cloudflare.'
|
'[@astrojs/cloudflare] `output: "server"` or `output: "hybrid"` is required to use this adapter. Otherwise, this adapter is not necessary to deploy a static site to Cloudflare.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.base === SERVER_BUILD_FOLDER) {
|
if (_config.base === SERVER_BUILD_FOLDER) {
|
||||||
throw new AstroError(
|
throw new AstroError(
|
||||||
'[@astrojs/cloudflare] `base: "${SERVER_BUILD_FOLDER}"` is not allowed. Please change your `base` config to something else.'
|
'[@astrojs/cloudflare] `base: "${SERVER_BUILD_FOLDER}"` is not allowed. Please change your `base` config to something else.'
|
||||||
);
|
);
|
||||||
|
@ -372,7 +255,10 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
bundle: true,
|
bundle: true,
|
||||||
minify: _config.vite?.build?.minify !== false,
|
minify: _config.vite?.build?.minify !== false,
|
||||||
banner: {
|
banner: {
|
||||||
js: SHIM,
|
js: `globalThis.process = {
|
||||||
|
argv: [],
|
||||||
|
env: {},
|
||||||
|
};`,
|
||||||
},
|
},
|
||||||
logOverride: {
|
logOverride: {
|
||||||
'ignored-bare-import': 'silent',
|
'ignored-bare-import': 'silent',
|
||||||
|
@ -449,7 +335,10 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
bundle: true,
|
bundle: true,
|
||||||
minify: _config.vite?.build?.minify !== false,
|
minify: _config.vite?.build?.minify !== false,
|
||||||
banner: {
|
banner: {
|
||||||
js: SHIM,
|
js: `globalThis.process = {
|
||||||
|
argv: [],
|
||||||
|
env: {},
|
||||||
|
};`,
|
||||||
},
|
},
|
||||||
logOverride: {
|
logOverride: {
|
||||||
'ignored-bare-import': 'silent',
|
'ignored-bare-import': 'silent',
|
||||||
|
@ -506,10 +395,14 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
|
|
||||||
// this creates a _routes.json, in case there is none present to enable
|
// this creates a _routes.json, in case there is none present to enable
|
||||||
// cloudflare to handle static files and support _redirects configuration
|
// cloudflare to handle static files and support _redirects configuration
|
||||||
// (without calling the function)
|
|
||||||
if (!routesExists) {
|
if (!routesExists) {
|
||||||
|
/**
|
||||||
|
* These route types are candiates for being part of the `_routes.json` `include` array.
|
||||||
|
*/
|
||||||
|
const potentialFunctionRouteTypes = ['endpoint', 'page'];
|
||||||
|
|
||||||
const functionEndpoints = routes
|
const functionEndpoints = routes
|
||||||
// Certain route types, when their prerender option is set to false, a run on the server as function invocations
|
// Certain route types, when their prerender option is set to false, run on the server as function invocations
|
||||||
.filter((route) => potentialFunctionRouteTypes.includes(route.type) && !route.prerender)
|
.filter((route) => potentialFunctionRouteTypes.includes(route.type) && !route.prerender)
|
||||||
.map((route) => {
|
.map((route) => {
|
||||||
const includePattern =
|
const includePattern =
|
||||||
|
@ -672,59 +565,3 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function prependForwardSlash(path: string) {
|
|
||||||
return path[0] === '/' ? path : '/' + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove duplicates and redundant patterns from an `include` or `exclude` list.
|
|
||||||
* Otherwise Cloudflare will throw an error on deployment. Plus, it saves more entries.
|
|
||||||
* E.g. `['/foo/*', '/foo/*', '/foo/bar'] => ['/foo/*']`
|
|
||||||
* @param patterns a list of `include` or `exclude` patterns
|
|
||||||
* @returns a deduplicated list of patterns
|
|
||||||
*/
|
|
||||||
function deduplicatePatterns(patterns: string[]) {
|
|
||||||
const openPatterns: RegExp[] = [];
|
|
||||||
|
|
||||||
return [...new Set(patterns)]
|
|
||||||
.sort((a, b) => a.length - b.length)
|
|
||||||
.filter((pattern) => {
|
|
||||||
if (openPatterns.some((p) => p.test(pattern))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern.endsWith('*')) {
|
|
||||||
openPatterns.push(new RegExp(`^${pattern.replace(/(\*\/)*\*$/g, '.*')}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param relativePathToAssets - relative path from the final location for the current esbuild output bundle, to the assets directory.
|
|
||||||
*/
|
|
||||||
function rewriteWasmImportPath({
|
|
||||||
relativePathToAssets,
|
|
||||||
}: {
|
|
||||||
relativePathToAssets: string;
|
|
||||||
}): esbuild.Plugin {
|
|
||||||
return {
|
|
||||||
name: 'wasm-loader',
|
|
||||||
setup(build) {
|
|
||||||
build.onResolve({ filter: /.*\.wasm.mjs$/ }, (args) => {
|
|
||||||
const updatedPath = [
|
|
||||||
relativePathToAssets.replaceAll('\\', '/'),
|
|
||||||
basename(args.path).replace(/\.mjs$/, ''),
|
|
||||||
].join('/');
|
|
||||||
|
|
||||||
return {
|
|
||||||
path: updatedPath, // change the reference to the changed module
|
|
||||||
external: true, // mark it as external in the bundle
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* Remove duplicates and redundant patterns from an `include` or `exclude` list.
|
||||||
|
* Otherwise Cloudflare will throw an error on deployment. Plus, it saves more entries.
|
||||||
|
* E.g. `['/foo/*', '/foo/*', '/foo/bar'] => ['/foo/*']`
|
||||||
|
* @param patterns a list of `include` or `exclude` patterns
|
||||||
|
* @returns a deduplicated list of patterns
|
||||||
|
*/
|
||||||
|
export function deduplicatePatterns(patterns: string[]) {
|
||||||
|
const openPatterns: RegExp[] = [];
|
||||||
|
|
||||||
|
// A value in the set may only occur once; it is unique in the set's collection.
|
||||||
|
// ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
|
||||||
|
return [...new Set(patterns)]
|
||||||
|
.sort((a, b) => a.length - b.length)
|
||||||
|
.filter((pattern) => {
|
||||||
|
if (openPatterns.some((p) => p.test(pattern))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pattern.endsWith('*')) {
|
||||||
|
openPatterns.push(new RegExp(`^${pattern.replace(/(\*\/)*\*$/g, '.*')}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
70
packages/integrations/cloudflare/src/utils/getCFObject.ts
Normal file
70
packages/integrations/cloudflare/src/utils/getCFObject.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import type { IncomingRequestCfProperties } from '@cloudflare/workers-types/experimental';
|
||||||
|
|
||||||
|
export async function getCFObject(
|
||||||
|
runtimeMode: string
|
||||||
|
): Promise<IncomingRequestCfProperties | void> {
|
||||||
|
const CF_ENDPOINT = 'https://workers.cloudflare.com/cf.json';
|
||||||
|
const CF_FALLBACK: IncomingRequestCfProperties = {
|
||||||
|
asOrganization: '',
|
||||||
|
asn: 395747,
|
||||||
|
colo: 'DFW',
|
||||||
|
city: 'Austin',
|
||||||
|
region: 'Texas',
|
||||||
|
regionCode: 'TX',
|
||||||
|
metroCode: '635',
|
||||||
|
postalCode: '78701',
|
||||||
|
country: 'US',
|
||||||
|
continent: 'NA',
|
||||||
|
timezone: 'America/Chicago',
|
||||||
|
latitude: '30.27130',
|
||||||
|
longitude: '-97.74260',
|
||||||
|
clientTcpRtt: 0,
|
||||||
|
httpProtocol: 'HTTP/1.1',
|
||||||
|
requestPriority: 'weight=192;exclusive=0',
|
||||||
|
tlsCipher: 'AEAD-AES128-GCM-SHA256',
|
||||||
|
tlsVersion: 'TLSv1.3',
|
||||||
|
tlsClientAuth: {
|
||||||
|
certPresented: '0',
|
||||||
|
certVerified: 'NONE',
|
||||||
|
certRevoked: '0',
|
||||||
|
certIssuerDN: '',
|
||||||
|
certSubjectDN: '',
|
||||||
|
certIssuerDNRFC2253: '',
|
||||||
|
certSubjectDNRFC2253: '',
|
||||||
|
certIssuerDNLegacy: '',
|
||||||
|
certSubjectDNLegacy: '',
|
||||||
|
certSerial: '',
|
||||||
|
certIssuerSerial: '',
|
||||||
|
certSKI: '',
|
||||||
|
certIssuerSKI: '',
|
||||||
|
certFingerprintSHA1: '',
|
||||||
|
certFingerprintSHA256: '',
|
||||||
|
certNotBefore: '',
|
||||||
|
certNotAfter: '',
|
||||||
|
},
|
||||||
|
edgeRequestKeepAliveStatus: 0,
|
||||||
|
hostMetadata: undefined,
|
||||||
|
clientTrustScore: 99,
|
||||||
|
botManagement: {
|
||||||
|
corporateProxy: false,
|
||||||
|
verifiedBot: false,
|
||||||
|
ja3Hash: '25b4882c2bcb50cd6b469ff28c596742',
|
||||||
|
staticResource: false,
|
||||||
|
detectionIds: [],
|
||||||
|
score: 99,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (runtimeMode === 'local') {
|
||||||
|
return CF_FALLBACK;
|
||||||
|
} else if (runtimeMode === 'remote') {
|
||||||
|
try {
|
||||||
|
const res = await fetch(CF_ENDPOINT);
|
||||||
|
const cfText = await res.text();
|
||||||
|
const storedCf = JSON.parse(cfText);
|
||||||
|
return storedCf;
|
||||||
|
} catch (e: any) {
|
||||||
|
return CF_FALLBACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function prependForwardSlash(path: string) {
|
||||||
|
return path[0] === '/' ? path : '/' + path;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import esbuild from 'esbuild';
|
||||||
|
import { basename } from 'node:path';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param relativePathToAssets - relative path from the final location for the current esbuild output bundle, to the assets directory.
|
||||||
|
*/
|
||||||
|
export function rewriteWasmImportPath({
|
||||||
|
relativePathToAssets,
|
||||||
|
}: {
|
||||||
|
relativePathToAssets: string;
|
||||||
|
}): esbuild.Plugin {
|
||||||
|
return {
|
||||||
|
name: 'wasm-loader',
|
||||||
|
setup(build) {
|
||||||
|
build.onResolve({ filter: /.*\.wasm.mjs$/ }, (args) => {
|
||||||
|
const updatedPath = [
|
||||||
|
relativePathToAssets.replaceAll('\\', '/'),
|
||||||
|
basename(args.path).replace(/\.mjs$/, ''),
|
||||||
|
].join('/');
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: updatedPath,
|
||||||
|
external: true, // mark it as external in the bundle
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue