Netlify Edge: forward requests for static assets (#3170)
* Netlify Edge: forward requests for static assets * Adds a changeset * Don't run edge tests, yet
This commit is contained in:
parent
e632c09049
commit
19667c45f3
14 changed files with 106 additions and 8 deletions
6
.changeset/smooth-tables-tan.md
Normal file
6
.changeset/smooth-tables-tan.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
'@astrojs/netlify': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Netlify Edge: Forward requests for static assets
|
|
@ -13,8 +13,11 @@ export function deserializeManifest(serializedManifest: SerializedSSRManifest):
|
||||||
route.routeData = deserializeRouteData(serializedRoute.routeData);
|
route.routeData = deserializeRouteData(serializedRoute.routeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const assets = new Set<string>(serializedManifest.assets);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...serializedManifest,
|
...serializedManifest,
|
||||||
|
assets,
|
||||||
routes,
|
routes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,12 @@ export interface SSRManifest {
|
||||||
pageMap: Map<ComponentPath, ComponentInstance>;
|
pageMap: Map<ComponentPath, ComponentInstance>;
|
||||||
renderers: SSRLoadedRenderer[];
|
renderers: SSRLoadedRenderer[];
|
||||||
entryModules: Record<string, string>;
|
entryModules: Record<string, string>;
|
||||||
|
assets: Set<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializedSSRManifest = Omit<SSRManifest, 'routes'> & {
|
export type SerializedSSRManifest = Omit<SSRManifest, 'routes' | 'assets'> & {
|
||||||
routes: SerializedRouteInfo[];
|
routes: SerializedRouteInfo[];
|
||||||
|
assets: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AdapterCreateExports<T = any> = (
|
export type AdapterCreateExports<T = any> = (
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { fileURLToPath } from 'url';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import { createBuildInternals } from '../../core/build/internal.js';
|
import { createBuildInternals } from '../../core/build/internal.js';
|
||||||
import { info } from '../logger/core.js';
|
import { info } from '../logger/core.js';
|
||||||
import { appendForwardSlash, prependForwardSlash } from '../../core/path.js';
|
import { prependForwardSlash } from '../../core/path.js';
|
||||||
import { emptyDir, removeDir } from '../../core/util.js';
|
import { emptyDir, removeDir } from '../../core/util.js';
|
||||||
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
||||||
import { vitePluginHoistedScripts } from './vite-plugin-hoisted-scripts.js';
|
import { vitePluginHoistedScripts } from './vite-plugin-hoisted-scripts.js';
|
||||||
|
|
|
@ -7,6 +7,8 @@ import type { SerializedRouteInfo, SerializedSSRManifest } from '../app/types';
|
||||||
import { serializeRouteData } from '../routing/index.js';
|
import { serializeRouteData } from '../routing/index.js';
|
||||||
import { eachPageData } from './internal.js';
|
import { eachPageData } from './internal.js';
|
||||||
import { addRollupInput } from './add-rollup-input.js';
|
import { addRollupInput } from './add-rollup-input.js';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import glob from 'fast-glob';
|
||||||
import { virtualModuleId as pagesVirtualModuleId } from './vite-plugin-pages.js';
|
import { virtualModuleId as pagesVirtualModuleId } from './vite-plugin-pages.js';
|
||||||
import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
||||||
|
|
||||||
|
@ -65,11 +67,19 @@ if(_start in adapter) {
|
||||||
}
|
}
|
||||||
return void 0;
|
return void 0;
|
||||||
},
|
},
|
||||||
generateBundle(_opts, bundle) {
|
async generateBundle(_opts, bundle) {
|
||||||
const manifest = buildManifest(buildOpts, internals);
|
const staticFiles = await glob('**/*', {
|
||||||
|
cwd: fileURLToPath(buildOpts.buildConfig.client),
|
||||||
|
});
|
||||||
|
|
||||||
|
const manifest = buildManifest(buildOpts, internals, staticFiles);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (const [_chunkName, chunk] of Object.entries(bundle)) {
|
for (const [_chunkName, chunk] of Object.entries(bundle)) {
|
||||||
if (chunk.type === 'asset') continue;
|
if (chunk.type === 'asset') {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
if (chunk.modules[resolvedVirtualModuleId]) {
|
if (chunk.modules[resolvedVirtualModuleId]) {
|
||||||
const code = chunk.code;
|
const code = chunk.code;
|
||||||
chunk.code = code.replace(replaceExp, () => {
|
chunk.code = code.replace(replaceExp, () => {
|
||||||
|
@ -81,7 +91,7 @@ if(_start in adapter) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildManifest(opts: StaticBuildOptions, internals: BuildInternals): SerializedSSRManifest {
|
function buildManifest(opts: StaticBuildOptions, internals: BuildInternals, staticFiles: string[]): SerializedSSRManifest {
|
||||||
const { astroConfig } = opts;
|
const { astroConfig } = opts;
|
||||||
|
|
||||||
const routes: SerializedRouteInfo[] = [];
|
const routes: SerializedRouteInfo[] = [];
|
||||||
|
@ -112,6 +122,7 @@ function buildManifest(opts: StaticBuildOptions, internals: BuildInternals): Ser
|
||||||
pageMap: null as any,
|
pageMap: null as any,
|
||||||
renderers: [],
|
renderers: [],
|
||||||
entryModules,
|
entryModules,
|
||||||
|
assets: staticFiles.map(s => '/' + s)
|
||||||
};
|
};
|
||||||
|
|
||||||
return ssrManifest;
|
return ssrManifest;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
"@astrojs/webapi": "^0.11.1"
|
"@astrojs/webapi": "^0.11.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@netlify/edge-handler-types": "^0.34.1",
|
||||||
"@netlify/functions": "^1.0.0",
|
"@netlify/functions": "^1.0.0",
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*",
|
||||||
"astro-scripts": "workspace:*"
|
"astro-scripts": "workspace:*"
|
||||||
|
|
|
@ -5,7 +5,14 @@ import { App } from 'astro/app';
|
||||||
export function createExports(manifest: SSRManifest) {
|
export function createExports(manifest: SSRManifest) {
|
||||||
const app = new App(manifest);
|
const app = new App(manifest);
|
||||||
|
|
||||||
const handler = async (request: Request): Promise<Response> => {
|
const handler = async (request: Request): Promise<Response | void> => {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
|
||||||
|
// If this matches a static asset, just return and Netlify will forward it
|
||||||
|
// to its static asset handler.
|
||||||
|
if(manifest.assets.has(url.pathname)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (app.match(request)) {
|
if (app.match(request)) {
|
||||||
return app.render(request);
|
return app.render(request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import { netlifyEdgeFunctions } from '@astrojs/netlify';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
adapter: netlifyEdgeFunctions({
|
||||||
|
dist: new URL('./dist/', import.meta.url),
|
||||||
|
}),
|
||||||
|
experimental: {
|
||||||
|
ssr: true
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "@test/netlify-edge-root-dynamic",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "workspace:*",
|
||||||
|
"@astrojs/netlify": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
background: blue;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Testing</title>
|
||||||
|
<link rel="stylesheet" href="/styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Testing</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import { runBuild } from './test-utils.ts';
|
||||||
|
// @ts-ignore
|
||||||
|
import { assertEquals, assert, DOMParser } from './deps.ts';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
Deno.test({
|
||||||
|
name: 'Assets are preferred over HTML routes',
|
||||||
|
async fn() {
|
||||||
|
let close = await runBuild('./fixtures/root-dynamic/');
|
||||||
|
const { default: handler } = await import('./fixtures/root-dynamic/dist/edge-functions/entry.js');
|
||||||
|
const response = await handler(new Request('http://example.com/styles.css'));
|
||||||
|
assertEquals(response, undefined, 'No response because this is an asset');
|
||||||
|
await close();
|
||||||
|
},
|
||||||
|
});
|
|
@ -5,6 +5,10 @@
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"module": "ES2020",
|
"module": "ES2020",
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"target": "ES2020"
|
"target": "ES2020",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
"node_modules/@netlify"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1267,12 +1267,14 @@ importers:
|
||||||
packages/integrations/netlify:
|
packages/integrations/netlify:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/webapi': ^0.11.1
|
'@astrojs/webapi': ^0.11.1
|
||||||
|
'@netlify/edge-handler-types': ^0.34.1
|
||||||
'@netlify/functions': ^1.0.0
|
'@netlify/functions': ^1.0.0
|
||||||
astro: workspace:*
|
astro: workspace:*
|
||||||
astro-scripts: workspace:*
|
astro-scripts: workspace:*
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/webapi': link:../../webapi
|
'@astrojs/webapi': link:../../webapi
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@netlify/edge-handler-types': 0.34.1
|
||||||
'@netlify/functions': 1.0.0
|
'@netlify/functions': 1.0.0
|
||||||
astro: link:../../astro
|
astro: link:../../astro
|
||||||
astro-scripts: link:../../../scripts
|
astro-scripts: link:../../../scripts
|
||||||
|
@ -1287,6 +1289,14 @@ importers:
|
||||||
'@astrojs/react': link:../../../../../react
|
'@astrojs/react': link:../../../../../react
|
||||||
astro: link:../../../../../../astro
|
astro: link:../../../../../../astro
|
||||||
|
|
||||||
|
packages/integrations/netlify/test/edge-functions/fixtures/root-dynamic:
|
||||||
|
specifiers:
|
||||||
|
'@astrojs/netlify': workspace:*
|
||||||
|
astro: workspace:*
|
||||||
|
dependencies:
|
||||||
|
'@astrojs/netlify': link:../../../..
|
||||||
|
astro: link:../../../../../../astro
|
||||||
|
|
||||||
packages/integrations/node:
|
packages/integrations/node:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/webapi': ^0.11.1
|
'@astrojs/webapi': ^0.11.1
|
||||||
|
@ -3485,6 +3495,12 @@ packages:
|
||||||
vue: 3.2.33
|
vue: 3.2.33
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@netlify/edge-handler-types/0.34.1:
|
||||||
|
resolution: {integrity: sha512-YTwn8cw89M4lRTmoUhl9s8ljSGMDt7FOIsxsrx7YrRz/RZlbh4Yuh4RU13DDafDRBEVuRbjGo93cnN621ZfBjA==}
|
||||||
|
dependencies:
|
||||||
|
web-streams-polyfill: 3.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@netlify/functions/1.0.0:
|
/@netlify/functions/1.0.0:
|
||||||
resolution: {integrity: sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==}
|
resolution: {integrity: sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==}
|
||||||
engines: {node: '>=8.3.0'}
|
engines: {node: '>=8.3.0'}
|
||||||
|
|
Loading…
Reference in a new issue