feature(@astrojs/cloudflare): port functionPerRoute (#8078)
* port functionPerRoute to cloudflare * add changeset * port bugfix to next * update changeset * Update packages/astro/src/core/build/generate.ts Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * update changeset * update README * add TODO comment * Update .changeset/wise-cameras-agree.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update .changeset/wise-cameras-agree.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update .changeset/nasty-garlics-listen.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * update README * Update .changeset/wise-cameras-agree.md Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com> * Update packages/integrations/cloudflare/README.md Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com> --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com>
This commit is contained in:
parent
bbf0b7470b
commit
2540feedb0
20 changed files with 101 additions and 38 deletions
5
.changeset/nasty-garlics-listen.md
Normal file
5
.changeset/nasty-garlics-listen.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Reimplement https://github.com/withastro/astro/pull/7509 to correctly emit pre-rendered pages now that `build.split` is deprecated and this configuration has been moved to `functionPerRoute` inside the adapter.
|
23
.changeset/wise-cameras-agree.md
Normal file
23
.changeset/wise-cameras-agree.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
'@astrojs/cloudflare': major
|
||||
---
|
||||
|
||||
The configuration `build.split` and `build.excludeMiddleware` are deprecated.
|
||||
|
||||
You can now configure this behavior using `functionPerRoute` in your Cloudflare integration config:
|
||||
|
||||
```diff
|
||||
import {defineConfig} from "astro/config";
|
||||
import cloudflare from '@astrojs/cloudflare';
|
||||
|
||||
export default defineConfig({
|
||||
- build: {
|
||||
- split: true
|
||||
- },
|
||||
- adapter: cloudflare()
|
||||
+ adapter: cloudflare({
|
||||
+ mode: 'directory',
|
||||
+ functionPerRoute: true
|
||||
+ })
|
||||
})
|
||||
```
|
|
@ -158,7 +158,11 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
|
|||
if (pageData.route.prerender) {
|
||||
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
|
||||
const ssrEntryPage = await import(ssrEntryURLPage.toString());
|
||||
if (opts.settings.config.build.split) {
|
||||
if (
|
||||
// TODO: remove in Astro 4.0
|
||||
opts.settings.config.build.split ||
|
||||
opts.settings.adapter?.adapterFeatures?.functionPerRoute
|
||||
) {
|
||||
// forcing to use undefined, so we fail in an expected way if the module is not even there.
|
||||
const ssrEntry = ssrEntryPage?.manifest?.pageModule;
|
||||
if (ssrEntry) {
|
||||
|
|
|
@ -44,23 +44,37 @@ export default defineConfig({
|
|||
|
||||
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.
|
||||
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.
|
||||
|
||||
For most projects the adapter default of `advanced` will be sufficient; the `dist` folder will contain your compiled project. 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.
|
||||
#### `mode:directory`
|
||||
|
||||
In directory mode, the adapter will compile the client side part of your app the same way 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.
|
||||
|
||||
With the build configuration `split: true`, the adapter instead compiles a separate bundle for each page. 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```ts
|
||||
// directory mode
|
||||
// astro.config.mjs
|
||||
export default defineConfig({
|
||||
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 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
|
||||
import {defineConfig} from "astro/config";
|
||||
import cloudflare from '@astrojs/cloudflare';
|
||||
|
||||
export default defineConfig({
|
||||
adapter: cloudflare({
|
||||
mode: 'directory',
|
||||
+ functionPerRoute: true
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Enabling Preview
|
||||
|
||||
In order for preview to work you must install `wrangler`
|
||||
|
|
|
@ -9,6 +9,7 @@ import glob from 'tiny-glob';
|
|||
|
||||
type Options = {
|
||||
mode: 'directory' | 'advanced';
|
||||
functionPerRoute?: boolean;
|
||||
};
|
||||
|
||||
interface BuildConfig {
|
||||
|
@ -18,12 +19,22 @@ interface BuildConfig {
|
|||
split?: boolean;
|
||||
}
|
||||
|
||||
export function getAdapter(isModeDirectory: boolean): AstroAdapter {
|
||||
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',
|
||||
|
@ -67,9 +78,11 @@ const potentialFunctionRouteTypes = ['endpoint', 'page'];
|
|||
export default function createIntegration(args?: Options): AstroIntegration {
|
||||
let _config: AstroConfig;
|
||||
let _buildConfig: BuildConfig;
|
||||
const isModeDirectory = args?.mode === 'directory';
|
||||
let _entryPoints = new Map<RouteData, URL>();
|
||||
|
||||
const isModeDirectory = args?.mode === 'directory';
|
||||
const functionPerRoute = args?.functionPerRoute ?? false;
|
||||
|
||||
return {
|
||||
name: '@astrojs/cloudflare',
|
||||
hooks: {
|
||||
|
@ -84,7 +97,7 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
|||
});
|
||||
},
|
||||
'astro:config:done': ({ setAdapter, config }) => {
|
||||
setAdapter(getAdapter(isModeDirectory));
|
||||
setAdapter(getAdapter({ isModeDirectory, functionPerRoute }));
|
||||
_config = config;
|
||||
_buildConfig = config.build;
|
||||
|
||||
|
@ -136,7 +149,8 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
|||
await fs.promises.mkdir(functionsUrl, { recursive: true });
|
||||
}
|
||||
|
||||
if (isModeDirectory && _buildConfig.split) {
|
||||
// TODO: remove _buildConfig.split in Astro 4.0
|
||||
if (isModeDirectory && (_buildConfig.split || functionPerRoute)) {
|
||||
const entryPointsURL = [..._entryPoints.values()];
|
||||
const entryPaths = entryPointsURL.map((entry) => fileURLToPath(entry));
|
||||
const outputUrl = new URL('$astro', _buildConfig.server);
|
||||
|
|
15
packages/integrations/cloudflare/test/fixtures/function-per-route/astro.config.mjs
vendored
Normal file
15
packages/integrations/cloudflare/test/fixtures/function-per-route/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import cloudflare from '@astrojs/cloudflare';
|
||||
|
||||
export default defineConfig({
|
||||
adapter: cloudflare({
|
||||
mode: 'directory',
|
||||
functionPerRoute: true
|
||||
}),
|
||||
output: 'server',
|
||||
vite: {
|
||||
build: {
|
||||
minify: false,
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@test/astro-cloudflare-split",
|
||||
"name": "@test/astro-cloudflare-function-per-route",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
|
@ -1,25 +1,13 @@
|
|||
import { loadFixture } from './test-utils.js';
|
||||
import { expect } from 'chai';
|
||||
import cloudflare from '../dist/index.js';
|
||||
|
||||
/** @type {import('./test-utils').Fixture} */
|
||||
describe('Cloudflare SSR split', () => {
|
||||
/** @type {import('./test-utils.js').Fixture} */
|
||||
describe('Cloudflare SSR functionPerRoute', () => {
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: './fixtures/split/',
|
||||
adapter: cloudflare({ mode: 'directory' }),
|
||||
output: 'server',
|
||||
build: {
|
||||
split: true,
|
||||
excludeMiddleware: false,
|
||||
},
|
||||
vite: {
|
||||
build: {
|
||||
minify: false,
|
||||
},
|
||||
},
|
||||
root: './fixtures/function-per-route/',
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
|
@ -3644,6 +3644,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/cloudflare/test/fixtures/function-per-route:
|
||||
dependencies:
|
||||
'@astrojs/cloudflare':
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/cloudflare/test/fixtures/no-output:
|
||||
dependencies:
|
||||
'@astrojs/cloudflare':
|
||||
|
@ -3680,15 +3689,6 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/cloudflare/test/fixtures/split:
|
||||
dependencies:
|
||||
'@astrojs/cloudflare':
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/cloudflare/test/fixtures/with-solid-js:
|
||||
dependencies:
|
||||
'@astrojs/cloudflare':
|
||||
|
|
Loading…
Reference in a new issue