Skip to content

Commit 80f1494

Browse files
committed
feat: adapter features, deprecate astro configs (#7839)
1 parent 036388f commit 80f1494

20 files changed

Lines changed: 214 additions & 31 deletions

File tree

.changeset/fair-emus-divide.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
'astro': major
3+
'@astrojs/netlify': minor
4+
---
5+
6+
The configuration `build.split` and `build.excludeMiddleware` are deprecated.
7+
8+
Configuration that were inside the astro configuration, are now moved inside the adapter:
9+
10+
```diff
11+
import {defineConfig} from "astro/config";
12+
import netlify from "@astrojs/netlify/functions";
13+
14+
export default defineConfig({
15+
- build: {
16+
- excludeMiddleware: true
17+
- },
18+
- adapter: netlify()
19+
+ adapter: netlify({
20+
+ edgeMiddleware: true
21+
+ })
22+
})
23+
```
24+
25+
```diff
26+
import {defineConfig} from "astro/config";
27+
import netlify from "@astrojs/netlify/functions";
28+
29+
export default defineConfig({
30+
- build: {
31+
- split: true
32+
- },
33+
- adapter: netlify()
34+
+ adapter: netlify({
35+
+ functionPerRoute: true
36+
+ })
37+
})
38+
```
39+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
'astro': major
3+
'@astrojs/vercel': minor
4+
---
5+
6+
The configuration `build.split` and `build.excludeMiddleware` are deprecated.
7+
8+
Configuration that were inside the astro configuration, are now moved inside the adapter:
9+
10+
```diff
11+
import {defineConfig} from "astro/config";
12+
import vercel from "@astrojs/vercel/serverless";
13+
14+
export default defineConfig({
15+
- build: {
16+
- excludeMiddleware: true
17+
- },
18+
- adapter: vercel()
19+
+ adapter: vercel({
20+
+ edgeMiddleware: true
21+
+ })
22+
})
23+
```
24+
25+
```diff
26+
import {defineConfig} from "astro/config";
27+
import vercel from "@astrojs/vercel/serverless";
28+
29+
export default defineConfig({
30+
- build: {
31+
- split: true
32+
- },
33+
- adapter: vercel()
34+
+ adapter: vercel({
35+
+ functionPerRoute: true
36+
+ })
37+
})
38+
```
39+

packages/astro/src/@types/astro.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,17 @@ export interface DataEntryType {
14151415

14161416
export type GetDataEntryInfoReturnType = { data: Record<string, unknown>; rawData?: string };
14171417

1418+
export interface AstroAdapterFeatures {
1419+
/**
1420+
* Creates and edge function that will communiate with the Astro middleware
1421+
*/
1422+
edgeMiddleware: boolean;
1423+
/**
1424+
* SSR only. Each route becomes its own function/file.
1425+
*/
1426+
functionPerRoute: boolean;
1427+
}
1428+
14181429
export interface AstroSettings {
14191430
config: AstroConfig;
14201431
adapter: AstroAdapter | undefined;
@@ -1680,6 +1691,7 @@ export interface AstroAdapter {
16801691
previewEntrypoint?: string;
16811692
exports?: string[];
16821693
args?: any;
1694+
adapterFeatures?: AstroAdapterFeatures;
16831695
}
16841696

16851697
type Body = string;

packages/astro/src/core/build/plugins/plugin-pages.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
7474
exports.push(`export { renderers };`);
7575

7676
// The middleware should not be imported by the pages
77-
if (!opts.settings.config.build.excludeMiddleware) {
77+
if (
78+
// TODO: remover in Astro 4.0
79+
!opts.settings.config.build.excludeMiddleware ||
80+
opts.settings.adapter?.adapterFeatures?.edgeMiddleware === true
81+
) {
7882
const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
7983
if (middlewareModule) {
8084
imports.push(`import { onRequest } from "${middlewareModule.id}";`);

packages/astro/src/core/build/plugins/plugin-ssr.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { join } from 'node:path';
33
import { fileURLToPath, pathToFileURL } from 'node:url';
44
import type { Plugin as VitePlugin } from 'vite';
55
import type { AstroAdapter, AstroConfig } from '../../../@types/astro';
6-
import { runHookBuildSsr } from '../../../integrations/index.js';
6+
import { isFunctionPerRouteEnabled, runHookBuildSsr } from '../../../integrations/index.js';
77
import { isServerLikeOutput } from '../../../prerender/utils.js';
88
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
99
import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types';
@@ -103,12 +103,16 @@ export function pluginSSR(
103103
internals: BuildInternals
104104
): AstroBuildPlugin {
105105
const ssr = isServerLikeOutput(options.settings.config);
106+
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
106107
return {
107108
build: 'ssr',
108109
hooks: {
109110
'build:before': () => {
110111
let vitePlugin =
111-
ssr && !options.settings.config.build.split
112+
ssr &&
113+
// TODO: Remove in Astro 4.0
114+
options.settings.config.build.split === false &&
115+
functionPerRouteEnabled === false
112116
? vitePluginSSR(internals, options.settings.adapter!, options)
113117
: undefined;
114118

@@ -122,7 +126,7 @@ export function pluginSSR(
122126
return;
123127
}
124128

125-
if (options.settings.config.build.split) {
129+
if (options.settings.config.build.split || functionPerRouteEnabled) {
126130
return;
127131
}
128132

@@ -155,11 +159,12 @@ function vitePluginSSRSplit(
155159
adapter: AstroAdapter,
156160
options: StaticBuildOptions
157161
): VitePlugin {
162+
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
158163
return {
159164
name: '@astrojs/vite-plugin-astro-ssr-split',
160165
enforce: 'post',
161166
options(opts) {
162-
if (options.settings.config.build.split) {
167+
if (options.settings.config.build.split || functionPerRouteEnabled) {
163168
const inputs = new Set<string>();
164169

165170
for (const path of Object.keys(options.allPages)) {
@@ -229,12 +234,14 @@ export function pluginSSRSplit(
229234
internals: BuildInternals
230235
): AstroBuildPlugin {
231236
const ssr = isServerLikeOutput(options.settings.config);
237+
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
238+
232239
return {
233240
build: 'ssr',
234241
hooks: {
235242
'build:before': () => {
236243
let vitePlugin =
237-
ssr && options.settings.config.build.split
244+
ssr && (options.settings.config.build.split || functionPerRouteEnabled)
238245
? vitePluginSSRSplit(internals, options.settings.adapter!, options)
239246
: undefined;
240247

@@ -247,7 +254,7 @@ export function pluginSSRSplit(
247254
if (!ssr) {
248255
return;
249256
}
250-
if (!options.settings.config.build.split) {
257+
if (!options.settings.config.build.split && !functionPerRouteEnabled) {
251258
return;
252259
}
253260

@@ -276,7 +283,7 @@ function generateSSRCode(config: AstroConfig, adapter: AstroAdapter) {
276283
const imports: string[] = [];
277284
const contents: string[] = [];
278285
let pageMap;
279-
if (config.build.split) {
286+
if (config.build.split || isFunctionPerRouteEnabled(adapter)) {
280287
pageMap = 'pageModule';
281288
} else {
282289
pageMap = 'pageMap';
@@ -337,7 +344,10 @@ export async function createManifest(
337344
buildOpts: StaticBuildOptions,
338345
internals: BuildInternals
339346
): Promise<SerializedSSRManifest> {
340-
if (buildOpts.settings.config.build.split) {
347+
if (
348+
buildOpts.settings.config.build.split ||
349+
isFunctionPerRouteEnabled(buildOpts.settings.adapter)
350+
) {
341351
if (internals.ssrSplitEntryChunks.size === 0) {
342352
throw new Error(`Did not generate an entry chunk for SSR in serverless mode`);
343353
}

packages/astro/src/core/config/schema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,15 @@ export const AstroConfigSchema = z.object({
124124
.optional()
125125
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
126126

127+
/**
128+
* @deprecated
129+
* Use the adapter feature instead
130+
*/
127131
split: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.build.split),
132+
/**
133+
* @deprecated
134+
* Use the adapter feature instead
135+
*/
128136
excludeMiddleware: z
129137
.boolean()
130138
.optional()

packages/astro/src/integrations/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { AddressInfo } from 'node:net';
44
import { fileURLToPath } from 'node:url';
55
import type { InlineConfig, ViteDevServer } from 'vite';
66
import type {
7+
AstroAdapter,
78
AstroConfig,
89
AstroIntegration,
910
AstroRenderer,
@@ -410,3 +411,19 @@ export async function runHookBuildDone({ config, pages, routes, logging }: RunHo
410411
}
411412
}
412413
}
414+
415+
export function isFunctionPerRouteEnabled(adapter: AstroAdapter | undefined): boolean {
416+
if (adapter?.adapterFeatures?.functionPerRoute === true) {
417+
return true;
418+
} else {
419+
return false;
420+
}
421+
}
422+
423+
export function isEdgeMiddlewareEnabled(adapter: AstroAdapter | undefined): boolean {
424+
if (adapter?.adapterFeatures?.edgeMiddleware === true) {
425+
return true;
426+
} else {
427+
return false;
428+
}
429+
}

packages/integrations/netlify/src/integration-functions.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,33 @@ import { createRedirects } from './shared.js';
88
export const NETLIFY_EDGE_MIDDLEWARE_FILE = 'netlify-edge-middleware';
99
export const ASTRO_LOCALS_HEADER = 'x-astro-locals';
1010

11-
export function getAdapter(args: Args = {}): AstroAdapter {
11+
export function getAdapter({ functionPerRoute, edgeMiddleware, ...args }: Args): AstroAdapter {
1212
return {
1313
name: '@astrojs/netlify/functions',
1414
serverEntrypoint: '@astrojs/netlify/netlify-functions.js',
1515
exports: ['handler'],
1616
args,
17+
adapterFeatures: {
18+
functionPerRoute,
19+
edgeMiddleware,
20+
},
1721
};
1822
}
1923

2024
interface NetlifyFunctionsOptions {
2125
dist?: URL;
2226
builders?: boolean;
2327
binaryMediaTypes?: string[];
28+
edgeMiddleware?: boolean;
29+
functionPerRoute?: boolean;
2430
}
2531

2632
function netlifyFunctions({
2733
dist,
2834
builders,
2935
binaryMediaTypes,
36+
functionPerRoute = false,
37+
edgeMiddleware = false,
3038
}: NetlifyFunctionsOptions = {}): AstroIntegration {
3139
let _config: AstroConfig;
3240
let _entryPoints: Map<RouteData, URL>;
@@ -53,7 +61,7 @@ function netlifyFunctions({
5361
_entryPoints = entryPoints;
5462
},
5563
'astro:config:done': ({ config, setAdapter }) => {
56-
setAdapter(getAdapter({ binaryMediaTypes, builders }));
64+
setAdapter(getAdapter({ binaryMediaTypes, builders, functionPerRoute, edgeMiddleware }));
5765
_config = config;
5866
ssrEntryFile = config.build.serverEntry.replace(/\.m?js/, '');
5967

packages/integrations/netlify/src/netlify-functions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ applyPolyfills();
99
export interface Args {
1010
builders?: boolean;
1111
binaryMediaTypes?: string[];
12+
edgeMiddleware: boolean;
13+
functionPerRoute: boolean;
1214
}
1315

1416
function parseContentType(header?: string) {

packages/integrations/netlify/test/functions/edge-middleware.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('Middleware', () => {
1010
output: 'server',
1111
adapter: netlifyAdapter({
1212
dist: new URL('./fixtures/middleware-with-handler-file/dist/', import.meta.url),
13+
edgeMiddleware: true,
1314
}),
1415
site: `http://example.com`,
1516
integrations: [testIntegration()],

0 commit comments

Comments
 (0)