@sveltejs/adapter-vercel 5.1.0 → 5.2.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 +1 -0
- package/index.js +73 -34
- package/package.json +2 -2
- package/utils.js +58 -12
package/files/edge.js
CHANGED
package/index.js
CHANGED
|
@@ -3,7 +3,8 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { nodeFileTrace } from '@vercel/nft';
|
|
5
5
|
import esbuild from 'esbuild';
|
|
6
|
-
import { get_pathname } from './utils.js';
|
|
6
|
+
import { get_pathname, pattern_to_src } from './utils.js';
|
|
7
|
+
import { VERSION } from '@sveltejs/kit';
|
|
7
8
|
|
|
8
9
|
const name = '@sveltejs/adapter-vercel';
|
|
9
10
|
const DEFAULT_FUNCTION_NAME = 'fn';
|
|
@@ -57,7 +58,12 @@ const plugin = function (defaults = {}) {
|
|
|
57
58
|
functions: `${dir}/functions`
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
builder.log.minor('Copying assets...');
|
|
62
|
+
|
|
63
|
+
builder.writeClient(dirs.static);
|
|
64
|
+
builder.writePrerendered(dirs.static);
|
|
65
|
+
|
|
66
|
+
const static_config = static_vercel_config(builder, defaults, dirs.static);
|
|
61
67
|
|
|
62
68
|
builder.log.minor('Generating serverless function...');
|
|
63
69
|
|
|
@@ -174,7 +180,11 @@ const plugin = function (defaults = {}) {
|
|
|
174
180
|
{
|
|
175
181
|
runtime: config.runtime,
|
|
176
182
|
regions: config.regions,
|
|
177
|
-
entrypoint: 'index.js'
|
|
183
|
+
entrypoint: 'index.js',
|
|
184
|
+
framework: {
|
|
185
|
+
slug: 'sveltekit',
|
|
186
|
+
version: VERSION
|
|
187
|
+
}
|
|
178
188
|
},
|
|
179
189
|
null,
|
|
180
190
|
'\t'
|
|
@@ -305,18 +315,7 @@ const plugin = function (defaults = {}) {
|
|
|
305
315
|
if (is_prerendered(route)) continue;
|
|
306
316
|
|
|
307
317
|
const pattern = route.pattern.toString();
|
|
308
|
-
|
|
309
|
-
let src = pattern
|
|
310
|
-
// remove leading / and trailing $/
|
|
311
|
-
.slice(1, -2)
|
|
312
|
-
// replace escaped \/ with /
|
|
313
|
-
.replace(/\\\//g, '/');
|
|
314
|
-
|
|
315
|
-
// replace the root route "^/" with "^/?"
|
|
316
|
-
if (src === '^/') {
|
|
317
|
-
src = '^/?';
|
|
318
|
-
}
|
|
319
|
-
|
|
318
|
+
const src = pattern_to_src(pattern);
|
|
320
319
|
const name = functions.get(pattern) ?? 'fn-0';
|
|
321
320
|
|
|
322
321
|
const isr = isr_config.get(route);
|
|
@@ -374,11 +373,6 @@ const plugin = function (defaults = {}) {
|
|
|
374
373
|
// including ISR aliases if there is only one function
|
|
375
374
|
static_config.routes.push({ src: '/.*', dest: `/${DEFAULT_FUNCTION_NAME}` });
|
|
376
375
|
|
|
377
|
-
builder.log.minor('Copying assets...');
|
|
378
|
-
|
|
379
|
-
builder.writeClient(dirs.static);
|
|
380
|
-
builder.writePrerendered(dirs.static);
|
|
381
|
-
|
|
382
376
|
builder.log.minor('Writing routes...');
|
|
383
377
|
|
|
384
378
|
write(`${dir}/config.json`, JSON.stringify(static_config, null, '\t'));
|
|
@@ -431,8 +425,9 @@ function write(file, data) {
|
|
|
431
425
|
/**
|
|
432
426
|
* @param {import('@sveltejs/kit').Builder} builder
|
|
433
427
|
* @param {import('.').Config} config
|
|
428
|
+
* @param {string} dir
|
|
434
429
|
*/
|
|
435
|
-
function static_vercel_config(builder, config) {
|
|
430
|
+
function static_vercel_config(builder, config, dir) {
|
|
436
431
|
/** @type {any[]} */
|
|
437
432
|
const prerendered_redirects = [];
|
|
438
433
|
|
|
@@ -473,20 +468,60 @@ function static_vercel_config(builder, config) {
|
|
|
473
468
|
overrides[page.file] = { path: overrides_path };
|
|
474
469
|
}
|
|
475
470
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
{
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
471
|
+
const routes = [
|
|
472
|
+
...prerendered_redirects,
|
|
473
|
+
{
|
|
474
|
+
src: `/${builder.getAppPath()}/immutable/.+`,
|
|
475
|
+
headers: {
|
|
476
|
+
'cache-control': 'public, immutable, max-age=31536000'
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
];
|
|
480
|
+
|
|
481
|
+
// https://vercel.com/docs/deployments/skew-protection
|
|
482
|
+
if (process.env.VERCEL_SKEW_PROTECTION_ENABLED) {
|
|
483
|
+
routes.push({
|
|
484
|
+
src: '/.*',
|
|
485
|
+
has: [
|
|
486
|
+
{
|
|
487
|
+
type: 'header',
|
|
488
|
+
key: 'Sec-Fetch-Dest',
|
|
489
|
+
value: 'document'
|
|
484
490
|
}
|
|
491
|
+
],
|
|
492
|
+
headers: {
|
|
493
|
+
'Set-Cookie': `__vdpl=${process.env.VERCEL_DEPLOYMENT_ID}; Path=${builder.config.kit.paths.base}/; SameSite=Strict; Secure; HttpOnly`
|
|
485
494
|
},
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
495
|
+
continue: true
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// this is a dreadful hack that is necessary until the Vercel Build Output API
|
|
499
|
+
// allows you to set multiple cookies for a single route. essentially, since we
|
|
500
|
+
// know that the entry file will be requested immediately, we can set the second
|
|
501
|
+
// cookie in _that_ response rather than the document response
|
|
502
|
+
const base = `${dir}/${builder.config.kit.appDir}/immutable/entry`;
|
|
503
|
+
const entry = fs.readdirSync(base).find((file) => file.startsWith('start.'));
|
|
504
|
+
|
|
505
|
+
if (!entry) {
|
|
506
|
+
throw new Error('Could not find entry point');
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
routes.splice(-2, 0, {
|
|
510
|
+
src: `/${builder.getAppPath()}/immutable/entry/${entry}`,
|
|
511
|
+
headers: {
|
|
512
|
+
'Set-Cookie': `__vdpl=; Path=/${builder.getAppPath()}/version.json; SameSite=Strict; Secure; HttpOnly`
|
|
513
|
+
},
|
|
514
|
+
continue: true
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
routes.push({
|
|
519
|
+
handle: 'filesystem'
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
return {
|
|
523
|
+
version: 3,
|
|
524
|
+
routes,
|
|
490
525
|
overrides,
|
|
491
526
|
images
|
|
492
527
|
};
|
|
@@ -599,7 +634,11 @@ async function create_function_bundle(builder, entry, dir, config) {
|
|
|
599
634
|
maxDuration: config.maxDuration,
|
|
600
635
|
handler: path.relative(base + ancestor, entry),
|
|
601
636
|
launcherType: 'Nodejs',
|
|
602
|
-
experimentalResponseStreaming: !config.isr
|
|
637
|
+
experimentalResponseStreaming: !config.isr,
|
|
638
|
+
framework: {
|
|
639
|
+
slug: 'sveltekit',
|
|
640
|
+
version: VERSION
|
|
641
|
+
}
|
|
603
642
|
},
|
|
604
643
|
null,
|
|
605
644
|
'\t'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/adapter-vercel",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "A SvelteKit adapter that creates a Vercel app",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@types/node": "^18.19.3",
|
|
34
34
|
"typescript": "^5.3.3",
|
|
35
35
|
"vitest": "^1.2.0",
|
|
36
|
-
"@sveltejs/kit": "^2.4
|
|
36
|
+
"@sveltejs/kit": "^2.5.4"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@sveltejs/kit": "^2.4.0"
|
package/utils.js
CHANGED
|
@@ -2,22 +2,68 @@
|
|
|
2
2
|
export function get_pathname(route) {
|
|
3
3
|
let i = 1;
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const pathname = route.segments
|
|
6
6
|
.map((segment) => {
|
|
7
7
|
if (!segment.dynamic) {
|
|
8
|
-
return segment.content;
|
|
8
|
+
return '/' + segment.content;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const parts = segment.content.split(/\[(.+?)\](?!\])/);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
.
|
|
12
|
+
let result = '';
|
|
13
|
+
|
|
14
|
+
if (
|
|
15
|
+
parts.length === 3 &&
|
|
16
|
+
!parts[0] &&
|
|
17
|
+
!parts[2] &&
|
|
18
|
+
(parts[1].startsWith('...') || parts[1][0] === '[')
|
|
19
|
+
) {
|
|
20
|
+
// Special case: segment is a single optional or rest parameter.
|
|
21
|
+
// In that case we don't prepend a slash (also see comment in pattern_to_src).
|
|
22
|
+
result = `$${i++}`;
|
|
23
|
+
} else {
|
|
24
|
+
result =
|
|
25
|
+
'/' +
|
|
26
|
+
parts
|
|
27
|
+
.map((content, j) => {
|
|
28
|
+
if (j % 2) {
|
|
29
|
+
return `$${i++}`;
|
|
30
|
+
} else {
|
|
31
|
+
return content;
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
.join('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
21
38
|
})
|
|
22
|
-
.join('
|
|
39
|
+
.join('');
|
|
40
|
+
|
|
41
|
+
return pathname[0] === '/' ? pathname.slice(1) : pathname;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Adjusts the stringified route regex for Vercel's routing system
|
|
46
|
+
* @param {string} pattern stringified route regex
|
|
47
|
+
*/
|
|
48
|
+
export function pattern_to_src(pattern) {
|
|
49
|
+
let src = pattern
|
|
50
|
+
// remove leading / and trailing $/
|
|
51
|
+
.slice(1, -2)
|
|
52
|
+
// replace escaped \/ with /
|
|
53
|
+
.replace(/\\\//g, '/');
|
|
54
|
+
|
|
55
|
+
// replace the root route "^/" with "^/?"
|
|
56
|
+
if (src === '^/') {
|
|
57
|
+
src = '^/?';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Move non-capturing groups that swallow slashes into their following capturing groups.
|
|
61
|
+
// This is necessary because during ISR we're using the regex to construct the __pathname
|
|
62
|
+
// query parameter: In case of a route like [required]/[...rest] we need to turn them
|
|
63
|
+
// into $1$2 and not $1/$2, because if [...rest] is empty, we don't want to have a trailing
|
|
64
|
+
// slash in the __pathname query parameter which wasn't there in the original URL, as that
|
|
65
|
+
// could result in a false trailing slash redirect in the SvelteKit runtime, leading to infinite redirects.
|
|
66
|
+
src = src.replace(/\(\?:\/\((.+?)\)\)/g, '(/$1)');
|
|
67
|
+
|
|
68
|
+
return src;
|
|
23
69
|
}
|