@sveltejs/adapter-netlify 6.0.3 → 7.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/files/edge.js +9 -20
- package/files/serverless.js +18 -23
- package/index.js +209 -198
- package/package.json +9 -14
- package/files/shims.js +0 -32
package/files/edge.js
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
|
-
import { Server } from
|
|
2
|
-
import { manifest } from
|
|
3
|
-
|
|
1
|
+
import { Server } from "0SERVER";
|
|
2
|
+
import { manifest } from "MANIFEST";
|
|
3
|
+
//#region src/edge.js
|
|
4
4
|
const server = new Server(manifest);
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
* We don't know the origin until we receive a request, but
|
|
7
|
+
* that's guaranteed to happen before we call `read`
|
|
8
|
+
* @type {string}
|
|
9
|
+
*/
|
|
11
10
|
let origin;
|
|
12
|
-
|
|
13
11
|
const initialized = server.init({
|
|
14
|
-
// @ts-ignore
|
|
15
12
|
env: Deno.env.toObject(),
|
|
16
13
|
read: async (file) => {
|
|
17
14
|
const url = `${origin}/${file}`;
|
|
18
15
|
const response = await fetch(url);
|
|
19
|
-
|
|
20
|
-
if (!response.ok) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
`read(...) failed: could not fetch ${url} (${response.status} ${response.statusText})`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
16
|
+
if (!response.ok) throw new Error(`read(...) failed: could not fetch ${url} (${response.status} ${response.statusText})`);
|
|
26
17
|
return response.body;
|
|
27
18
|
}
|
|
28
19
|
});
|
|
29
|
-
|
|
30
20
|
/** @type {import('@netlify/edge-functions').EdgeFunction} */
|
|
31
21
|
async function handler(request, context) {
|
|
32
22
|
if (!origin) {
|
|
33
23
|
origin = new URL(request.url).origin;
|
|
34
24
|
await initialized;
|
|
35
25
|
}
|
|
36
|
-
|
|
37
26
|
return server.respond(request, {
|
|
38
27
|
platform: { context },
|
|
39
28
|
getClientAddress() {
|
|
@@ -41,5 +30,5 @@ async function handler(request, context) {
|
|
|
41
30
|
}
|
|
42
31
|
});
|
|
43
32
|
}
|
|
44
|
-
|
|
33
|
+
//#endregion
|
|
45
34
|
export { handler as default };
|
package/files/serverless.js
CHANGED
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import 'node:buffer';
|
|
7
|
-
import 'node:crypto';
|
|
8
|
-
|
|
1
|
+
import { Server } from "0SERVER";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
//#region ../kit/src/exports/node/index.js
|
|
9
6
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
* Converts a file on disk to a readable stream
|
|
8
|
+
* @param {string} file
|
|
9
|
+
* @returns {ReadableStream}
|
|
10
|
+
* @since 2.4.0
|
|
11
|
+
*/
|
|
15
12
|
function createReadableStream(file) {
|
|
16
|
-
return
|
|
13
|
+
return Readable.toWeb(createReadStream(file));
|
|
17
14
|
}
|
|
18
|
-
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/serverless.js
|
|
19
17
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
* @param {import('@sveltejs/kit').SSRManifest} manifest
|
|
19
|
+
* @returns {(request: Request, context: import('@netlify/functions').Context) => Promise<Response>}
|
|
20
|
+
*/
|
|
23
21
|
function init(manifest) {
|
|
24
22
|
const server = new Server(manifest);
|
|
25
|
-
|
|
26
23
|
/** @type {Promise<void> | null} */
|
|
27
24
|
let init_promise = server.init({
|
|
28
|
-
env:
|
|
25
|
+
env: process.env,
|
|
29
26
|
read: (file) => createReadableStream(`.netlify/server/${file}`)
|
|
30
27
|
});
|
|
31
|
-
|
|
32
28
|
return async (request, context) => {
|
|
33
29
|
if (init_promise !== null) {
|
|
34
30
|
await init_promise;
|
|
35
31
|
init_promise = null;
|
|
36
32
|
}
|
|
37
|
-
|
|
38
33
|
return server.respond(request, {
|
|
39
34
|
platform: { context },
|
|
40
35
|
getClientAddress() {
|
|
@@ -43,5 +38,5 @@ function init(manifest) {
|
|
|
43
38
|
});
|
|
44
39
|
};
|
|
45
40
|
}
|
|
46
|
-
|
|
41
|
+
//#endregion
|
|
47
42
|
export { init };
|
package/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { join, resolve, posix } from 'node:path';
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, posix } from 'node:path';
|
|
4
3
|
import { fileURLToPath } from 'node:url';
|
|
5
4
|
import { builtinModules } from 'node:module';
|
|
6
5
|
import process from 'node:process';
|
|
7
|
-
import esbuild from 'esbuild';
|
|
8
6
|
import toml from '@iarna/toml';
|
|
7
|
+
import { build } from 'rolldown';
|
|
8
|
+
import { matches, get_publish_directory, s } from './utils.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {{
|
|
@@ -14,6 +14,9 @@ import toml from '@iarna/toml';
|
|
|
14
14
|
* } & toml.JsonMap} NetlifyConfig
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8'));
|
|
18
|
+
const adapter_version = pkg.version;
|
|
19
|
+
|
|
17
20
|
const name = '@sveltejs/adapter-netlify';
|
|
18
21
|
const files = fileURLToPath(new URL('./files', import.meta.url).href);
|
|
19
22
|
|
|
@@ -21,13 +24,16 @@ const edge_set_in_env_var =
|
|
|
21
24
|
process.env.NETLIFY_SVELTEKIT_USE_EDGE === 'true' ||
|
|
22
25
|
process.env.NETLIFY_SVELTEKIT_USE_EDGE === '1';
|
|
23
26
|
|
|
27
|
+
const netlify_framework_config_path = '.netlify/v1/config.json';
|
|
28
|
+
const netlify_framework_serverless_path = '.netlify/v1/functions';
|
|
29
|
+
const netlify_framework_edge_path = '.netlify/v1/edge-functions';
|
|
30
|
+
|
|
24
31
|
const FUNCTION_PREFIX = 'sveltekit-';
|
|
25
32
|
|
|
26
33
|
/** @type {import('./index.js').default} */
|
|
27
34
|
export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
|
|
28
35
|
return {
|
|
29
36
|
name,
|
|
30
|
-
/** @param {import('@sveltejs/kit').Builder} builder */
|
|
31
37
|
async adapt(builder) {
|
|
32
38
|
if (!builder.routes) {
|
|
33
39
|
throw new Error(
|
|
@@ -55,11 +61,14 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
|
|
|
55
61
|
|
|
56
62
|
// empty out existing build directories
|
|
57
63
|
builder.rimraf(publish);
|
|
64
|
+
builder.rimraf('.netlify/v1');
|
|
65
|
+
|
|
66
|
+
// clean up legacy directories from older adapter versions to avoid
|
|
67
|
+
// gnarly edge cases when an existing project is upgraded to this version
|
|
58
68
|
builder.rimraf('.netlify/edge-functions');
|
|
59
69
|
builder.rimraf('.netlify/server');
|
|
60
70
|
builder.rimraf('.netlify/package.json');
|
|
61
71
|
builder.rimraf('.netlify/serverless.js');
|
|
62
|
-
|
|
63
72
|
if (existsSync('.netlify/functions-internal')) {
|
|
64
73
|
for (const file of readdirSync('.netlify/functions-internal')) {
|
|
65
74
|
if (file.startsWith(FUNCTION_PREFIX)) {
|
|
@@ -75,13 +84,13 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
|
|
|
75
84
|
builder.writeClient(publish_dir);
|
|
76
85
|
builder.writePrerendered(publish_dir);
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
);
|
|
87
|
+
// Copy user's custom _headers file if it exists
|
|
88
|
+
if (existsSync('_headers')) {
|
|
89
|
+
builder.copy('_headers', join(publish, '_headers'));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
builder.log.minor('Writing Netlify config...');
|
|
93
|
+
write_frameworks_config({ builder });
|
|
85
94
|
|
|
86
95
|
if (edge) {
|
|
87
96
|
if (split) {
|
|
@@ -90,7 +99,7 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
|
|
|
90
99
|
|
|
91
100
|
await generate_edge_functions({ builder });
|
|
92
101
|
} else {
|
|
93
|
-
|
|
102
|
+
generate_serverless_functions({ builder, split, publish });
|
|
94
103
|
}
|
|
95
104
|
},
|
|
96
105
|
|
|
@@ -100,131 +109,24 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
|
|
|
100
109
|
}
|
|
101
110
|
};
|
|
102
111
|
}
|
|
103
|
-
/**
|
|
104
|
-
* @param { object } params
|
|
105
|
-
* @param {import('@sveltejs/kit').Builder} params.builder
|
|
106
|
-
*/
|
|
107
|
-
async function generate_edge_functions({ builder }) {
|
|
108
|
-
const tmp = builder.getBuildDirectory('netlify-tmp');
|
|
109
|
-
builder.rimraf(tmp);
|
|
110
|
-
builder.mkdirp(tmp);
|
|
111
|
-
|
|
112
|
-
builder.mkdirp('.netlify/edge-functions');
|
|
113
|
-
|
|
114
|
-
builder.log.minor('Generating Edge Function...');
|
|
115
|
-
const relativePath = posix.relative(tmp, builder.getServerDirectory());
|
|
116
|
-
|
|
117
|
-
builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, {
|
|
118
|
-
replace: {
|
|
119
|
-
'0SERVER': `${relativePath}/index.js`,
|
|
120
|
-
MANIFEST: './manifest.js'
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const manifest = builder.generateManifest({
|
|
125
|
-
relativePath
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
writeFileSync(`${tmp}/manifest.js`, `export const manifest = ${manifest};\n`);
|
|
129
|
-
|
|
130
|
-
/** @type {{ assets: Set<string> }} */
|
|
131
|
-
// we have to prepend the file:// protocol because Windows doesn't support absolute path imports
|
|
132
|
-
const { assets } = (await import(`file://${tmp}/manifest.js`)).manifest;
|
|
133
|
-
|
|
134
|
-
const path = '/*';
|
|
135
|
-
// We only need to specify paths without the trailing slash because
|
|
136
|
-
// Netlify will handle the optional trailing slash for us
|
|
137
|
-
const excluded = [
|
|
138
|
-
// Contains static files
|
|
139
|
-
`/${builder.getAppPath()}/immutable/*`,
|
|
140
|
-
`/${builder.getAppPath()}/version.json`,
|
|
141
|
-
...builder.prerendered.paths,
|
|
142
|
-
...Array.from(assets).flatMap((asset) => {
|
|
143
|
-
if (asset.endsWith('/index.html')) {
|
|
144
|
-
const dir = asset.replace(/\/index\.html$/, '');
|
|
145
|
-
return [
|
|
146
|
-
`${builder.config.kit.paths.base}/${asset}`,
|
|
147
|
-
`${builder.config.kit.paths.base}/${dir}`
|
|
148
|
-
];
|
|
149
|
-
}
|
|
150
|
-
return `${builder.config.kit.paths.base}/${asset}`;
|
|
151
|
-
}),
|
|
152
|
-
// Should not be served by SvelteKit at all
|
|
153
|
-
'/.netlify/*'
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
/** @type {import('@netlify/edge-functions').Manifest} */
|
|
157
|
-
const edge_manifest = {
|
|
158
|
-
functions: [
|
|
159
|
-
{
|
|
160
|
-
function: 'render',
|
|
161
|
-
path,
|
|
162
|
-
excludedPath: /** @type {`/${string}`[]} */ (excluded)
|
|
163
|
-
}
|
|
164
|
-
],
|
|
165
|
-
version: 1
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/** @type {BuildOptions} */
|
|
169
|
-
const esbuild_config = {
|
|
170
|
-
bundle: true,
|
|
171
|
-
format: 'esm',
|
|
172
|
-
platform: 'browser',
|
|
173
|
-
sourcemap: 'linked',
|
|
174
|
-
target: 'es2020',
|
|
175
|
-
loader: {
|
|
176
|
-
'.wasm': 'copy',
|
|
177
|
-
'.woff': 'copy',
|
|
178
|
-
'.woff2': 'copy',
|
|
179
|
-
'.ttf': 'copy',
|
|
180
|
-
'.eot': 'copy',
|
|
181
|
-
'.otf': 'copy'
|
|
182
|
-
},
|
|
183
|
-
// Node built-ins are allowed, but must be prefixed with `node:`
|
|
184
|
-
// https://docs.netlify.com/edge-functions/api/#runtime-environment
|
|
185
|
-
external: builtinModules.map((id) => `node:${id}`),
|
|
186
|
-
alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`]))
|
|
187
|
-
};
|
|
188
|
-
await Promise.all([
|
|
189
|
-
esbuild.build({
|
|
190
|
-
entryPoints: [`${tmp}/entry.js`],
|
|
191
|
-
outfile: '.netlify/edge-functions/render.js',
|
|
192
|
-
...esbuild_config
|
|
193
|
-
}),
|
|
194
|
-
builder.hasServerInstrumentationFile() &&
|
|
195
|
-
esbuild.build({
|
|
196
|
-
entryPoints: [`${builder.getServerDirectory()}/instrumentation.server.js`],
|
|
197
|
-
outfile: '.netlify/edge/instrumentation.server.js',
|
|
198
|
-
...esbuild_config
|
|
199
|
-
})
|
|
200
|
-
]);
|
|
201
112
|
|
|
202
|
-
if (builder.hasServerInstrumentationFile()) {
|
|
203
|
-
builder.instrument({
|
|
204
|
-
entrypoint: '.netlify/edge-functions/render.js',
|
|
205
|
-
instrumentation: '.netlify/edge/instrumentation.server.js',
|
|
206
|
-
start: '.netlify/edge/start.js'
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest));
|
|
211
|
-
}
|
|
212
113
|
/**
|
|
213
114
|
* @param { object } params
|
|
214
115
|
* @param {import('@sveltejs/kit').Builder} params.builder
|
|
215
116
|
* @param { string } params.publish
|
|
216
117
|
* @param { boolean } params.split
|
|
217
118
|
*/
|
|
218
|
-
function
|
|
219
|
-
|
|
119
|
+
function generate_serverless_functions({ builder, publish, split }) {
|
|
120
|
+
// https://docs.netlify.com/build/frameworks/frameworks-api/#netlifyv1functions
|
|
121
|
+
builder.mkdirp(netlify_framework_serverless_path);
|
|
220
122
|
|
|
221
|
-
builder.writeServer('.netlify/server');
|
|
123
|
+
builder.writeServer('.netlify/v1/server');
|
|
222
124
|
|
|
223
125
|
const replace = {
|
|
224
126
|
'0SERVER': './server/index.js' // digit prefix prevents CJS build from using this as a variable name, which would also get replaced
|
|
225
127
|
};
|
|
226
128
|
|
|
227
|
-
builder.copy(files, '.netlify', { replace, filter: (
|
|
129
|
+
builder.copy(files, '.netlify/v1', { replace, filter: (file) => !file.endsWith('edge.js') });
|
|
228
130
|
|
|
229
131
|
builder.log.minor('Generating serverless functions...');
|
|
230
132
|
|
|
@@ -260,7 +162,9 @@ function generate_lambda_functions({ builder, publish, split }) {
|
|
|
260
162
|
|
|
261
163
|
// skip routes with identical patterns, they were already folded into another function
|
|
262
164
|
if (seen.has(pattern)) continue;
|
|
263
|
-
|
|
165
|
+
|
|
166
|
+
const patterns = [pattern, `${pattern === '/' ? '' : pattern}/__data.json`];
|
|
167
|
+
patterns.forEach((p) => seen.add(p));
|
|
264
168
|
|
|
265
169
|
// figure out which lower priority routes should be considered fallbacks
|
|
266
170
|
for (let j = i + 1; j < builder.routes.length; j += 1) {
|
|
@@ -275,12 +179,18 @@ function generate_lambda_functions({ builder, publish, split }) {
|
|
|
275
179
|
generate_serverless_function({
|
|
276
180
|
builder,
|
|
277
181
|
routes,
|
|
278
|
-
patterns
|
|
182
|
+
patterns,
|
|
279
183
|
name
|
|
280
184
|
});
|
|
281
185
|
}
|
|
282
186
|
|
|
283
|
-
|
|
187
|
+
generate_serverless_function({
|
|
188
|
+
builder,
|
|
189
|
+
routes: [],
|
|
190
|
+
patterns: ['/*'],
|
|
191
|
+
name: `${FUNCTION_PREFIX}catch-all`,
|
|
192
|
+
exclude: Array.from(seen)
|
|
193
|
+
});
|
|
284
194
|
} else {
|
|
285
195
|
generate_serverless_function({
|
|
286
196
|
builder,
|
|
@@ -298,75 +208,43 @@ function generate_lambda_functions({ builder, publish, split }) {
|
|
|
298
208
|
}
|
|
299
209
|
}
|
|
300
210
|
|
|
211
|
+
/**
|
|
212
|
+
* @returns {NetlifyConfig | null}
|
|
213
|
+
*/
|
|
301
214
|
function get_netlify_config() {
|
|
302
215
|
if (!existsSync('netlify.toml')) return null;
|
|
303
216
|
|
|
304
217
|
try {
|
|
305
|
-
return
|
|
218
|
+
return toml.parse(readFileSync('netlify.toml', 'utf-8'));
|
|
306
219
|
} catch (err) {
|
|
307
|
-
err
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* @param {NetlifyConfig | null} netlify_config
|
|
314
|
-
* @param {import('@sveltejs/kit').Builder} builder
|
|
315
|
-
**/
|
|
316
|
-
function get_publish_directory(netlify_config, builder) {
|
|
317
|
-
if (netlify_config) {
|
|
318
|
-
if (!netlify_config.build?.publish) {
|
|
319
|
-
builder.log.minor('No publish directory specified in netlify.toml, using default');
|
|
320
|
-
return;
|
|
220
|
+
if (err instanceof Error) {
|
|
221
|
+
throw new Error(`Failed to parse netlify.toml: ${err.message}`, { cause: err });
|
|
321
222
|
}
|
|
322
|
-
|
|
323
|
-
if (resolve(netlify_config.build.publish) === process.cwd()) {
|
|
324
|
-
throw new Error(
|
|
325
|
-
'The publish directory cannot be set to the site root. Please change it to another value such as "build" in netlify.toml.'
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
return netlify_config.build.publish;
|
|
223
|
+
throw err;
|
|
329
224
|
}
|
|
330
|
-
|
|
331
|
-
builder.log.warn(
|
|
332
|
-
'No netlify.toml found. Using default publish directory. Consult https://svelte.dev/docs/kit/adapter-netlify#usage for more details'
|
|
333
|
-
);
|
|
334
225
|
}
|
|
335
226
|
|
|
336
227
|
/**
|
|
337
|
-
*
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* @param {RouteSegment[]} a
|
|
342
|
-
* @param {RouteSegment[]} b
|
|
343
|
-
* @returns {boolean}
|
|
228
|
+
* Writes the Netlify Frameworks API config file
|
|
229
|
+
* https://docs.netlify.com/build/frameworks/frameworks-api/
|
|
230
|
+
* @param {{ builder: import('@sveltejs/kit').Builder }} params
|
|
344
231
|
*/
|
|
345
|
-
function
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
232
|
+
function write_frameworks_config({ builder }) {
|
|
233
|
+
// https://docs.netlify.com/build/frameworks/frameworks-api/#headers
|
|
234
|
+
/** @type {{ headers: Array<{ for: string, values: Record<string, string> }> }} */
|
|
235
|
+
const config = {
|
|
236
|
+
headers: [
|
|
237
|
+
{
|
|
238
|
+
for: `/${builder.getAppPath()}/immutable/*`,
|
|
239
|
+
values: {
|
|
240
|
+
'cache-control': 'public, immutable, max-age=31536000'
|
|
241
|
+
}
|
|
354
242
|
}
|
|
243
|
+
]
|
|
244
|
+
};
|
|
355
245
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (!b[0].dynamic) {
|
|
360
|
-
if (!a[0].dynamic && a[0].content !== b[0].content) return false;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (a.length === 1 && b.length === 1) return true;
|
|
364
|
-
return matches(a.slice(1), b.slice(1));
|
|
365
|
-
} else if (a[0]) {
|
|
366
|
-
return a.length === 1 && a[0].rest;
|
|
367
|
-
} else {
|
|
368
|
-
return b.length === 1 && b[0].rest;
|
|
369
|
-
}
|
|
246
|
+
builder.mkdirp('.netlify/v1');
|
|
247
|
+
writeFileSync(netlify_framework_config_path, s(config));
|
|
370
248
|
}
|
|
371
249
|
|
|
372
250
|
/**
|
|
@@ -375,30 +253,31 @@ function matches(a, b) {
|
|
|
375
253
|
* builder: import('@sveltejs/kit').Builder,
|
|
376
254
|
* routes: import('@sveltejs/kit').RouteDefinition[] | undefined,
|
|
377
255
|
* patterns: string[],
|
|
378
|
-
* name: string
|
|
256
|
+
* name: string,
|
|
257
|
+
* exclude?: string[]
|
|
379
258
|
* }} opts
|
|
380
259
|
*/
|
|
381
|
-
function generate_serverless_function({ builder, routes, patterns, name }) {
|
|
260
|
+
function generate_serverless_function({ builder, routes, patterns, name, exclude }) {
|
|
382
261
|
const manifest = builder.generateManifest({
|
|
383
262
|
relativePath: '../server',
|
|
384
263
|
routes
|
|
385
264
|
});
|
|
386
265
|
|
|
387
266
|
const fn = generate_serverless_function_module(manifest);
|
|
388
|
-
const config = generate_config_export(patterns);
|
|
267
|
+
const config = generate_config_export(patterns, exclude);
|
|
389
268
|
|
|
390
269
|
if (builder.hasServerInstrumentationFile()) {
|
|
391
|
-
writeFileSync(
|
|
270
|
+
writeFileSync(`${netlify_framework_serverless_path}/${name}.mjs`, fn);
|
|
392
271
|
builder.instrument({
|
|
393
|
-
entrypoint:
|
|
394
|
-
instrumentation: '.netlify/server/instrumentation.server.js',
|
|
395
|
-
start: `.netlify/
|
|
272
|
+
entrypoint: `${netlify_framework_serverless_path}/${name}.mjs`,
|
|
273
|
+
instrumentation: '.netlify/v1/server/instrumentation.server.js',
|
|
274
|
+
start: `.netlify/v1/server/${name}.start.mjs`,
|
|
396
275
|
module: {
|
|
397
276
|
generateText: generate_traced_module(config)
|
|
398
277
|
}
|
|
399
278
|
});
|
|
400
279
|
} else {
|
|
401
|
-
writeFileSync(
|
|
280
|
+
writeFileSync(`${netlify_framework_serverless_path}/${name}.mjs`, `${fn}\n${config}`);
|
|
402
281
|
}
|
|
403
282
|
}
|
|
404
283
|
|
|
@@ -414,16 +293,23 @@ export default init(${manifest});
|
|
|
414
293
|
`;
|
|
415
294
|
}
|
|
416
295
|
|
|
296
|
+
const generator_string = `@sveltejs/adapter-netlify@${adapter_version}`;
|
|
297
|
+
|
|
417
298
|
/**
|
|
418
299
|
* @param {string[]} patterns
|
|
300
|
+
* @param {string[]} [exclude]
|
|
419
301
|
* @returns {string}
|
|
420
302
|
*/
|
|
421
|
-
function generate_config_export(patterns) {
|
|
303
|
+
function generate_config_export(patterns, exclude = []) {
|
|
422
304
|
// TODO: add a human friendly name for the function https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-2
|
|
305
|
+
|
|
306
|
+
// https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-2
|
|
423
307
|
return `\
|
|
424
308
|
export const config = {
|
|
425
|
-
|
|
426
|
-
|
|
309
|
+
name: 'SvelteKit server',
|
|
310
|
+
generator: '${generator_string}',
|
|
311
|
+
path: [${patterns.map(s).join(', ')}],
|
|
312
|
+
excludedPath: [${['/.netlify/*', ...exclude].map(s).join(', ')}],
|
|
427
313
|
preferStatic: true
|
|
428
314
|
};
|
|
429
315
|
`;
|
|
@@ -436,10 +322,135 @@ export const config = {
|
|
|
436
322
|
function generate_traced_module(config) {
|
|
437
323
|
return ({ instrumentation, start }) => {
|
|
438
324
|
return `\
|
|
439
|
-
import '
|
|
440
|
-
const { default: _0 } = await import('
|
|
325
|
+
import '../server/${instrumentation}';
|
|
326
|
+
const { default: _0 } = await import('../server/${start}');
|
|
441
327
|
export { _0 as default };
|
|
442
328
|
|
|
443
329
|
${config}`;
|
|
444
330
|
};
|
|
445
331
|
}
|
|
332
|
+
|
|
333
|
+
/** @satisfies {import('rolldown').BuildOptions} */
|
|
334
|
+
const rolldown_config = {
|
|
335
|
+
platform: 'browser',
|
|
336
|
+
output: {
|
|
337
|
+
sourcemap: true,
|
|
338
|
+
codeSplitting: false
|
|
339
|
+
},
|
|
340
|
+
transform: {
|
|
341
|
+
target: 'es2022'
|
|
342
|
+
},
|
|
343
|
+
// Node built-ins are allowed, but must be prefixed with `node:`
|
|
344
|
+
// https://docs.netlify.com/edge-functions/api/#runtime-environment
|
|
345
|
+
external: builtinModules.map((id) => `node:${id}`),
|
|
346
|
+
resolve: {
|
|
347
|
+
alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`]))
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param { object } params
|
|
353
|
+
* @param {import('@sveltejs/kit').Builder} params.builder
|
|
354
|
+
*/
|
|
355
|
+
async function generate_edge_functions({ builder }) {
|
|
356
|
+
const tmp = builder.getBuildDirectory('netlify-tmp');
|
|
357
|
+
builder.rimraf(tmp);
|
|
358
|
+
builder.mkdirp(tmp);
|
|
359
|
+
|
|
360
|
+
// https://docs.netlify.com/build/frameworks/frameworks-api/#edge-functions
|
|
361
|
+
builder.mkdirp('.netlify/v1/edge-functions');
|
|
362
|
+
|
|
363
|
+
builder.log.minor('Generating Edge Function...');
|
|
364
|
+
const relativePath = posix.relative(tmp, builder.getServerDirectory());
|
|
365
|
+
|
|
366
|
+
builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, {
|
|
367
|
+
replace: {
|
|
368
|
+
'0SERVER': `${relativePath}/index.js`,
|
|
369
|
+
MANIFEST: './manifest.js'
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const manifest = builder.generateManifest({
|
|
374
|
+
relativePath
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
writeFileSync(`${tmp}/manifest.js`, `export const manifest = ${manifest};\n`);
|
|
378
|
+
|
|
379
|
+
/** @type {{ assets: Set<string> }} */
|
|
380
|
+
// we have to prepend the file:// protocol because Windows doesn't support absolute path imports
|
|
381
|
+
const { assets } = (await import(`file://${tmp}/manifest.js`)).manifest;
|
|
382
|
+
|
|
383
|
+
const path = '/*';
|
|
384
|
+
// We only need to specify paths without the trailing slash because
|
|
385
|
+
// Netlify will handle the optional trailing slash for us
|
|
386
|
+
const excluded_paths = [
|
|
387
|
+
// Contains static files
|
|
388
|
+
`/${builder.getAppPath()}/immutable/*`,
|
|
389
|
+
`/${builder.getAppPath()}/version.json`,
|
|
390
|
+
...builder.prerendered.paths,
|
|
391
|
+
...Array.from(assets).flatMap((asset) => {
|
|
392
|
+
if (asset.endsWith('/index.html')) {
|
|
393
|
+
const dir = asset.replace(/\/index\.html$/, '');
|
|
394
|
+
return [
|
|
395
|
+
`${builder.config.kit.paths.base}/${asset}`,
|
|
396
|
+
`${builder.config.kit.paths.base}/${dir}`
|
|
397
|
+
];
|
|
398
|
+
}
|
|
399
|
+
return `${builder.config.kit.paths.base}/${asset}`;
|
|
400
|
+
}),
|
|
401
|
+
// Should not be served by SvelteKit at all
|
|
402
|
+
'/.netlify/*'
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
await Promise.all([
|
|
406
|
+
build({
|
|
407
|
+
...rolldown_config,
|
|
408
|
+
input: `${tmp}/entry.js`,
|
|
409
|
+
output: {
|
|
410
|
+
...rolldown_config.output,
|
|
411
|
+
file: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}render.js`
|
|
412
|
+
}
|
|
413
|
+
}),
|
|
414
|
+
builder.hasServerInstrumentationFile() &&
|
|
415
|
+
build({
|
|
416
|
+
...rolldown_config,
|
|
417
|
+
input: `${builder.getServerDirectory()}/instrumentation.server.js`,
|
|
418
|
+
output: {
|
|
419
|
+
...rolldown_config.output,
|
|
420
|
+
file: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}instrumentation.server.js`
|
|
421
|
+
}
|
|
422
|
+
})
|
|
423
|
+
]);
|
|
424
|
+
|
|
425
|
+
if (builder.hasServerInstrumentationFile()) {
|
|
426
|
+
builder.instrument({
|
|
427
|
+
entrypoint: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}render.js`,
|
|
428
|
+
instrumentation: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}instrumentation.server.js`,
|
|
429
|
+
start: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}start.js`
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
add_edge_function_config({ builder, path, excluded_paths });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Adds edge function configuration to the Frameworks API config file `config.json`
|
|
438
|
+
* https://docs.netlify.com/build/frameworks/frameworks-api/#netlifyv1edge-functions
|
|
439
|
+
* @param {{ builder: import('@sveltejs/kit').Builder, path: string, excluded_paths: string[] }} params
|
|
440
|
+
*/
|
|
441
|
+
function add_edge_function_config({ path, excluded_paths }) {
|
|
442
|
+
const config = JSON.parse(readFileSync(netlify_framework_config_path, 'utf-8'));
|
|
443
|
+
|
|
444
|
+
// https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-1
|
|
445
|
+
config.edge_functions = [
|
|
446
|
+
{
|
|
447
|
+
function: `${FUNCTION_PREFIX}render`,
|
|
448
|
+
name: 'SvelteKit server',
|
|
449
|
+
generator: generator_string,
|
|
450
|
+
path,
|
|
451
|
+
excludedPath: excluded_paths
|
|
452
|
+
}
|
|
453
|
+
];
|
|
454
|
+
|
|
455
|
+
writeFileSync(netlify_framework_config_path, s(config));
|
|
456
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/adapter-netlify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-next.0",
|
|
4
4
|
"description": "A SvelteKit adapter that creates a Netlify app",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@iarna/toml": "^2.2.5",
|
|
37
|
-
"
|
|
37
|
+
"rolldown": "^1.0.0-rc.6"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@netlify/dev": "^4.11.2",
|
|
@@ -42,26 +42,21 @@
|
|
|
42
42
|
"@netlify/functions": "^5.0.0",
|
|
43
43
|
"@netlify/node-cookies": "^0.1.0",
|
|
44
44
|
"@netlify/types": "^2.1.0",
|
|
45
|
-
"@
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"@sveltejs/
|
|
49
|
-
"@types/node": "^18.19.119",
|
|
50
|
-
"rollup": "^4.14.2",
|
|
51
|
-
"typescript": "^5.3.3",
|
|
52
|
-
"vitest": "^4.0.0",
|
|
53
|
-
"@sveltejs/kit": "^2.53.0"
|
|
45
|
+
"@types/node": "^22.19.19",
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
|
+
"vitest": "^4.1.7",
|
|
48
|
+
"@sveltejs/kit": "^3.0.0-next.0"
|
|
54
49
|
},
|
|
55
50
|
"peerDependencies": {
|
|
56
51
|
"@sveltejs/kit": "^2.31.0"
|
|
57
52
|
},
|
|
58
53
|
"scripts": {
|
|
59
|
-
"dev": "
|
|
60
|
-
"build": "
|
|
54
|
+
"dev": "rolldown -cw",
|
|
55
|
+
"build": "rolldown -c",
|
|
61
56
|
"check": "tsc",
|
|
62
57
|
"lint": "prettier --check .",
|
|
63
58
|
"format": "pnpm lint --write",
|
|
64
|
-
"test": "pnpm test:integration",
|
|
59
|
+
"test": "pnpm test:unit && pnpm test:integration",
|
|
65
60
|
"test:unit": "vitest run",
|
|
66
61
|
"test:integration": "pnpm build && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test"
|
|
67
62
|
}
|
package/files/shims.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import buffer from 'node:buffer';
|
|
2
|
-
import { webcrypto } from 'node:crypto';
|
|
3
|
-
|
|
4
|
-
// `buffer.File` was added in Node 18.13.0 while the `File` global was added in Node 20.0.0
|
|
5
|
-
const File = /** @type {import('node:buffer') & { File?: File}} */ (buffer).File;
|
|
6
|
-
|
|
7
|
-
/** @type {Record<string, any>} */
|
|
8
|
-
const globals = {
|
|
9
|
-
crypto: webcrypto,
|
|
10
|
-
File
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// exported for dev/preview and node environments
|
|
14
|
-
/**
|
|
15
|
-
* Make various web APIs available as globals:
|
|
16
|
-
* - `crypto`
|
|
17
|
-
* - `File`
|
|
18
|
-
*/
|
|
19
|
-
function installPolyfills() {
|
|
20
|
-
for (const name in globals) {
|
|
21
|
-
if (name in globalThis) continue;
|
|
22
|
-
|
|
23
|
-
Object.defineProperty(globalThis, name, {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
configurable: true,
|
|
26
|
-
writable: true,
|
|
27
|
-
value: globals[name]
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
installPolyfills();
|