feat: add support to @astrojs/cloudflare
directory deploy mode (#3806)
Co-authored-by: Matthew Phillips <matthew@skypack.dev> Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
This commit is contained in:
parent
821074fcb5
commit
f4c571bdb0
6 changed files with 98 additions and 11 deletions
5
.changeset/proud-moose-push.md
Normal file
5
.changeset/proud-moose-push.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/cloudflare': minor
|
||||
---
|
||||
|
||||
add support for compiling functions to a functions directory rather than `_worker.js`
|
|
@ -14,6 +14,29 @@ export default defineConfig({
|
|||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
### Mode
|
||||
|
||||
`mode: "advanced" | "directory"`
|
||||
|
||||
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 adaptor default of `advanced` will be sufficiant, when in this mode the `dist` folder will contain your compiled project. However if you'd like to use [pages plugins](https://developers.cloudflare.com/pages/platform/functions/plugins/) such as [Sentry](https://developers.cloudflare.com/pages/platform/functions/plugins/sentry/) for example to enable logging, you'll need to use directory mode.
|
||||
|
||||
In directory mode the adaptor will compile the client side part of you app the same way, but it will move the worker script into a `functions` folder in the project root. The adaptor will only ever place a `[[path]].js` in that folder, allowing you to add additional plugins and pages middlewhere which can be checked into version control .
|
||||
|
||||
```ts
|
||||
// directory mode
|
||||
export default defineConfig({
|
||||
adapter: cloudflare({ mode: "directory" }),
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Enabling Preview
|
||||
|
||||
In order for preview to work you must install `wrangler`
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./server.js": "./dist/server.js",
|
||||
"./server.advanced.js": "./dist/server.advanced.js",
|
||||
"./server.directory.js": "./dist/server.directory.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -3,12 +3,22 @@ import esbuild from 'esbuild';
|
|||
import * as fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export function getAdapter(): AstroAdapter {
|
||||
return {
|
||||
name: '@astrojs/cloudflare',
|
||||
serverEntrypoint: '@astrojs/cloudflare/server.js',
|
||||
exports: ['default'],
|
||||
};
|
||||
type Options = {
|
||||
mode: 'directory' | 'advanced';
|
||||
};
|
||||
|
||||
export function getAdapter(isModeDirectory: boolean): AstroAdapter {
|
||||
return isModeDirectory
|
||||
? {
|
||||
name: '@astrojs/cloudflare',
|
||||
serverEntrypoint: '@astrojs/cloudflare/server.directory.js',
|
||||
exports: ['onRequest'],
|
||||
}
|
||||
: {
|
||||
name: '@astrojs/cloudflare',
|
||||
serverEntrypoint: '@astrojs/cloudflare/server.advanced.js',
|
||||
exports: ['default'],
|
||||
};
|
||||
}
|
||||
|
||||
const SHIM = `globalThis.process = {
|
||||
|
@ -16,15 +26,16 @@ const SHIM = `globalThis.process = {
|
|||
env: {},
|
||||
};`;
|
||||
|
||||
export default function createIntegration(): AstroIntegration {
|
||||
export default function createIntegration(args?: Options): AstroIntegration {
|
||||
let _config: AstroConfig;
|
||||
let _buildConfig: BuildConfig;
|
||||
const isModeDirectory = args?.mode === 'directory';
|
||||
|
||||
return {
|
||||
name: '@astrojs/cloudflare',
|
||||
hooks: {
|
||||
'astro:config:done': ({ setAdapter, config }) => {
|
||||
setAdapter(getAdapter());
|
||||
setAdapter(getAdapter(isModeDirectory));
|
||||
_config = config;
|
||||
|
||||
if (config.output === 'static') {
|
||||
|
@ -36,8 +47,8 @@ export default function createIntegration(): AstroIntegration {
|
|||
},
|
||||
'astro:build:start': ({ buildConfig }) => {
|
||||
_buildConfig = buildConfig;
|
||||
buildConfig.serverEntry = '_worker.js';
|
||||
buildConfig.client = new URL('./static/', _config.outDir);
|
||||
buildConfig.serverEntry = '_worker.js';
|
||||
buildConfig.server = new URL('./', _config.outDir);
|
||||
},
|
||||
'astro:build:setup': ({ vite, target }) => {
|
||||
|
@ -64,7 +75,6 @@ export default function createIntegration(): AstroIntegration {
|
|||
'astro:build:done': async () => {
|
||||
const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server);
|
||||
const pkg = fileURLToPath(entryUrl);
|
||||
|
||||
await esbuild.build({
|
||||
target: 'es2020',
|
||||
platform: 'browser',
|
||||
|
@ -82,6 +92,13 @@ export default function createIntegration(): AstroIntegration {
|
|||
// throw the server folder in the bin
|
||||
const chunksUrl = new URL('./chunks', _buildConfig.server);
|
||||
await fs.promises.rm(chunksUrl, { recursive: true, force: true });
|
||||
|
||||
if (isModeDirectory) {
|
||||
const functionsUrl = new URL(`file://${process.cwd()}/functions/`);
|
||||
await fs.promises.mkdir(functionsUrl, { recursive: true });
|
||||
const directoryUrl = new URL('[[path]].js', functionsUrl);
|
||||
await fs.promises.rename(entryUrl, directoryUrl);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
41
packages/integrations/cloudflare/src/server.directory.ts
Normal file
41
packages/integrations/cloudflare/src/server.directory.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import './shim.js';
|
||||
|
||||
import type { SSRManifest } from 'astro';
|
||||
import { App } from 'astro/app';
|
||||
|
||||
export function createExports(manifest: SSRManifest) {
|
||||
const app = new App(manifest, false)
|
||||
|
||||
const onRequest = async ({
|
||||
request,
|
||||
next,
|
||||
}: {
|
||||
request: Request;
|
||||
next: (request: Request) => void;
|
||||
}) => {
|
||||
const { origin, pathname } = new URL(request.url);
|
||||
|
||||
// static assets
|
||||
if (manifest.assets.has(pathname)) {
|
||||
const assetRequest = new Request(`${origin}/static${pathname}`, request);
|
||||
return next(assetRequest);
|
||||
}
|
||||
|
||||
let routeData = app.match(request, { matchNotFound: true });
|
||||
if (routeData) {
|
||||
Reflect.set(
|
||||
request,
|
||||
Symbol.for('astro.clientAddress'),
|
||||
request.headers.get('cf-connecting-ip')
|
||||
);
|
||||
return app.render(request, routeData);
|
||||
}
|
||||
|
||||
return new Response(null, {
|
||||
status: 404,
|
||||
statusText: 'Not found',
|
||||
});
|
||||
};
|
||||
|
||||
return { onRequest };
|
||||
}
|
Loading…
Reference in a new issue