vite-plugin-vercel 0.3.7 → 2.0.1
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/README.md +53 -14
- package/dist/index.cjs +156 -34
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +157 -34
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
# vite-plugin-vercel
|
|
2
2
|
|
|
3
|
-
Vercel adapter for [
|
|
3
|
+
Vercel adapter for [Vite](https://vitejs.dev/).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[Vercel API v3](https://vercel.com/docs/build-output-api/v3).
|
|
5
|
+
Bundle your Vite application as supported by [Vercel Output API (v3)](https://vercel.com/docs/build-output-api/v3).
|
|
7
6
|
|
|
8
7
|
## Features
|
|
9
8
|
|
|
10
|
-
- [x] [SSG/Static files
|
|
9
|
+
- [x] [SSG/Static files](https://vercel.com/docs/build-output-api/v3/primitives#static-files)
|
|
11
10
|
- see [`prerender` config](/packages/vercel/src/types.ts#L37)
|
|
12
|
-
- [x] [SSR/Serverless functions
|
|
11
|
+
- [x] [SSR/Serverless functions](https://vercel.com/docs/build-output-api/v3/primitives#serverless-functions)
|
|
13
12
|
- `.[jt]s` files under the `<root>/api` folder of your project are automatically bundled as Serverless functions under `.vercel/output/functions/api/*.func`
|
|
14
13
|
- see [`additionalEndpoints` config](/packages/vercel/src/types.ts#L62)
|
|
15
|
-
- [x] [ISR/Prerender functions
|
|
14
|
+
- [x] [ISR/Prerender functions](https://vercel.com/docs/build-output-api/v3/primitives#prerender-functions)
|
|
16
15
|
- see [`isr` config](/packages/vercel/src/types.ts#L89). Also see implementation of [vike](/packages/vike-integration/vike.ts) for example
|
|
17
|
-
- [x] [Edge functions
|
|
18
|
-
- [
|
|
19
|
-
- [ ] [
|
|
20
|
-
- [
|
|
21
|
-
|
|
16
|
+
- [x] [Edge functions](https://vercel.com/docs/build-output-api/v3/primitives#edge-functions)
|
|
17
|
+
- [x] [Edge middleware](https://vercel.com/docs/functions/edge-middleware/middleware-api)
|
|
18
|
+
- [ ] [Images optimization](https://vercel.com/docs/build-output-api/v3/configuration#images)
|
|
19
|
+
- [ ] [Preview mode](https://vercel.com/docs/build-output-api/v3/features#preview-mode)
|
|
20
|
+
- [x] [Advanced config](/packages/vercel/src/types.ts#L19)
|
|
22
21
|
|
|
23
22
|
## Simple usage
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
Install this package as a dev dependency and add it to your Vite config:
|
|
26
25
|
|
|
27
26
|
```ts
|
|
28
27
|
// vite.config.ts
|
|
@@ -32,11 +31,51 @@ import vercel from 'vite-plugin-vercel';
|
|
|
32
31
|
export default defineConfig({
|
|
33
32
|
plugins: [vercel()],
|
|
34
33
|
vercel: {
|
|
35
|
-
// optional configuration options, see below for details
|
|
34
|
+
// optional configuration options, see "Advanced usage" below for details
|
|
36
35
|
},
|
|
37
36
|
});
|
|
38
37
|
```
|
|
39
38
|
|
|
39
|
+
> [!NOTE]
|
|
40
|
+
> Files under `/api` or `/_api` directory will automatically be added under `/api/*` route
|
|
41
|
+
> Prefer using `/_api` directory, as `@vercel/build` is currently force building `/api` files,
|
|
42
|
+
> with no way to disable it, thus avoiding double compilation and unexpected behaviour.
|
|
43
|
+
|
|
44
|
+
### Configure endpoints
|
|
45
|
+
|
|
46
|
+
Endpoints under `/api`, `/_api` or added through `additionalEndpoints` can be configured
|
|
47
|
+
by exporting values from the endpoint file:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// file: _api/endpoint.ts
|
|
51
|
+
|
|
52
|
+
// Should run on edge runtime
|
|
53
|
+
export const edge = true;
|
|
54
|
+
|
|
55
|
+
// Always add those header to this endpoint
|
|
56
|
+
export const headers = {
|
|
57
|
+
'Some-Header': 'some value',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Enable Incremental Static Regeneration for this endpoint
|
|
61
|
+
export const isr = {
|
|
62
|
+
expiration: 30,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default async function handler() {
|
|
66
|
+
return new Response('Edge Function: OK', {
|
|
67
|
+
status: 200,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> [!NOTE]
|
|
73
|
+
> Please create an issue if you need other per-endpoints configurations
|
|
74
|
+
|
|
75
|
+
### Edge middleware
|
|
76
|
+
|
|
77
|
+
You can use [Edge middleware as describe in the official documentation](https://vercel.com/docs/functions/edge-middleware/middleware-api) (i.e. with a `middleware.ts` file at the root of your project).
|
|
78
|
+
|
|
40
79
|
## Usage with vike
|
|
41
80
|
|
|
42
81
|
[vike](https://vike.dev/) is supported through [@vite-plugin-vercel/vike](/packages/vike-integration/README.md) plugin.
|
|
@@ -126,7 +165,7 @@ export default defineConfig({
|
|
|
126
165
|
*/
|
|
127
166
|
trailingSlash: true,
|
|
128
167
|
/**
|
|
129
|
-
* By default, all `api/*` endpoints are compiled under `.vercel/output/functions/api/*.func`.
|
|
168
|
+
* By default, all `api/*` and `_api/*` endpoints are compiled under `.vercel/output/functions/api/*.func`.
|
|
130
169
|
* If others serverless functions need to be compiled under `.vercel/output/functions`, they should be added here.
|
|
131
170
|
* For instance, a framework can leverage this to have a generic ssr endpoint
|
|
132
171
|
* without requiring the user to write any code.
|
package/dist/index.cjs
CHANGED
|
@@ -158,7 +158,7 @@ function reorderEnforce(arr) {
|
|
|
158
158
|
...arr.filter((r) => r.enforce === "post")
|
|
159
159
|
];
|
|
160
160
|
}
|
|
161
|
-
function getConfig(resolvedConfig, rewrites, overrides) {
|
|
161
|
+
function getConfig(resolvedConfig, rewrites, overrides, headers) {
|
|
162
162
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
163
163
|
const _rewrites = [
|
|
164
164
|
// User provided config always comes first
|
|
@@ -169,27 +169,49 @@ function getConfig(resolvedConfig, rewrites, overrides) {
|
|
|
169
169
|
cleanUrls: ((_b = resolvedConfig.vercel) == null ? void 0 : _b.cleanUrls) ?? true,
|
|
170
170
|
trailingSlash: (_c = resolvedConfig.vercel) == null ? void 0 : _c.trailingSlash,
|
|
171
171
|
rewrites: reorderEnforce(_rewrites),
|
|
172
|
-
redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0
|
|
172
|
+
redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0,
|
|
173
|
+
headers
|
|
173
174
|
});
|
|
174
175
|
if (error) {
|
|
175
176
|
throw error;
|
|
176
177
|
}
|
|
177
|
-
if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0
|
|
178
|
+
if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0 && !resolvedConfig.vercel.config.routes.every(
|
|
179
|
+
(r) => "continue" in r && r.continue
|
|
180
|
+
)) {
|
|
178
181
|
console.warn(
|
|
179
|
-
"
|
|
182
|
+
'Did you forget to add `"continue": true` to your routes? See https://vercel.com/docs/build-output-api/v3/configuration#source-route\nIf not, it is discouraged to use `vercel.config.routes` to override routes. Prefer using `vercel.rewrites` and `vercel.redirects`.'
|
|
180
183
|
);
|
|
181
184
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
let userRoutes = [];
|
|
186
|
+
let buildRoutes = [];
|
|
187
|
+
if ((_i = (_h = resolvedConfig.vercel) == null ? void 0 : _h.config) == null ? void 0 : _i.routes) {
|
|
188
|
+
const norm = (0, import_routing_utils.normalizeRoutes)(resolvedConfig.vercel.config.routes);
|
|
189
|
+
if (norm.error) {
|
|
190
|
+
throw norm.error;
|
|
191
|
+
}
|
|
192
|
+
userRoutes = norm.routes ?? [];
|
|
193
|
+
}
|
|
194
|
+
if (routes) {
|
|
195
|
+
const norm = (0, import_routing_utils.normalizeRoutes)(routes);
|
|
196
|
+
if (norm.error) {
|
|
197
|
+
throw norm.error;
|
|
198
|
+
}
|
|
199
|
+
buildRoutes = norm.routes ?? [];
|
|
188
200
|
}
|
|
201
|
+
const cleanRoutes = (0, import_routing_utils.mergeRoutes)({
|
|
202
|
+
userRoutes,
|
|
203
|
+
builds: [
|
|
204
|
+
{
|
|
205
|
+
use: "@vercel/node",
|
|
206
|
+
entrypoint: "index.js",
|
|
207
|
+
routes: buildRoutes
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
});
|
|
189
211
|
return vercelOutputConfigSchema.parse({
|
|
190
212
|
version: 3,
|
|
191
213
|
...(_j = resolvedConfig.vercel) == null ? void 0 : _j.config,
|
|
192
|
-
routes: cleanRoutes
|
|
214
|
+
routes: cleanRoutes,
|
|
193
215
|
overrides: {
|
|
194
216
|
...(_l = (_k = resolvedConfig.vercel) == null ? void 0 : _k.config) == null ? void 0 : _l.overrides,
|
|
195
217
|
...overrides
|
|
@@ -199,11 +221,11 @@ function getConfig(resolvedConfig, rewrites, overrides) {
|
|
|
199
221
|
function getConfigDestination(resolvedConfig) {
|
|
200
222
|
return import_path2.default.join(getOutput(resolvedConfig), "config.json");
|
|
201
223
|
}
|
|
202
|
-
async function writeConfig(resolvedConfig, rewrites, overrides) {
|
|
224
|
+
async function writeConfig(resolvedConfig, rewrites, overrides, headers) {
|
|
203
225
|
await import_promises.default.writeFile(
|
|
204
226
|
getConfigDestination(resolvedConfig),
|
|
205
227
|
JSON.stringify(
|
|
206
|
-
getConfig(resolvedConfig, rewrites, overrides),
|
|
228
|
+
getConfig(resolvedConfig, rewrites, overrides, headers),
|
|
207
229
|
void 0,
|
|
208
230
|
2
|
|
209
231
|
),
|
|
@@ -256,6 +278,21 @@ var vercelOutputVcConfigSchema = import_zod2.z.union([
|
|
|
256
278
|
|
|
257
279
|
// src/build.ts
|
|
258
280
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
281
|
+
var import_eval = __toESM(require("eval"), 1);
|
|
282
|
+
|
|
283
|
+
// src/schemas/exports.ts
|
|
284
|
+
var import_zod3 = require("zod");
|
|
285
|
+
var vercelEndpointExports = import_zod3.z.object({
|
|
286
|
+
edge: import_zod3.z.boolean().optional(),
|
|
287
|
+
headers: import_zod3.z.record(import_zod3.z.string()).optional(),
|
|
288
|
+
isr: import_zod3.z.object({
|
|
289
|
+
expiration: import_zod3.z.number().or(import_zod3.z.literal(false))
|
|
290
|
+
}).optional()
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// src/build.ts
|
|
294
|
+
var import_magicast = require("magicast");
|
|
295
|
+
var import_build_utils = require("@vercel/build-utils");
|
|
259
296
|
function getAdditionalEndpoints(resolvedConfig) {
|
|
260
297
|
var _a;
|
|
261
298
|
return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => ({
|
|
@@ -368,7 +405,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
|
|
|
368
405
|
}
|
|
369
406
|
const ctx = { found: false, index: "" };
|
|
370
407
|
options.plugins.push(vercelOgPlugin(ctx));
|
|
371
|
-
await (0, import_esbuild.build)(options);
|
|
408
|
+
const output = await (0, import_esbuild.build)(options);
|
|
372
409
|
if (ctx.found && ctx.index) {
|
|
373
410
|
const dir = (0, import_path3.dirname)(ctx.index);
|
|
374
411
|
const externalFiles = await (0, import_fast_glob.default)(`${dir}/*.{ttf,wasm}`);
|
|
@@ -384,6 +421,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
|
|
|
384
421
|
}
|
|
385
422
|
}
|
|
386
423
|
await writeVcConfig(resolvedConfig, entry.destination, Boolean(entry.edge));
|
|
424
|
+
return output;
|
|
387
425
|
}
|
|
388
426
|
async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
389
427
|
var _a;
|
|
@@ -392,6 +430,7 @@ async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
|
392
430
|
destination,
|
|
393
431
|
".vc-config.json"
|
|
394
432
|
);
|
|
433
|
+
const nodeVersion = await (0, import_build_utils.getNodeVersion)(getOutput(resolvedConfig));
|
|
395
434
|
await import_promises2.default.writeFile(
|
|
396
435
|
vcConfig,
|
|
397
436
|
JSON.stringify(
|
|
@@ -400,7 +439,7 @@ async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
|
400
439
|
runtime: "edge",
|
|
401
440
|
entrypoint: "index.js"
|
|
402
441
|
} : {
|
|
403
|
-
runtime:
|
|
442
|
+
runtime: nodeVersion.runtime,
|
|
404
443
|
handler: "index.js",
|
|
405
444
|
maxDuration: (_a = resolvedConfig.vercel) == null ? void 0 : _a.defaultMaxDuration,
|
|
406
445
|
launcherType: "Nodejs",
|
|
@@ -419,28 +458,102 @@ function getSourceAndDestination(destination) {
|
|
|
419
458
|
}
|
|
420
459
|
return import_path3.default.posix.resolve("/", destination, ":match*");
|
|
421
460
|
}
|
|
461
|
+
async function removeDefaultExport(filepath) {
|
|
462
|
+
const mod = await (0, import_magicast.loadFile)(filepath);
|
|
463
|
+
try {
|
|
464
|
+
delete mod.exports.default;
|
|
465
|
+
} catch (_) {
|
|
466
|
+
}
|
|
467
|
+
return (0, import_magicast.generateCode)(mod).code;
|
|
468
|
+
}
|
|
469
|
+
async function extractExports(filepath) {
|
|
470
|
+
var _a;
|
|
471
|
+
try {
|
|
472
|
+
const contents = await removeDefaultExport(filepath);
|
|
473
|
+
const buildOptions = {
|
|
474
|
+
...standardBuildOptions,
|
|
475
|
+
minify: false,
|
|
476
|
+
write: false,
|
|
477
|
+
legalComments: "none"
|
|
478
|
+
};
|
|
479
|
+
buildOptions.stdin = {
|
|
480
|
+
sourcefile: filepath,
|
|
481
|
+
contents,
|
|
482
|
+
loader: filepath.endsWith(".ts") ? "ts" : filepath.endsWith(".tsx") ? "tsx" : filepath.endsWith(".js") ? "js" : filepath.endsWith(".jsx") ? "jsx" : "default",
|
|
483
|
+
resolveDir: (0, import_path3.dirname)(filepath)
|
|
484
|
+
};
|
|
485
|
+
const output = await (0, import_esbuild.build)(buildOptions);
|
|
486
|
+
const bundle = new TextDecoder().decode((_a = output.outputFiles[0]) == null ? void 0 : _a.contents);
|
|
487
|
+
return vercelEndpointExports.parse((0, import_eval.default)(bundle, filepath, {}, true));
|
|
488
|
+
} catch (e) {
|
|
489
|
+
console.warn(`Warning: failed to read exports of '${filepath}'`, e);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
422
492
|
async function buildEndpoints(resolvedConfig) {
|
|
423
493
|
const entries = getEntries(resolvedConfig);
|
|
424
494
|
for (const entry of entries) {
|
|
495
|
+
if (typeof entry.source === "string") {
|
|
496
|
+
const exports = await extractExports(entry.source);
|
|
497
|
+
if (exports) {
|
|
498
|
+
if (entry.headers || exports.headers) {
|
|
499
|
+
entry.headers = {
|
|
500
|
+
...exports.headers,
|
|
501
|
+
...entry.headers
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
if (entry.edge !== void 0 && exports.edge !== void 0) {
|
|
505
|
+
throw new Error(
|
|
506
|
+
`edge configuration should be defined either in the endpoint itself or through Vite config, not both ('${entry.source}')`
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
if (exports.edge !== void 0) {
|
|
510
|
+
entry.edge = exports.edge;
|
|
511
|
+
}
|
|
512
|
+
if (entry.isr !== void 0 && exports.isr !== void 0) {
|
|
513
|
+
throw new Error(
|
|
514
|
+
`isr configuration should be defined either in the endpoint itself or through Vite config, not both ('${entry.source}')`
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
if (exports.isr) {
|
|
518
|
+
entry.isr = exports.isr;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
425
522
|
await buildFn(resolvedConfig, entry);
|
|
426
523
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
524
|
+
const isrEntries = entries.filter((e) => e.isr).map(
|
|
525
|
+
(e) => [
|
|
526
|
+
e.destination.replace(/\.func$/, ""),
|
|
527
|
+
{ expiration: e.isr.expiration }
|
|
528
|
+
]
|
|
529
|
+
);
|
|
530
|
+
return {
|
|
531
|
+
rewrites: entries.filter((e) => e.addRoute !== false).map((e) => e.destination.replace(/\.func$/, "")).map((destination) => ({
|
|
532
|
+
source: getSourceAndDestination(destination),
|
|
533
|
+
destination: getSourceAndDestination(destination)
|
|
534
|
+
})),
|
|
535
|
+
isr: Object.fromEntries(isrEntries),
|
|
536
|
+
headers: entries.filter((e) => e.headers).map((e) => ({
|
|
537
|
+
source: "/" + e.destination.replace(/\.func$/, ""),
|
|
538
|
+
headers: Object.entries(e.headers).map(([key, value]) => ({
|
|
539
|
+
key,
|
|
540
|
+
value
|
|
541
|
+
}))
|
|
542
|
+
}))
|
|
543
|
+
};
|
|
431
544
|
}
|
|
432
545
|
|
|
433
546
|
// src/prerender.ts
|
|
434
547
|
var import_path4 = __toESM(require("path"), 1);
|
|
435
548
|
|
|
436
549
|
// src/schemas/config/prerender-config.ts
|
|
437
|
-
var
|
|
438
|
-
var vercelOutputPrerenderConfigSchema =
|
|
439
|
-
expiration:
|
|
440
|
-
group:
|
|
441
|
-
bypassToken:
|
|
442
|
-
fallback:
|
|
443
|
-
allowQuery:
|
|
550
|
+
var import_zod4 = require("zod");
|
|
551
|
+
var vercelOutputPrerenderConfigSchema = import_zod4.z.object({
|
|
552
|
+
expiration: import_zod4.z.union([import_zod4.z.number().int().positive(), import_zod4.z.literal(false)]),
|
|
553
|
+
group: import_zod4.z.number().int().optional(),
|
|
554
|
+
bypassToken: import_zod4.z.string().optional(),
|
|
555
|
+
fallback: import_zod4.z.string().optional(),
|
|
556
|
+
allowQuery: import_zod4.z.array(import_zod4.z.string()).optional()
|
|
444
557
|
}).strict();
|
|
445
558
|
|
|
446
559
|
// src/prerender.ts
|
|
@@ -494,8 +607,12 @@ function getPrerenderSymlinkInfo(resolvedConfig, destination, target) {
|
|
|
494
607
|
)
|
|
495
608
|
};
|
|
496
609
|
}
|
|
497
|
-
async function buildPrerenderConfigs(resolvedConfig) {
|
|
498
|
-
const isr =
|
|
610
|
+
async function buildPrerenderConfigs(resolvedConfig, extractedIsr) {
|
|
611
|
+
const isr = Object.assign(
|
|
612
|
+
{},
|
|
613
|
+
extractedIsr,
|
|
614
|
+
await getIsrConfig(resolvedConfig)
|
|
615
|
+
);
|
|
499
616
|
const entries = Object.entries(isr);
|
|
500
617
|
const rewrites = [];
|
|
501
618
|
for (const [destination, { symlink, route, ...isr2 }] of entries) {
|
|
@@ -560,12 +677,17 @@ function vercelPlugin() {
|
|
|
560
677
|
}
|
|
561
678
|
const overrides = await execPrerender(resolvedConfig);
|
|
562
679
|
const userOverrides = await computeStaticHtmlOverrides(resolvedConfig);
|
|
563
|
-
const rewrites = await buildEndpoints(resolvedConfig);
|
|
564
|
-
rewrites.push(...await buildPrerenderConfigs(resolvedConfig));
|
|
565
|
-
await writeConfig(
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
680
|
+
const { rewrites, isr, headers } = await buildEndpoints(resolvedConfig);
|
|
681
|
+
rewrites.push(...await buildPrerenderConfigs(resolvedConfig, isr));
|
|
682
|
+
await writeConfig(
|
|
683
|
+
resolvedConfig,
|
|
684
|
+
rewrites,
|
|
685
|
+
{
|
|
686
|
+
...userOverrides,
|
|
687
|
+
...overrides
|
|
688
|
+
},
|
|
689
|
+
headers
|
|
690
|
+
);
|
|
569
691
|
}
|
|
570
692
|
};
|
|
571
693
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -639,6 +639,14 @@ interface ViteVercelApiEntry {
|
|
|
639
639
|
* Set to `true` to mark this function as an Edge Function
|
|
640
640
|
*/
|
|
641
641
|
edge?: boolean;
|
|
642
|
+
/**
|
|
643
|
+
* Additional headers
|
|
644
|
+
*/
|
|
645
|
+
headers?: Record<string, string>;
|
|
646
|
+
/**
|
|
647
|
+
* ISR config
|
|
648
|
+
*/
|
|
649
|
+
isr?: VercelOutputIsr;
|
|
642
650
|
}
|
|
643
651
|
|
|
644
652
|
declare function allPlugins(options?: {
|
package/dist/index.d.ts
CHANGED
|
@@ -639,6 +639,14 @@ interface ViteVercelApiEntry {
|
|
|
639
639
|
* Set to `true` to mark this function as an Edge Function
|
|
640
640
|
*/
|
|
641
641
|
edge?: boolean;
|
|
642
|
+
/**
|
|
643
|
+
* Additional headers
|
|
644
|
+
*/
|
|
645
|
+
headers?: Record<string, string>;
|
|
646
|
+
/**
|
|
647
|
+
* ISR config
|
|
648
|
+
*/
|
|
649
|
+
isr?: VercelOutputIsr;
|
|
642
650
|
}
|
|
643
651
|
|
|
644
652
|
declare function allPlugins(options?: {
|
package/dist/index.js
CHANGED
|
@@ -118,6 +118,7 @@ var vercelOutputConfigSchema = z.object({
|
|
|
118
118
|
import fs from "fs/promises";
|
|
119
119
|
import {
|
|
120
120
|
getTransformedRoutes,
|
|
121
|
+
mergeRoutes,
|
|
121
122
|
normalizeRoutes
|
|
122
123
|
} from "@vercel/routing-utils";
|
|
123
124
|
function reorderEnforce(arr) {
|
|
@@ -127,7 +128,7 @@ function reorderEnforce(arr) {
|
|
|
127
128
|
...arr.filter((r) => r.enforce === "post")
|
|
128
129
|
];
|
|
129
130
|
}
|
|
130
|
-
function getConfig(resolvedConfig, rewrites, overrides) {
|
|
131
|
+
function getConfig(resolvedConfig, rewrites, overrides, headers) {
|
|
131
132
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
132
133
|
const _rewrites = [
|
|
133
134
|
// User provided config always comes first
|
|
@@ -138,27 +139,49 @@ function getConfig(resolvedConfig, rewrites, overrides) {
|
|
|
138
139
|
cleanUrls: ((_b = resolvedConfig.vercel) == null ? void 0 : _b.cleanUrls) ?? true,
|
|
139
140
|
trailingSlash: (_c = resolvedConfig.vercel) == null ? void 0 : _c.trailingSlash,
|
|
140
141
|
rewrites: reorderEnforce(_rewrites),
|
|
141
|
-
redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0
|
|
142
|
+
redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0,
|
|
143
|
+
headers
|
|
142
144
|
});
|
|
143
145
|
if (error) {
|
|
144
146
|
throw error;
|
|
145
147
|
}
|
|
146
|
-
if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0
|
|
148
|
+
if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0 && !resolvedConfig.vercel.config.routes.every(
|
|
149
|
+
(r) => "continue" in r && r.continue
|
|
150
|
+
)) {
|
|
147
151
|
console.warn(
|
|
148
|
-
"
|
|
152
|
+
'Did you forget to add `"continue": true` to your routes? See https://vercel.com/docs/build-output-api/v3/configuration#source-route\nIf not, it is discouraged to use `vercel.config.routes` to override routes. Prefer using `vercel.rewrites` and `vercel.redirects`.'
|
|
149
153
|
);
|
|
150
154
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
let userRoutes = [];
|
|
156
|
+
let buildRoutes = [];
|
|
157
|
+
if ((_i = (_h = resolvedConfig.vercel) == null ? void 0 : _h.config) == null ? void 0 : _i.routes) {
|
|
158
|
+
const norm = normalizeRoutes(resolvedConfig.vercel.config.routes);
|
|
159
|
+
if (norm.error) {
|
|
160
|
+
throw norm.error;
|
|
161
|
+
}
|
|
162
|
+
userRoutes = norm.routes ?? [];
|
|
163
|
+
}
|
|
164
|
+
if (routes) {
|
|
165
|
+
const norm = normalizeRoutes(routes);
|
|
166
|
+
if (norm.error) {
|
|
167
|
+
throw norm.error;
|
|
168
|
+
}
|
|
169
|
+
buildRoutes = norm.routes ?? [];
|
|
157
170
|
}
|
|
171
|
+
const cleanRoutes = mergeRoutes({
|
|
172
|
+
userRoutes,
|
|
173
|
+
builds: [
|
|
174
|
+
{
|
|
175
|
+
use: "@vercel/node",
|
|
176
|
+
entrypoint: "index.js",
|
|
177
|
+
routes: buildRoutes
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
});
|
|
158
181
|
return vercelOutputConfigSchema.parse({
|
|
159
182
|
version: 3,
|
|
160
183
|
...(_j = resolvedConfig.vercel) == null ? void 0 : _j.config,
|
|
161
|
-
routes: cleanRoutes
|
|
184
|
+
routes: cleanRoutes,
|
|
162
185
|
overrides: {
|
|
163
186
|
...(_l = (_k = resolvedConfig.vercel) == null ? void 0 : _k.config) == null ? void 0 : _l.overrides,
|
|
164
187
|
...overrides
|
|
@@ -168,11 +191,11 @@ function getConfig(resolvedConfig, rewrites, overrides) {
|
|
|
168
191
|
function getConfigDestination(resolvedConfig) {
|
|
169
192
|
return path2.join(getOutput(resolvedConfig), "config.json");
|
|
170
193
|
}
|
|
171
|
-
async function writeConfig(resolvedConfig, rewrites, overrides) {
|
|
194
|
+
async function writeConfig(resolvedConfig, rewrites, overrides, headers) {
|
|
172
195
|
await fs.writeFile(
|
|
173
196
|
getConfigDestination(resolvedConfig),
|
|
174
197
|
JSON.stringify(
|
|
175
|
-
getConfig(resolvedConfig, rewrites, overrides),
|
|
198
|
+
getConfig(resolvedConfig, rewrites, overrides, headers),
|
|
176
199
|
void 0,
|
|
177
200
|
2
|
|
178
201
|
),
|
|
@@ -225,6 +248,21 @@ var vercelOutputVcConfigSchema = z2.union([
|
|
|
225
248
|
|
|
226
249
|
// src/build.ts
|
|
227
250
|
import fs2, { copyFile } from "fs/promises";
|
|
251
|
+
import _eval from "eval";
|
|
252
|
+
|
|
253
|
+
// src/schemas/exports.ts
|
|
254
|
+
import { z as z3 } from "zod";
|
|
255
|
+
var vercelEndpointExports = z3.object({
|
|
256
|
+
edge: z3.boolean().optional(),
|
|
257
|
+
headers: z3.record(z3.string()).optional(),
|
|
258
|
+
isr: z3.object({
|
|
259
|
+
expiration: z3.number().or(z3.literal(false))
|
|
260
|
+
}).optional()
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// src/build.ts
|
|
264
|
+
import { generateCode, loadFile } from "magicast";
|
|
265
|
+
import { getNodeVersion } from "@vercel/build-utils";
|
|
228
266
|
function getAdditionalEndpoints(resolvedConfig) {
|
|
229
267
|
var _a;
|
|
230
268
|
return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => ({
|
|
@@ -337,7 +375,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
|
|
|
337
375
|
}
|
|
338
376
|
const ctx = { found: false, index: "" };
|
|
339
377
|
options.plugins.push(vercelOgPlugin(ctx));
|
|
340
|
-
await build(options);
|
|
378
|
+
const output = await build(options);
|
|
341
379
|
if (ctx.found && ctx.index) {
|
|
342
380
|
const dir = dirname(ctx.index);
|
|
343
381
|
const externalFiles = await glob(`${dir}/*.{ttf,wasm}`);
|
|
@@ -353,6 +391,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
|
|
|
353
391
|
}
|
|
354
392
|
}
|
|
355
393
|
await writeVcConfig(resolvedConfig, entry.destination, Boolean(entry.edge));
|
|
394
|
+
return output;
|
|
356
395
|
}
|
|
357
396
|
async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
358
397
|
var _a;
|
|
@@ -361,6 +400,7 @@ async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
|
361
400
|
destination,
|
|
362
401
|
".vc-config.json"
|
|
363
402
|
);
|
|
403
|
+
const nodeVersion = await getNodeVersion(getOutput(resolvedConfig));
|
|
364
404
|
await fs2.writeFile(
|
|
365
405
|
vcConfig,
|
|
366
406
|
JSON.stringify(
|
|
@@ -369,7 +409,7 @@ async function writeVcConfig(resolvedConfig, destination, edge) {
|
|
|
369
409
|
runtime: "edge",
|
|
370
410
|
entrypoint: "index.js"
|
|
371
411
|
} : {
|
|
372
|
-
runtime:
|
|
412
|
+
runtime: nodeVersion.runtime,
|
|
373
413
|
handler: "index.js",
|
|
374
414
|
maxDuration: (_a = resolvedConfig.vercel) == null ? void 0 : _a.defaultMaxDuration,
|
|
375
415
|
launcherType: "Nodejs",
|
|
@@ -388,28 +428,102 @@ function getSourceAndDestination(destination) {
|
|
|
388
428
|
}
|
|
389
429
|
return path3.posix.resolve("/", destination, ":match*");
|
|
390
430
|
}
|
|
431
|
+
async function removeDefaultExport(filepath) {
|
|
432
|
+
const mod = await loadFile(filepath);
|
|
433
|
+
try {
|
|
434
|
+
delete mod.exports.default;
|
|
435
|
+
} catch (_) {
|
|
436
|
+
}
|
|
437
|
+
return generateCode(mod).code;
|
|
438
|
+
}
|
|
439
|
+
async function extractExports(filepath) {
|
|
440
|
+
var _a;
|
|
441
|
+
try {
|
|
442
|
+
const contents = await removeDefaultExport(filepath);
|
|
443
|
+
const buildOptions = {
|
|
444
|
+
...standardBuildOptions,
|
|
445
|
+
minify: false,
|
|
446
|
+
write: false,
|
|
447
|
+
legalComments: "none"
|
|
448
|
+
};
|
|
449
|
+
buildOptions.stdin = {
|
|
450
|
+
sourcefile: filepath,
|
|
451
|
+
contents,
|
|
452
|
+
loader: filepath.endsWith(".ts") ? "ts" : filepath.endsWith(".tsx") ? "tsx" : filepath.endsWith(".js") ? "js" : filepath.endsWith(".jsx") ? "jsx" : "default",
|
|
453
|
+
resolveDir: dirname(filepath)
|
|
454
|
+
};
|
|
455
|
+
const output = await build(buildOptions);
|
|
456
|
+
const bundle = new TextDecoder().decode((_a = output.outputFiles[0]) == null ? void 0 : _a.contents);
|
|
457
|
+
return vercelEndpointExports.parse(_eval(bundle, filepath, {}, true));
|
|
458
|
+
} catch (e) {
|
|
459
|
+
console.warn(`Warning: failed to read exports of '${filepath}'`, e);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
391
462
|
async function buildEndpoints(resolvedConfig) {
|
|
392
463
|
const entries = getEntries(resolvedConfig);
|
|
393
464
|
for (const entry of entries) {
|
|
465
|
+
if (typeof entry.source === "string") {
|
|
466
|
+
const exports = await extractExports(entry.source);
|
|
467
|
+
if (exports) {
|
|
468
|
+
if (entry.headers || exports.headers) {
|
|
469
|
+
entry.headers = {
|
|
470
|
+
...exports.headers,
|
|
471
|
+
...entry.headers
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
if (entry.edge !== void 0 && exports.edge !== void 0) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
`edge configuration should be defined either in the endpoint itself or through Vite config, not both ('${entry.source}')`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
if (exports.edge !== void 0) {
|
|
480
|
+
entry.edge = exports.edge;
|
|
481
|
+
}
|
|
482
|
+
if (entry.isr !== void 0 && exports.isr !== void 0) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`isr configuration should be defined either in the endpoint itself or through Vite config, not both ('${entry.source}')`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
if (exports.isr) {
|
|
488
|
+
entry.isr = exports.isr;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
394
492
|
await buildFn(resolvedConfig, entry);
|
|
395
493
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
494
|
+
const isrEntries = entries.filter((e) => e.isr).map(
|
|
495
|
+
(e) => [
|
|
496
|
+
e.destination.replace(/\.func$/, ""),
|
|
497
|
+
{ expiration: e.isr.expiration }
|
|
498
|
+
]
|
|
499
|
+
);
|
|
500
|
+
return {
|
|
501
|
+
rewrites: entries.filter((e) => e.addRoute !== false).map((e) => e.destination.replace(/\.func$/, "")).map((destination) => ({
|
|
502
|
+
source: getSourceAndDestination(destination),
|
|
503
|
+
destination: getSourceAndDestination(destination)
|
|
504
|
+
})),
|
|
505
|
+
isr: Object.fromEntries(isrEntries),
|
|
506
|
+
headers: entries.filter((e) => e.headers).map((e) => ({
|
|
507
|
+
source: "/" + e.destination.replace(/\.func$/, ""),
|
|
508
|
+
headers: Object.entries(e.headers).map(([key, value]) => ({
|
|
509
|
+
key,
|
|
510
|
+
value
|
|
511
|
+
}))
|
|
512
|
+
}))
|
|
513
|
+
};
|
|
400
514
|
}
|
|
401
515
|
|
|
402
516
|
// src/prerender.ts
|
|
403
517
|
import path4 from "path";
|
|
404
518
|
|
|
405
519
|
// src/schemas/config/prerender-config.ts
|
|
406
|
-
import { z as
|
|
407
|
-
var vercelOutputPrerenderConfigSchema =
|
|
408
|
-
expiration:
|
|
409
|
-
group:
|
|
410
|
-
bypassToken:
|
|
411
|
-
fallback:
|
|
412
|
-
allowQuery:
|
|
520
|
+
import { z as z4 } from "zod";
|
|
521
|
+
var vercelOutputPrerenderConfigSchema = z4.object({
|
|
522
|
+
expiration: z4.union([z4.number().int().positive(), z4.literal(false)]),
|
|
523
|
+
group: z4.number().int().optional(),
|
|
524
|
+
bypassToken: z4.string().optional(),
|
|
525
|
+
fallback: z4.string().optional(),
|
|
526
|
+
allowQuery: z4.array(z4.string()).optional()
|
|
413
527
|
}).strict();
|
|
414
528
|
|
|
415
529
|
// src/prerender.ts
|
|
@@ -463,8 +577,12 @@ function getPrerenderSymlinkInfo(resolvedConfig, destination, target) {
|
|
|
463
577
|
)
|
|
464
578
|
};
|
|
465
579
|
}
|
|
466
|
-
async function buildPrerenderConfigs(resolvedConfig) {
|
|
467
|
-
const isr =
|
|
580
|
+
async function buildPrerenderConfigs(resolvedConfig, extractedIsr) {
|
|
581
|
+
const isr = Object.assign(
|
|
582
|
+
{},
|
|
583
|
+
extractedIsr,
|
|
584
|
+
await getIsrConfig(resolvedConfig)
|
|
585
|
+
);
|
|
468
586
|
const entries = Object.entries(isr);
|
|
469
587
|
const rewrites = [];
|
|
470
588
|
for (const [destination, { symlink, route, ...isr2 }] of entries) {
|
|
@@ -529,12 +647,17 @@ function vercelPlugin() {
|
|
|
529
647
|
}
|
|
530
648
|
const overrides = await execPrerender(resolvedConfig);
|
|
531
649
|
const userOverrides = await computeStaticHtmlOverrides(resolvedConfig);
|
|
532
|
-
const rewrites = await buildEndpoints(resolvedConfig);
|
|
533
|
-
rewrites.push(...await buildPrerenderConfigs(resolvedConfig));
|
|
534
|
-
await writeConfig(
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
650
|
+
const { rewrites, isr, headers } = await buildEndpoints(resolvedConfig);
|
|
651
|
+
rewrites.push(...await buildPrerenderConfigs(resolvedConfig, isr));
|
|
652
|
+
await writeConfig(
|
|
653
|
+
resolvedConfig,
|
|
654
|
+
rewrites,
|
|
655
|
+
{
|
|
656
|
+
...userOverrides,
|
|
657
|
+
...overrides
|
|
658
|
+
},
|
|
659
|
+
headers
|
|
660
|
+
);
|
|
538
661
|
}
|
|
539
662
|
};
|
|
540
663
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-vercel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"vike": "*",
|
|
24
24
|
"vite": "^4.2.0",
|
|
25
|
-
"@vite-plugin-vercel/vike": "0.
|
|
25
|
+
"@vite-plugin-vercel/vike": "2.0.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependenciesMeta": {
|
|
28
28
|
"@vite-plugin-vercel/vike": {
|
|
@@ -41,13 +41,16 @@
|
|
|
41
41
|
"typescript": "^5.2.2",
|
|
42
42
|
"vike": "^0.4.143",
|
|
43
43
|
"vite": "^4.4.11",
|
|
44
|
-
"@vite-plugin-vercel/vike": "0.
|
|
44
|
+
"@vite-plugin-vercel/vike": "2.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@brillout/libassert": "^0.5.8",
|
|
48
|
+
"@vercel/build-utils": "^7.2.2",
|
|
48
49
|
"@vercel/routing-utils": "^3.0.0",
|
|
49
50
|
"esbuild": "^0.19.4",
|
|
51
|
+
"eval": "^0.1.8",
|
|
50
52
|
"fast-glob": "^3.3.1",
|
|
53
|
+
"magicast": "^0.3.0",
|
|
51
54
|
"zod": "^3.22.4"
|
|
52
55
|
},
|
|
53
56
|
"scripts": {
|