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
|
## Enabling Preview
|
||||||
|
|
||||||
In order for preview to work you must install `wrangler`
|
In order for preview to work you must install `wrangler`
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
"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",
|
||||||
"./server.js": "./dist/server.js",
|
"./server.advanced.js": "./dist/server.advanced.js",
|
||||||
|
"./server.directory.js": "./dist/server.directory.js",
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -3,12 +3,22 @@ import esbuild from 'esbuild';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
export function getAdapter(): AstroAdapter {
|
type Options = {
|
||||||
return {
|
mode: 'directory' | 'advanced';
|
||||||
name: '@astrojs/cloudflare',
|
};
|
||||||
serverEntrypoint: '@astrojs/cloudflare/server.js',
|
|
||||||
exports: ['default'],
|
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 = {
|
const SHIM = `globalThis.process = {
|
||||||
|
@ -16,15 +26,16 @@ const SHIM = `globalThis.process = {
|
||||||
env: {},
|
env: {},
|
||||||
};`;
|
};`;
|
||||||
|
|
||||||
export default function createIntegration(): AstroIntegration {
|
export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
let _config: AstroConfig;
|
let _config: AstroConfig;
|
||||||
let _buildConfig: BuildConfig;
|
let _buildConfig: BuildConfig;
|
||||||
|
const isModeDirectory = args?.mode === 'directory';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/cloudflare',
|
name: '@astrojs/cloudflare',
|
||||||
hooks: {
|
hooks: {
|
||||||
'astro:config:done': ({ setAdapter, config }) => {
|
'astro:config:done': ({ setAdapter, config }) => {
|
||||||
setAdapter(getAdapter());
|
setAdapter(getAdapter(isModeDirectory));
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
if (config.output === 'static') {
|
if (config.output === 'static') {
|
||||||
|
@ -36,8 +47,8 @@ export default function createIntegration(): AstroIntegration {
|
||||||
},
|
},
|
||||||
'astro:build:start': ({ buildConfig }) => {
|
'astro:build:start': ({ buildConfig }) => {
|
||||||
_buildConfig = buildConfig;
|
_buildConfig = buildConfig;
|
||||||
buildConfig.serverEntry = '_worker.js';
|
|
||||||
buildConfig.client = new URL('./static/', _config.outDir);
|
buildConfig.client = new URL('./static/', _config.outDir);
|
||||||
|
buildConfig.serverEntry = '_worker.js';
|
||||||
buildConfig.server = new URL('./', _config.outDir);
|
buildConfig.server = new URL('./', _config.outDir);
|
||||||
},
|
},
|
||||||
'astro:build:setup': ({ vite, target }) => {
|
'astro:build:setup': ({ vite, target }) => {
|
||||||
|
@ -64,7 +75,6 @@ export default function createIntegration(): AstroIntegration {
|
||||||
'astro:build:done': async () => {
|
'astro:build:done': async () => {
|
||||||
const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server);
|
const entryUrl = new URL(_buildConfig.serverEntry, _buildConfig.server);
|
||||||
const pkg = fileURLToPath(entryUrl);
|
const pkg = fileURLToPath(entryUrl);
|
||||||
|
|
||||||
await esbuild.build({
|
await esbuild.build({
|
||||||
target: 'es2020',
|
target: 'es2020',
|
||||||
platform: 'browser',
|
platform: 'browser',
|
||||||
|
@ -82,6 +92,13 @@ export default function createIntegration(): AstroIntegration {
|
||||||
// throw the server folder in the bin
|
// throw the server folder in the bin
|
||||||
const chunksUrl = new URL('./chunks', _buildConfig.server);
|
const chunksUrl = new URL('./chunks', _buildConfig.server);
|
||||||
await fs.promises.rm(chunksUrl, { recursive: true, force: true });
|
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