vite-plugin-vercel 11.0.0-beta.2 → 11.0.0-beta.21

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 CHANGED
@@ -1,15 +1,12 @@
1
1
  # vite-plugin-vercel
2
2
 
3
3
  > [!NOTE]
4
- > You are on the [Vite Environment API](https://vite.dev/guide/api-environment.html#environment-configuration) beta branch (v10). Check out [v9 branch](https://github.com/magne4000/vite-plugin-vercel/tree/v9) for current stable version.
4
+ > You are on the [Vite Environment API](https://vite.dev/guide/api-environment.html#environment-configuration) beta branch (v11). Check out [v9 branch](https://github.com/magne4000/vite-plugin-vercel/tree/v9) for current stable version.
5
5
 
6
6
  Vercel adapter for [Vite](https://vitejs.dev/).
7
7
 
8
8
  Bundle your Vite application as supported by [Vercel Output API (v3)](https://vercel.com/docs/build-output-api/v3).
9
9
 
10
- > [!NOTE]
11
- > This plugin is mostly a re-export of [`@photonjs/vercel`](https://github.com/photon-js/photon/tree/main/packages/adapter-vercel)
12
-
13
10
  ## Install
14
11
 
15
12
  ```bash
@@ -68,7 +65,7 @@ export default defineConfig({
68
65
  ```
69
66
 
70
67
  > [!NOTE]
71
- > `@vercel/build` currently forces the building of files in the _/api_ folder, with no way to disable this behavior.
68
+ > `@vercel/build` forces the building of files in the _/api_ folder, with no way to disable this behavior.
72
69
  > It's recommended to place your files in a different folder.
73
70
 
74
71
  ### Configure endpoints
@@ -165,7 +162,7 @@ export default defineConfig({
165
162
  trailingSlash: true,
166
163
  /**
167
164
  * Use `getVercelEntries` for mapping your filesystem routes to entries.
168
- * If you are interfacing this plugin with a framework, entries can also be added through the Photon API
165
+ * If you are interfacing this plugin with a framework, entries can also be added through the {@link https://github.com/photon-js/universal-deploy | universal-deploy} API
169
166
  */
170
167
  entries: {
171
168
  root: {
@@ -209,7 +206,7 @@ Related documentation: https://vercel.com/docs/edge-network/headers/request-head
209
206
 
210
207
  ## Migrations
211
208
 
212
- - [Migration from v9 to v10](https://github.com/magne4000/vite-plugin-vercel/blob/main/MIGRATION.md)
209
+ - [Migration from v9 to v11](https://github.com/magne4000/vite-plugin-vercel/blob/main/MIGRATION.md)
213
210
 
214
211
  ## Demo
215
212
 
package/dist/api.js CHANGED
@@ -1,3 +1,65 @@
1
- import { n as getVercelAPI, t as createAPI } from "./api-DR2y7JVQ.js";
1
+ import { t as assert } from "./assert-vtiLgQIb.js";
2
2
 
3
+ //#region src/api.ts
4
+ function createAPI(outfiles, pluginConfig) {
5
+ return {
6
+ getOutFiles() {
7
+ return outfiles;
8
+ },
9
+ get config() {
10
+ pluginConfig.config ??= {};
11
+ return pluginConfig.config;
12
+ },
13
+ get defaultMaxDuration() {
14
+ return pluginConfig.defaultMaxDuration;
15
+ },
16
+ set defaultMaxDuration(value) {
17
+ pluginConfig.defaultMaxDuration = value;
18
+ },
19
+ get expiration() {
20
+ return pluginConfig.expiration;
21
+ },
22
+ set expiration(value) {
23
+ pluginConfig.expiration = value;
24
+ },
25
+ get rewrites() {
26
+ pluginConfig.rewrites ??= [];
27
+ return pluginConfig.rewrites;
28
+ },
29
+ get headers() {
30
+ pluginConfig.headers ??= [];
31
+ return pluginConfig.headers;
32
+ },
33
+ get redirects() {
34
+ pluginConfig.redirects ??= [];
35
+ return pluginConfig.redirects;
36
+ },
37
+ get cleanUrls() {
38
+ return pluginConfig.cleanUrls;
39
+ },
40
+ set cleanUrls(value) {
41
+ pluginConfig.cleanUrls = value;
42
+ },
43
+ get trailingSlash() {
44
+ return pluginConfig.trailingSlash;
45
+ },
46
+ set trailingSlash(value) {
47
+ pluginConfig.trailingSlash = value;
48
+ },
49
+ get defaultSupportsResponseStreaming() {
50
+ return pluginConfig.defaultSupportsResponseStreaming;
51
+ },
52
+ set defaultSupportsResponseStreaming(value) {
53
+ pluginConfig.defaultSupportsResponseStreaming = value;
54
+ }
55
+ };
56
+ }
57
+ function getVercelAPI(pluginContextOrServer) {
58
+ const vpv = ("environment" in pluginContextOrServer ? pluginContextOrServer.environment.config : pluginContextOrServer.config).plugins.find((p) => p.name === "vite-plugin-vercel:api");
59
+ assert(vpv, "Could not find vite-plugin-vercel:api plugin");
60
+ assert(vpv.api, "Missing `api`. Make sure vite-plugin-vercel is up-to-date");
61
+ return vpv.api("environment" in pluginContextOrServer ? pluginContextOrServer : void 0);
62
+ }
63
+
64
+ //#endregion
3
65
  export { createAPI, getVercelAPI };
@@ -0,0 +1,8 @@
1
+ //#region src/utils/assert.ts
2
+ function assert(condition, errorMessage) {
3
+ if (condition) return;
4
+ throw new Error(`[vite-plugin-vercel] ${errorMessage}`);
5
+ }
6
+
7
+ //#endregion
8
+ export { assert as t };
package/dist/index.d.ts CHANGED
@@ -1,18 +1,31 @@
1
1
  import { EntryMeta } from "@universal-deploy/store";
2
2
 
3
3
  //#region src/index.d.ts
4
-
4
+ interface GetVercelEntriesOptions {
5
+ /**
6
+ * Map entries to URL patterns
7
+ * @example
8
+ * // When dir: "endpoints/myapi" and destination: "api"
9
+ * // endpoints/myapi/page.ts -> /api/page
10
+ * // endpoints/myapi/name/[name].ts -> /api/name/*
11
+ */
12
+ destination?: string;
13
+ /**
14
+ * If true, parse entries exports for per-file settings.
15
+ * Entries can export `edge`, `isr`, `headers` and `streaming`. See README for more details
16
+ *
17
+ * @default true
18
+ */
19
+ tryParseExports?: boolean;
20
+ }
5
21
  /**
6
22
  * Scans the filesystem for entry points.
7
- * @experimental
23
+ * @beta
8
24
  */
9
25
  declare function getVercelEntries(dir: string, {
10
26
  destination,
11
27
  tryParseExports
12
- }: {
13
- destination?: string | undefined;
14
- tryParseExports?: boolean | undefined;
15
- }): Promise<EntryMeta[]>;
28
+ }: GetVercelEntriesOptions): Promise<EntryMeta[]>;
16
29
  declare function extractExports(filepath: string): Promise<{
17
30
  edge?: boolean | undefined;
18
31
  headers?: Record<string, string> | undefined;
@@ -22,4 +35,4 @@ declare function extractExports(filepath: string): Promise<{
22
35
  } | undefined;
23
36
  } | null>;
24
37
  //#endregion
25
- export { extractExports, getVercelEntries };
38
+ export { GetVercelEntriesOptions, extractExports, getVercelEntries };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as pathRelativeTo } from "./path-B4ThGm96.js";
1
+ import { t as pathRelativeTo } from "./path-DoLvGKnz.js";
2
2
  import path from "node:path";
3
3
  import { vercelEndpointExports } from "@vite-plugin-vercel/schemas";
4
4
  import { fromNextFs } from "convert-route/next-fs";
@@ -10,7 +10,7 @@ import { normalizePath } from "vite";
10
10
  //#region src/index.ts
11
11
  /**
12
12
  * Scans the filesystem for entry points.
13
- * @experimental
13
+ * @beta
14
14
  */
15
15
  async function getVercelEntries(dir, { destination = dir, tryParseExports = true }) {
16
16
  const normalizedDir = normalizePath(dir);
@@ -31,7 +31,7 @@ async function getVercelEntries(dir, { destination = dir, tryParseExports = true
31
31
  if (xports?.isr) entry.vercel.isr = xports.isr;
32
32
  if (xports?.headers) entry.vercel.headers = xports.headers;
33
33
  if (xports?.streaming) entry.vercel.streaming = xports.streaming;
34
- entry.pattern = entryToRou3(key);
34
+ entry.route = entryToRou3(key);
35
35
  if (key.includes("[...")) entry.vercel.enforce = "post";
36
36
  entryPoints.push(entry);
37
37
  }
package/dist/types.d.ts CHANGED
@@ -12,6 +12,20 @@ type ViteVercelRedirect = Redirect & {
12
12
  };
13
13
  type PluginContext = ThisParameterType<Extract<Plugin["resolveId"], (...args: never) => any>>;
14
14
  interface ViteVercelConfig {
15
+ /**
16
+ * @experimental
17
+ * @default basic
18
+ */
19
+ bundleStrategy?: "basic" | "nf3";
20
+ /**
21
+ * Override vite build environments
22
+ * @experimental
23
+ */
24
+ viteEnvNames?: {
25
+ client?: string;
26
+ edge?: string | false;
27
+ node?: string;
28
+ };
15
29
  /**
16
30
  * How long Functions should be allowed to run for every request, in seconds.
17
31
  * If left empty, default value for your plan will be used.
package/dist/vite.js CHANGED
@@ -1,22 +1,36 @@
1
- import { t as pathRelativeTo$1 } from "./path-B4ThGm96.js";
2
- import { r as assert, t as createAPI } from "./api-DR2y7JVQ.js";
1
+ import { t as pathRelativeTo$1 } from "./path-DoLvGKnz.js";
2
+ import { t as assert } from "./assert-vtiLgQIb.js";
3
+ import { createAPI, getVercelAPI } from "./api.js";
4
+ import { builtinModules } from "node:module";
3
5
  import path from "node:path";
4
6
  import { vercelOutputConfigSchema, vercelOutputPrerenderConfigSchema, vercelOutputVcConfigSchema } from "@vite-plugin-vercel/schemas";
5
7
  import { fromRou3 } from "convert-route/rou3";
6
8
  import { BuildEnvironment, createRunnableDevEnvironment, mergeConfig, normalizePath } from "vite";
7
9
  import { catchAll, devServer } from "@universal-deploy/store/vite";
8
- import { store } from "@universal-deploy/store";
9
- import fs from "node:fs";
10
+ import { addEntry, getAllEntries } from "@universal-deploy/store";
11
+ import fs, { existsSync, readFileSync, writeFileSync } from "node:fs";
12
+ import { copyFile, cp, rmdir, unlink } from "node:fs/promises";
13
+ import { findRoot } from "@manypkg/find-root";
14
+ import { nodeFileTrace, resolve } from "@vercel/nft";
15
+ import { transform } from "oxc-transform";
16
+ import { build } from "rolldown";
10
17
  import { cpus } from "node:os";
11
- import { resolve } from "@vercel/nft";
12
18
  import { externals } from "nf3/plugin";
13
19
  import pLimit from "p-limit";
14
- import { build } from "rolldown";
15
20
  import { getNodeVersion } from "@vercel/build-utils";
16
21
  import { toPathToRegexpV6 } from "convert-route/path-to-regexp-v6";
17
- import { cp } from "node:fs/promises";
18
22
  import { getTransformedRoutes, mergeRoutes, normalizeRoutes } from "@vercel/routing-utils";
19
23
 
24
+ //#region src/utils/buildEnvs.ts
25
+ function getBuildEnvNames(pluginConfig) {
26
+ return {
27
+ client: pluginConfig.viteEnvNames?.client ?? "vercel_client",
28
+ edge: pluginConfig.viteEnvNames?.edge ?? "vercel_edge",
29
+ node: pluginConfig.viteEnvNames?.node ?? "vercel_node"
30
+ };
31
+ }
32
+
33
+ //#endregion
20
34
  //#region src/utils/dedupeRoutes.ts
21
35
  /**
22
36
  * When multiple entries point to the same module, we can deploy them as a single function.
@@ -24,20 +38,65 @@ import { getTransformedRoutes, mergeRoutes, normalizeRoutes } from "@vercel/rout
24
38
  */
25
39
  function dedupeRoutes() {
26
40
  const entriesToKeep = [];
27
- const entriesGroupedByModuleId = groupBy(store.entries, (e) => e.id);
41
+ const entriesGroupedByModuleId = groupBy(getAllEntries(), (e) => e.id);
28
42
  for (const entries of entriesGroupedByModuleId.values()) {
29
43
  let groupedEntry;
30
44
  for (const entry of entries) if (entry.vercel && Object.keys(entry.vercel).length > 0) {
31
- if (!Array.isArray(entry.pattern)) entry.pattern = [entry.pattern];
45
+ if (!Array.isArray(entry.route)) entry.route = [entry.route];
32
46
  entriesToKeep.push(entry);
33
47
  } else if (!groupedEntry) {
34
48
  groupedEntry = structuredClone(entry);
35
- if (!Array.isArray(groupedEntry.pattern)) groupedEntry.pattern = [groupedEntry.pattern];
49
+ if (!Array.isArray(groupedEntry.route)) groupedEntry.route = [groupedEntry.route];
36
50
  entriesToKeep.push(groupedEntry);
37
- } else groupedEntry.pattern.push(...[entry.pattern].flat());
51
+ } else groupedEntry.route.push(...[entry.route].flat());
38
52
  }
39
53
  return entriesToKeep;
40
54
  }
55
+ /**
56
+ * Sorts routes by specificity.
57
+ *
58
+ * Specificity rules:
59
+ * 1. Segment type priority at each position: Static > Dynamic/Param > Catch-all.
60
+ * 2. Total route length: Longer routes are generally more specific.
61
+ * 3. Prefix match exception: A shorter static route is more specific than a longer route
62
+ * that only adds a catch-all segment to the same prefix.
63
+ * 4. Alphabetical order: Final tie-breaker for static segments at the same position.
64
+ *
65
+ * @param routes - Array of routes to sort.
66
+ * @returns A new array of routes sorted from most specific to least specific.
67
+ */
68
+ function sortRoutes(routes) {
69
+ return [...routes].sort((a, b) => {
70
+ const lenA = a.pathname.length;
71
+ const lenB = b.pathname.length;
72
+ const commonLen = Math.min(lenA, lenB);
73
+ for (let i = 0; i < commonLen; i++) {
74
+ const segA = a.pathname[i];
75
+ const segB = b.pathname[i];
76
+ if (segA.value && !segB.value) return -1;
77
+ if (!segA.value && segB.value) return 1;
78
+ if (segA.value && segB.value) {
79
+ if (segA.value !== segB.value) {
80
+ if (lenA !== lenB) return lenB - lenA;
81
+ return segA.value.localeCompare(segB.value);
82
+ }
83
+ }
84
+ if (!segA.optional && segB.optional) return -1;
85
+ if (segA.optional && !segB.optional) return 1;
86
+ if (segA.catchAll && segB.catchAll) {
87
+ if (!segA.catchAll.greedy && segB.catchAll.greedy) return -1;
88
+ if (segA.catchAll.greedy && !segB.catchAll.greedy) return 1;
89
+ }
90
+ if (segA.catchAll && !segB.catchAll) return 1;
91
+ if (!segA.catchAll && segB.catchAll) return -1;
92
+ }
93
+ if (lenA !== lenB) {
94
+ if (lenA > lenB) return a.pathname[lenB].catchAll ? 1 : -1;
95
+ return b.pathname[lenA].catchAll ? -1 : 1;
96
+ }
97
+ return 0;
98
+ });
99
+ }
41
100
  function groupBy(list, fn, selector) {
42
101
  return Array.from(list).reduce((acc, curr) => {
43
102
  const key = fn(curr);
@@ -56,8 +115,36 @@ function removeExtension$1(subject) {
56
115
 
57
116
  //#endregion
58
117
  //#region src/utils/destination.ts
118
+ function parseViteId(id) {
119
+ const [path, query] = id.split("?");
120
+ return {
121
+ path: decodeURIComponent(path),
122
+ query
123
+ };
124
+ }
125
+ function extractBestPath({ path, query }) {
126
+ if (!query) return path;
127
+ return query.split("&").map(decodeURIComponent).find((p) => p.includes("/")) || path;
128
+ }
129
+ function shortenPath(path, maxSegments = 2) {
130
+ return removeExtension$1(path.split(/[\\/]/).filter(Boolean).slice(-maxSegments).join("_"));
131
+ }
132
+ function mapPath(path, maxSegments = 2) {
133
+ const nodeModuleMatch = path.match(/node_modules[\\/](.+?)([\\/].*)?$/);
134
+ if (nodeModuleMatch) return `${nodeModuleMatch[1].split(/[\\/]/)[0]}_${removeExtension$1(nodeModuleMatch[2]?.split(/[\\/]/).pop() || "index")}`;
135
+ return shortenPath(path, maxSegments);
136
+ }
137
+ function hashString(str, length = 6) {
138
+ let hash = 5381;
139
+ for (let i = 0; i < str.length; i++) hash = hash * 33 ^ str.charCodeAt(i);
140
+ hash = hash >>> 0;
141
+ return hash.toString(36).slice(0, length);
142
+ }
143
+ function uniqueViteName(id, entry, maxSegments = 2) {
144
+ return removeExtension$1(`${mapPath(extractBestPath(parseViteId(id)), maxSegments)}_${hashString(JSON.stringify(entry))}`.replace(/[^a-zA-Z0-9\-_[\]/]/g, "-"));
145
+ }
59
146
  function entryDestinationDefault(root, entry) {
60
- return `${removeExtension$1(pathRelativeTo$1(entry.id, root)).replace(/[^a-zA-Z0-9\-_[\]/]/g, "-")}`;
147
+ return uniqueViteName(pathRelativeTo$1(entry.id, root), entry);
61
148
  }
62
149
  function entryDestination(root, entry, postfix) {
63
150
  return `${path.posix.join("functions/", entryDestinationDefault(root, entry))}${postfix}`;
@@ -66,6 +153,7 @@ function entryDestination(root, entry, postfix) {
66
153
  //#endregion
67
154
  //#region src/plugins/api.ts
68
155
  function apiPlugin(pluginConfig) {
156
+ const envNames = getBuildEnvNames(pluginConfig);
69
157
  const outfiles = [];
70
158
  return {
71
159
  name: "vite-plugin-vercel:api",
@@ -73,12 +161,12 @@ function apiPlugin(pluginConfig) {
73
161
  return createAPI(outfiles, pluginConfig);
74
162
  },
75
163
  applyToEnvironment({ name }) {
76
- return name === "vercel_edge" || name === "vercel_node";
164
+ return name === envNames.edge || name === envNames.node;
77
165
  },
78
- writeBundle(_opts, bundle$1) {
166
+ writeBundle(_opts, bundle) {
79
167
  const root = this.environment.config.root ?? process.cwd();
80
168
  const entryMapByDestination = new Map(dedupeRoutes().map((e) => [entryDestination(root, e, ".func/index"), e]));
81
- for (const [key, value] of Object.entries(bundle$1)) if (value.type === "chunk" && entryMapByDestination.has(removeExtension$1(key))) outfiles.push({
169
+ for (const [key, value] of Object.entries(bundle)) if (value.type === "chunk" && entryMapByDestination.has(removeExtension$1(key))) outfiles.push({
82
170
  type: "chunk",
83
171
  root: this.environment.config.root,
84
172
  outdir: this.environment.config.build.outDir,
@@ -96,6 +184,17 @@ function apiPlugin(pluginConfig) {
96
184
  };
97
185
  }
98
186
 
187
+ //#endregion
188
+ //#region src/utils/edge.ts
189
+ const edgeConditions = [
190
+ "edge-light",
191
+ "worker",
192
+ "browser",
193
+ "module",
194
+ "import",
195
+ "default"
196
+ ];
197
+
99
198
  //#endregion
100
199
  //#region src/utils/external.ts
101
200
  const _external = [
@@ -108,8 +207,193 @@ const _external = [
108
207
  const edgeExternal = [..._external, ..._external.map((e) => `node:${e}`)];
109
208
 
110
209
  //#endregion
111
- //#region src/plugins/bundle.ts
112
- function bundlePlugin() {
210
+ //#region src/plugins/bundle/basic.ts
211
+ const builtIns = new Set(builtinModules.flatMap((m) => [m, `node:${m}`]));
212
+ const edgeWasmPlugin = {
213
+ name: "edge-wasm-vercel",
214
+ resolveId: {
215
+ filter: { id: [/\.wasm\?module$/] },
216
+ handler(id) {
217
+ return {
218
+ id: id.replace(/\.wasm\?module$/, ".wasm"),
219
+ external: true
220
+ };
221
+ }
222
+ }
223
+ };
224
+ const dynamicNativeImportPlugin = {
225
+ name: "edge-dynamic-import-native",
226
+ resolveDynamicImport(specifier) {
227
+ if (typeof specifier === "string" && builtIns.has(specifier)) return {
228
+ id: specifier,
229
+ external: true
230
+ };
231
+ }
232
+ };
233
+ const reactEdgePlugin$1 = {
234
+ name: "react-edge-plugin",
235
+ resolveId: {
236
+ filter: { id: [/react-dom\/server/] },
237
+ async handler(_id, importer, options) {
238
+ return this.resolve("react-dom/server.edge", importer, options);
239
+ }
240
+ }
241
+ };
242
+ function basicBundlePlugin(pluginConfig) {
243
+ const envNames = getBuildEnvNames(pluginConfig);
244
+ const bundledAssets = /* @__PURE__ */ new Map();
245
+ const bundledChunks = [];
246
+ return [{
247
+ name: "vite-plugin-vercel:bundle",
248
+ enforce: "post",
249
+ apply: "build",
250
+ generateBundle(_opts, bundle) {
251
+ for (const b of Object.values(bundle)) {
252
+ const outFile = joinAbsolute(this.environment, this.environment.config.build.outDir, b.fileName);
253
+ if (b.type === "asset") {
254
+ const originalFileNames = b.originalFileNames.map((relativePath) => path.resolve(this.environment.config.root, relativePath));
255
+ const asset = {
256
+ env: this.environment.name,
257
+ root: this.environment.config.root,
258
+ outDir: this.environment.config.build.outDir,
259
+ outFile,
260
+ fileName: b.fileName
261
+ };
262
+ for (const originalFileName of originalFileNames) bundledAssets.set(originalFileName, asset);
263
+ } else if (this.environment.name === envNames.edge || this.environment.name === envNames.node) bundledChunks.push(outFile);
264
+ }
265
+ },
266
+ closeBundle: {
267
+ order: "post",
268
+ async handler() {
269
+ if (!isVercelLastBuildStep(this.environment, pluginConfig)) return;
270
+ this.environment.logger.info("Creating Vercel bundles...");
271
+ const outfiles = getVercelAPI(this).getOutFiles();
272
+ const filesToKeepP = [];
273
+ for (const outfile of outfiles) if (outfile.type === "chunk") filesToKeepP.push(bundle$1(this, bundledAssets, outfile));
274
+ await cleanup$1((await Promise.all(filesToKeepP)).flat(), bundledChunks);
275
+ }
276
+ },
277
+ sharedDuringBuild: true
278
+ }];
279
+ }
280
+ function getAbsoluteOutFile(outfile) {
281
+ const source = joinAbsolutePosix(outfile.root, outfile.outdir, outfile.filepath);
282
+ return {
283
+ source,
284
+ destination: source.replace(outfile.outdir, outfile.outdir)
285
+ };
286
+ }
287
+ async function bundle$1(pluginContext, bundledAssets, outfile) {
288
+ const output = [];
289
+ const { source, destination } = getAbsoluteOutFile(outfile);
290
+ const isEdge = Boolean(outfile.relatedEntry.vercel?.edge);
291
+ const { environment } = pluginContext;
292
+ const buildOptions = {};
293
+ buildOptions.output = {
294
+ format: "esm",
295
+ legalComments: "none",
296
+ codeSplitting: false
297
+ };
298
+ buildOptions.checks = { pluginTimings: false };
299
+ buildOptions.input = [source];
300
+ buildOptions.treeshake = true;
301
+ buildOptions.resolve ??= {};
302
+ if (isEdge) {
303
+ buildOptions.platform = "browser";
304
+ buildOptions.external = edgeExternal;
305
+ buildOptions.resolve.conditionNames = edgeConditions;
306
+ buildOptions.transform = { define: { "process.env.NODE_ENV": JSON.stringify("production") } };
307
+ buildOptions.output.file = destination.replace(/\.mjs$/, ".js");
308
+ buildOptions.plugins = [
309
+ edgeWasmPlugin,
310
+ dynamicNativeImportPlugin,
311
+ reactEdgePlugin$1
312
+ ];
313
+ } else {
314
+ buildOptions.platform = "node";
315
+ buildOptions.output.file = destination.replace(/\.js$/, ".mjs");
316
+ }
317
+ try {
318
+ await build(buildOptions);
319
+ output.push(buildOptions.output.file);
320
+ } catch (e) {
321
+ throw new Error(`Error while bundling ${destination}`, { cause: e });
322
+ }
323
+ let base = environment.config.root;
324
+ try {
325
+ base = (await findRoot(environment.config.root)).rootDir;
326
+ } catch (_e) {}
327
+ const resolvedEntryP = pluginContext.resolve(outfile.relatedEntry.id);
328
+ const entryFilePath = existsSync(outfile.relatedEntry.id) ? outfile.relatedEntry.id : (await resolvedEntryP)?.id && existsSync((await resolvedEntryP).id) ? (await resolvedEntryP).id : null;
329
+ if (entryFilePath === null) return [];
330
+ const { fileList, reasons } = await nodeFileTrace([entryFilePath], {
331
+ base,
332
+ processCwd: environment.config.root,
333
+ mixedModules: true,
334
+ ignore: [
335
+ "**/node_modules/react{,-dom,-dom-server-turbopack}/**/*.development.js",
336
+ "**/*.d.ts",
337
+ "**/*.map",
338
+ "**/node_modules/webpack5/**/*"
339
+ ],
340
+ async readFile(filepath) {
341
+ const code = readFileSync(filepath, "utf-8");
342
+ if (filepath.endsWith(".ts") || filepath.endsWith(".tsx")) return (await transform(filepath, code, { target: "es2022" })).code;
343
+ return code;
344
+ }
345
+ });
346
+ for (const file of fileList) if (reasons.has(file) && reasons.get(file)?.type.includes("asset") && !file.endsWith(".js") && !file.endsWith(".cjs") && !file.endsWith(".mjs") && !file.endsWith("package.json")) {
347
+ const absolutePath = path.join(base, file);
348
+ const assetRenamedByVite = bundledAssets.get(absolutePath);
349
+ const basename = path.basename(assetRenamedByVite ? assetRenamedByVite.fileName : absolutePath);
350
+ if (assetRenamedByVite) writeFileSync(destination, readFileSync(destination, "utf-8").replaceAll(`/${assetRenamedByVite.fileName}`, `./${path.basename(assetRenamedByVite.fileName)}`));
351
+ const to = path.join(path.dirname(destination), basename);
352
+ output.push(to);
353
+ await copyFile(absolutePath, to);
354
+ }
355
+ return output;
356
+ }
357
+ function joinAbsolute(env_or_p0, p1, ...p) {
358
+ if (path.isAbsolute(p1)) return path.join(p1, ...p);
359
+ return path.join(typeof env_or_p0 === "string" ? env_or_p0 : env_or_p0.config.root, p1, ...p);
360
+ }
361
+ function joinAbsolutePosix(env_or_p0, p1, ...p) {
362
+ if (path.isAbsolute(p1)) return path.posix.join(p1, ...p);
363
+ return path.posix.join(typeof env_or_p0 === "string" ? env_or_p0 : env_or_p0.config.root, p1, ...p);
364
+ }
365
+ function isVercelLastBuildStep(env, pluginConfig) {
366
+ const envNames = getBuildEnvNames(pluginConfig);
367
+ return (typeof env !== "string" ? env.name : env) === envNames.node;
368
+ }
369
+ async function cleanup$1(filesToKeep, bundledChunks) {
370
+ const toKeep = new Set(filesToKeep);
371
+ const removedFiles = [];
372
+ await Promise.all(bundledChunks.map(async (file) => {
373
+ if (!toKeep.has(file)) try {
374
+ await unlink(file);
375
+ removedFiles.push(file);
376
+ } catch {}
377
+ }));
378
+ const dirsToRemove = /* @__PURE__ */ new Set();
379
+ for (const file of removedFiles) {
380
+ let dir = path.dirname(file);
381
+ while (dir && dir !== "." && dir !== "/" && !toKeep.has(dir)) {
382
+ dirsToRemove.add(dir);
383
+ dir = path.dirname(dir);
384
+ }
385
+ }
386
+ const sortedDirs = Array.from(dirsToRemove).sort((a, b) => b.length - a.length);
387
+ for (const dir of sortedDirs) try {
388
+ await rmdir(dir);
389
+ } catch {}
390
+ }
391
+
392
+ //#endregion
393
+ //#region src/plugins/bundle/nf3.ts
394
+ function nf3BundlePlugin(pluginConfig) {
395
+ console.warn("[vite-plugin-vercel] bundleStrategy 'nf3' is highly experimental. Use at your own risk; support is not provided for related issues.");
396
+ const envNames = getBuildEnvNames(pluginConfig);
113
397
  const externalsPlugin = externals({});
114
398
  delete externalsPlugin.buildEnd;
115
399
  let buildOutput;
@@ -125,24 +409,31 @@ function bundlePlugin() {
125
409
  return env.config.consumer !== "client";
126
410
  },
127
411
  async writeBundle(_, output) {
128
- const isEdge = this.environment.name === "vercel_edge";
412
+ const isEdge = this.environment.name === envNames.edge;
129
413
  const config = this.environment.config;
130
- const outDir$1 = normalizePath(path.isAbsolute(config.build.outDir) ? config.build.outDir : path.join(config.root, config.build.outDir));
414
+ const outDir = normalizePath(path.isAbsolute(config.build.outDir) ? config.build.outDir : path.join(config.root, config.build.outDir));
131
415
  const entries = Object.entries(output).filter((e) => "isEntry" in e[1] && e[1].isEntry).map((e) => ({
132
416
  name: e[1].name,
133
417
  fileName: e[1].fileName,
134
- outPath: path.join(outDir$1, e[1].fileName)
418
+ outPath: path.join(outDir, e[1].fileName)
135
419
  }));
136
- assert(entries.length > 0, "No entry files found in build output");
420
+ if (entries.length === 0) return;
137
421
  const outPaths = entries.map((entry) => entry.outPath);
138
- const input = Object.fromEntries(outPaths.map((e) => [removeExtension(pathRelativeTo(e, outDir$1)), e]));
422
+ const input = Object.fromEntries(outPaths.map((e) => [removeExtension(pathRelativeTo(e, outDir)), e]));
139
423
  const limit = pLimit(Math.max(1, Math.ceil(cpus().length / 2)));
424
+ const nonVitePlugins = this.environment.config.plugins.filter((p) => {
425
+ return !p.name.startsWith("vite:") && p.name !== "alias" && p.name !== "commonjs" && p.name !== "nitro:externals";
426
+ }).map((x) => {
427
+ const { buildStart, buildEnd, writeBundle, generateBundle, ...rest } = x;
428
+ return rest;
429
+ });
140
430
  const localOutput = (await Promise.all(Object.values(input).map((entryPath) => limit(async () => {
141
- const outDir$2 = path.dirname(entryPath);
431
+ const outDir = path.dirname(entryPath);
142
432
  return { output: (await bundle({
433
+ plugins: nonVitePlugins,
143
434
  isEdge,
144
435
  input: { index: entryPath },
145
- outDir: outDir$2,
436
+ outDir,
146
437
  externals: {
147
438
  conditions: this.environment.config.resolve.conditions,
148
439
  rootDir: this.environment.config.root,
@@ -155,7 +446,7 @@ function bundlePlugin() {
155
446
  }
156
447
  })).output.map((o) => ({
157
448
  ...o,
158
- fileName: path.join(outDir$2, o.fileName)
449
+ fileName: path.join(outDir, o.fileName)
159
450
  })) };
160
451
  })))).flatMap((r) => r.output);
161
452
  buildOutput = buildOutput ? [...buildOutput, ...localOutput] : localOutput;
@@ -169,7 +460,7 @@ function bundle(options) {
169
460
  platform: options.isEdge ? "browser" : "node",
170
461
  external: options.isEdge ? edgeExternal : [],
171
462
  write: true,
172
- plugins: [externals(options.externals)],
463
+ plugins: [...options.plugins, externals(options.externals)],
173
464
  input: options.input,
174
465
  resolve: { conditionNames: options.externals.conditions },
175
466
  output: {
@@ -208,12 +499,13 @@ function removeExtension(subject) {
208
499
  //#region src/plugins/clean-outdir.ts
209
500
  function vercelCleanupPlugin(pluginConfig) {
210
501
  let alreadyRun = false;
502
+ const envNames = getBuildEnvNames(pluginConfig);
211
503
  return {
212
504
  apply: "build",
213
505
  name: "vite-plugin-vercel:cleanup",
214
506
  enforce: "pre",
215
507
  applyToEnvironment(env) {
216
- return env.name === "vercel_client";
508
+ return env.name === envNames.client;
217
509
  },
218
510
  buildStart: {
219
511
  order: "pre",
@@ -251,10 +543,34 @@ function getVcConfig(pluginConfig, filename, options) {
251
543
  });
252
544
  }
253
545
 
546
+ //#endregion
547
+ //#region src/utils/request.ts
548
+ function getOriginalRequest(request) {
549
+ const xOriginalPath = request.headers.get("x-original-path");
550
+ let newUrl = null;
551
+ let newRequest = request;
552
+ if (typeof xOriginalPath === "string") newUrl = new URL(xOriginalPath, request.url).toString();
553
+ if (newUrl && request.url !== newUrl) newRequest = new Request(newUrl, {
554
+ method: request.method,
555
+ headers: request.headers,
556
+ body: request.body,
557
+ mode: request.mode,
558
+ credentials: request.credentials,
559
+ cache: request.cache,
560
+ redirect: request.redirect,
561
+ referrer: request.referrer,
562
+ integrity: request.integrity
563
+ });
564
+ return newRequest;
565
+ }
566
+
254
567
  //#endregion
255
568
  //#region src/plugins/loader.ts
256
- const re_DUMMY = /* @__PURE__ */ new RegExp(`__DUMMY__$`);
569
+ const re_DUMMY = new RegExp(`__DUMMY__$`);
570
+ const re_edge = /[?&]vercel_edge\b/;
571
+ const re_node = /[?&]vercel_node\b/;
257
572
  function loaderPlugin(pluginConfig) {
573
+ const envNames = getBuildEnvNames(pluginConfig);
258
574
  let root;
259
575
  return [
260
576
  {
@@ -277,19 +593,57 @@ function loaderPlugin(pluginConfig) {
277
593
  name: "vite-plugin-vercel:load-edge",
278
594
  apply: "build",
279
595
  resolveId: {
280
- filter: { id: [/\?edge$/] },
596
+ filter: { id: re_edge },
281
597
  async handler(id, importer, opts) {
282
- const resolved = await this.resolve(id.replace(/\?edge$/, ""), importer, opts);
598
+ const resolved = await this.resolve(id.replace(re_edge, ""), importer, opts);
283
599
  if (!resolved) return null;
284
- return `${resolved.id}?edge`;
600
+ return `${resolved.id}?vercel_edge`;
285
601
  }
286
602
  },
287
603
  load: {
288
- filter: { id: [/\?edge$/] },
604
+ filter: { id: re_edge },
289
605
  async handler(id) {
290
- const mod = id.replace(/\?edge$/, "");
606
+ const mod = id.replace(re_edge, "");
291
607
  return `import mod from ${JSON.stringify(mod)};
292
- const def = mod.fetch;
608
+
609
+ ${getOriginalRequest.toString()}
610
+
611
+ const fn = (r) => {
612
+ return mod.fetch(getOriginalRequest(r));
613
+ };
614
+
615
+ export default fn`;
616
+ }
617
+ }
618
+ },
619
+ {
620
+ name: "vite-plugin-vercel:load-node",
621
+ apply: "build",
622
+ resolveId: {
623
+ filter: { id: re_node },
624
+ async handler(id, importer, opts) {
625
+ const resolved = await this.resolve(id.replace(re_node, ""), importer, opts);
626
+ if (!resolved) return null;
627
+ return `${resolved.id}?vercel_node`;
628
+ }
629
+ },
630
+ load: {
631
+ filter: { id: re_node },
632
+ async handler(id) {
633
+ const mod = id.replace(re_node, "");
634
+ return `import mod from ${JSON.stringify(mod)};
635
+
636
+ ${getOriginalRequest.toString()}
637
+
638
+ if (mod?.fetch) {
639
+ const ori = mod.fetch;
640
+ mod.fetch = (r) => {
641
+ return ori(getOriginalRequest(r));
642
+ }
643
+ }
644
+
645
+ const def = mod?.server?.nodeHandler ?? mod;
646
+
293
647
  export default def;`;
294
648
  }
295
649
  }
@@ -298,7 +652,7 @@ export default def;`;
298
652
  name: "vite-plugin-vercel:build-functions",
299
653
  apply: "build",
300
654
  applyToEnvironment(env) {
301
- return env.name === "vercel_node" || env.name === "vercel_edge";
655
+ return env.name === envNames.node || env.name === envNames.edge;
302
656
  },
303
657
  config: {
304
658
  order: "post",
@@ -309,28 +663,30 @@ export default def;`;
309
663
  configEnvironment: {
310
664
  order: "post",
311
665
  handler(name) {
312
- const isEdge = name === "vercel_edge";
313
- if (name === "vercel_node" || isEdge) {
666
+ const isEdge = name === envNames.edge;
667
+ if (name === envNames.node || isEdge) {
314
668
  const entries = dedupeRoutes().filter((e) => (e.vercel?.edge ?? false) === isEdge);
315
669
  return { build: { rollupOptions: {
316
- input: Object.fromEntries(entries.map((e) => [entryDestination(root ?? process.cwd(), e, ".func/index"), isEdge ? `${e.id}?edge` : e.id])),
317
- output: { hoistTransitiveImports: false }
670
+ input: Object.fromEntries(entries.map((e) => [entryDestination(root ?? process.cwd(), e, ".func/index"), isEdge ? `${e.id}?vercel_edge` : `${e.id}?vercel_node`])),
671
+ output: {
672
+ hoistTransitiveImports: false,
673
+ entryFileNames: "[name].js"
674
+ }
318
675
  } } };
319
676
  }
320
677
  }
321
678
  },
322
679
  async buildStart() {
323
- const isEdge = this.environment.name === "vercel_edge";
680
+ const isEdge = this.environment.name === envNames.edge;
324
681
  const nodeVersion = await getNodeVersion(process.cwd());
325
682
  const entries = dedupeRoutes();
326
683
  for (const entry of entries.filter((e) => (e.vercel?.edge ?? false) === isEdge)) {
327
- const isEdge$1 = this.environment.name === "vercel_edge";
328
684
  this.emitFile({
329
685
  type: "asset",
330
686
  fileName: entryDestination(root ?? process.cwd(), entry, ".func/.vc-config.json"),
331
- source: JSON.stringify(getVcConfig(pluginConfig, isEdge$1 ? "index.js" : "index.mjs", {
687
+ source: JSON.stringify(getVcConfig(pluginConfig, isEdge ? "index.js" : "index.mjs", {
332
688
  nodeVersion,
333
- edge: isEdge$1,
689
+ edge: isEdge,
334
690
  streaming: entry.vercel?.streaming
335
691
  }), void 0, 2)
336
692
  });
@@ -340,8 +696,8 @@ export default def;`;
340
696
  source: JSON.stringify(vercelOutputPrerenderConfigSchema.parse(entry.vercel.isr), void 0, 2)
341
697
  });
342
698
  pluginConfig.rewrites ??= [];
343
- for (const pattern of [entry.pattern].flat()) {
344
- const source = toPathToRegexpV6(fromRou3(pattern));
699
+ for (const ir of sortRoutes([entry.route].flat().map((p) => fromRou3(p)))) {
700
+ const source = toPathToRegexpV6(ir);
345
701
  pluginConfig.rewrites.push({
346
702
  enforce: entry.vercel?.enforce,
347
703
  source,
@@ -367,11 +723,12 @@ export default def;`;
367
723
 
368
724
  //#endregion
369
725
  //#region src/plugins/react-edge.ts
370
- function reactEdgePlugin() {
726
+ function reactEdgePlugin(pluginConfig) {
727
+ const envNames = getBuildEnvNames(pluginConfig);
371
728
  return {
372
729
  name: "vite-plugin-vercel:react-edge",
373
730
  applyToEnvironment(env) {
374
- return env.name === "vercel_edge";
731
+ return env.name === envNames.edge;
375
732
  },
376
733
  resolveId: {
377
734
  order: "pre",
@@ -397,9 +754,18 @@ function getConfig(pluginConfig) {
397
754
  const { routes, error } = getTransformedRoutes({
398
755
  cleanUrls: pluginConfig.cleanUrls ?? true,
399
756
  trailingSlash: pluginConfig.trailingSlash,
400
- rewrites: reorderEnforce(_rewrites),
757
+ rewrites: reorderEnforce(_rewrites.map((r) => {
758
+ if (r.source === "/:_1*") r.source = "(.*)";
759
+ return r;
760
+ })),
401
761
  redirects: pluginConfig.redirects ? reorderEnforce(pluginConfig.redirects) : void 0,
402
- headers: pluginConfig.headers
762
+ headers: [{
763
+ source: "/(.*)",
764
+ headers: [{
765
+ key: "x-original-path",
766
+ value: "/$1"
767
+ }]
768
+ }, ...pluginConfig.headers ?? []]
403
769
  });
404
770
  if (error) throw error;
405
771
  if (pluginConfig.config?.routes && pluginConfig.config.routes.length > 0 && !pluginConfig.config.routes.every((r) => "continue" in r && r.continue)) console.warn("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 `routes` config to override routes. Prefer using `rewrites` and `redirects`.");
@@ -435,69 +801,64 @@ function getConfig(pluginConfig) {
435
801
  //#region src/utils/const.ts
436
802
  const virtualEntry = "virtual:vite-plugin-vercel:entry";
437
803
 
438
- //#endregion
439
- //#region src/utils/edge.ts
440
- const edgeConditions = [
441
- "edge-light",
442
- "worker",
443
- "browser",
444
- "module",
445
- "import",
446
- "default"
447
- ];
448
-
449
804
  //#endregion
450
805
  //#region src/plugins/setupEnvs.ts
451
806
  const outDir = path.posix.join(process.cwd(), ".vercel/output");
452
807
  const DUMMY = "__DUMMY__";
453
808
  let injected = false;
454
809
  function setupEnvs(pluginConfig) {
810
+ const envNames = getBuildEnvNames(pluginConfig);
455
811
  return [
456
812
  {
457
813
  name: "vite-plugin-vercel:setup-envs",
458
814
  buildApp: {
459
815
  order: "post",
460
816
  async handler(builder) {
461
- try {
462
- await builder.build(builder.environments.vercel_client);
817
+ if (!builder.environments[envNames.client].isBuilt) try {
818
+ await builder.build(builder.environments[envNames.client]);
463
819
  } catch (e) {
464
820
  if (e instanceof Error && e.message.includes(`Could not resolve entry module "index.html"`)) {} else throw e;
465
821
  }
466
- await builder.build(builder.environments.vercel_edge);
467
- await builder.build(builder.environments.vercel_node);
822
+ if (envNames.edge !== false && !builder.environments[envNames.edge].isBuilt) await builder.build(builder.environments[envNames.edge]);
823
+ if (!builder.environments[envNames.node].isBuilt) await builder.build(builder.environments[envNames.node]);
468
824
  }
469
825
  },
470
- config() {
471
- if (!injected) {
472
- injected = true;
473
- if (pluginConfig.entries) store.entries.push(...pluginConfig.entries);
826
+ config: {
827
+ order: "post",
828
+ handler() {
829
+ if (!injected) {
830
+ injected = true;
831
+ if (pluginConfig.entries) pluginConfig.entries.forEach((entry) => {
832
+ addEntry(entry);
833
+ });
834
+ }
835
+ const outDirOverride = pluginConfig.outDir ? { build: { outDir: pluginConfig.outDir } } : {};
836
+ const environments = {};
837
+ if (envNames.client) environments[envNames.client] = {
838
+ build: {
839
+ outDir: path.join(pluginConfig.outDir ?? outDir, "static"),
840
+ copyPublicDir: true,
841
+ rollupOptions: { input: getDummyInput() }
842
+ },
843
+ consumer: "client"
844
+ };
845
+ if (envNames.edge) environments[envNames.edge] = createVercelEnvironmentOptions(outDirOverride);
846
+ if (envNames.node) environments[envNames.node] = createVercelEnvironmentOptions(outDirOverride);
847
+ return {
848
+ environments,
849
+ builder: {}
850
+ };
474
851
  }
475
- const outDirOverride = pluginConfig.outDir ? { build: { outDir: pluginConfig.outDir } } : {};
476
- return {
477
- environments: {
478
- vercel_edge: createVercelEnvironmentOptions(outDirOverride),
479
- vercel_node: createVercelEnvironmentOptions(outDirOverride),
480
- vercel_client: {
481
- build: {
482
- outDir: path.join(pluginConfig.outDir ?? outDir, "static"),
483
- copyPublicDir: true,
484
- rollupOptions: { input: getDummyInput() }
485
- },
486
- consumer: "client"
487
- }
488
- },
489
- builder: {}
490
- };
491
852
  },
492
853
  sharedDuringBuild: true
493
854
  },
494
855
  {
495
856
  name: "vite-plugin-vercel:setup-envs:vercel_edge",
496
857
  applyToEnvironment(env) {
497
- return env.name === "vercel_edge";
858
+ return env.name === envNames.edge;
498
859
  },
499
860
  configEnvironment(name, config, env) {
500
- if (name !== "vercel_edge") return;
861
+ if (name !== envNames.edge) return;
501
862
  return {
502
863
  resolve: {
503
864
  external: edgeExternal,
@@ -524,8 +885,8 @@ function setupEnvs(pluginConfig) {
524
885
  },
525
886
  generateBundle: {
526
887
  order: "post",
527
- async handler(_opts, bundle$1) {
528
- cleanupDummy(bundle$1);
888
+ async handler(_opts, bundle) {
889
+ cleanupDummy(bundle);
529
890
  }
530
891
  },
531
892
  sharedDuringBuild: true
@@ -533,16 +894,16 @@ function setupEnvs(pluginConfig) {
533
894
  {
534
895
  name: "vite-plugin-vercel:setup-envs:vercel_node",
535
896
  applyToEnvironment(env) {
536
- return env.name === "vercel_node";
897
+ return env.name === envNames.node;
537
898
  },
538
899
  configEnvironment(name, config) {
539
- if (name !== "vercel_node") return;
900
+ if (name !== envNames.node) return;
540
901
  return { optimizeDeps: { ...config.optimizeDeps } };
541
902
  },
542
903
  generateBundle: {
543
904
  order: "post",
544
- async handler(_opts, bundle$1) {
545
- cleanupDummy(bundle$1);
905
+ async handler(_opts, bundle) {
906
+ cleanupDummy(bundle);
546
907
  this.emitFile({
547
908
  type: "asset",
548
909
  fileName: "config.json",
@@ -555,10 +916,10 @@ function setupEnvs(pluginConfig) {
555
916
  {
556
917
  name: "vite-plugin-vercel:setup-envs:vercel_client",
557
918
  applyToEnvironment(env) {
558
- return env.name === "vercel_client";
919
+ return env.name === envNames.client;
559
920
  },
560
- generateBundle: { async handler(_opts, bundle$1) {
561
- cleanupDummy(bundle$1);
921
+ generateBundle: { async handler(_opts, bundle) {
922
+ cleanupDummy(bundle);
562
923
  const topLevelConfig = this.environment.getTopLevelConfig();
563
924
  const clientEnv = topLevelConfig.environments.client;
564
925
  if (clientEnv) try {
@@ -589,7 +950,9 @@ function createVercelEnvironmentOptions(overrides) {
589
950
  rollupOptions: {
590
951
  input: getDummyInput(),
591
952
  output: {
592
- sanitizeFileName: false,
953
+ sanitizeFileName: (filename) => {
954
+ return filename.replace("\0", "_");
955
+ },
593
956
  sourcemap: false
594
957
  }
595
958
  },
@@ -604,26 +967,25 @@ function createVercelEnvironmentOptions(overrides) {
604
967
  function getDummyInput() {
605
968
  return { [DUMMY]: `${virtualEntry}:${DUMMY}` };
606
969
  }
607
- function cleanupDummy(bundle$1) {
608
- const dummy = Object.keys(bundle$1).find((key) => key.includes("_DUMMY_"));
609
- if (dummy) delete bundle$1[dummy];
970
+ function cleanupDummy(bundle) {
971
+ const dummy = Object.keys(bundle).find((key) => key.includes("_DUMMY_"));
972
+ if (dummy) delete bundle[dummy];
610
973
  }
611
974
 
612
975
  //#endregion
613
976
  //#region src/plugins/index.ts
614
977
  function vercel(pluginConfig = {}) {
615
978
  return [
616
- reactEdgePlugin(),
617
- vercelCleanupPlugin(),
979
+ reactEdgePlugin(pluginConfig),
980
+ vercelCleanupPlugin(pluginConfig),
618
981
  apiPlugin(pluginConfig),
619
982
  ...setupEnvs(pluginConfig),
620
983
  ...loaderPlugin(pluginConfig),
621
- ...bundlePlugin(),
984
+ ...pluginConfig?.bundleStrategy === "nf3" ? nf3BundlePlugin(pluginConfig) : basicBundlePlugin(pluginConfig),
622
985
  catchAll(),
623
986
  devServer()
624
987
  ];
625
988
  }
626
- var plugins_default = vercel;
627
989
 
628
990
  //#endregion
629
- export { plugins_default as default, vercel };
991
+ export { vercel as default, vercel };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-vercel",
3
- "version": "11.0.0-beta.2",
3
+ "version": "11.0.0-beta.21",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -26,29 +26,30 @@
26
26
  "@types/node": "^22.19.3",
27
27
  "@universal-middleware/express": "^0.4.22",
28
28
  "@vercel/node": "^5.5.15",
29
- "tsdown": "^0.18.4",
29
+ "tsdown": "^0.20.3",
30
30
  "typescript": "^5.9.3",
31
31
  "vite": "^7.2.4",
32
32
  "vitest": "^4.0.16"
33
33
  },
34
34
  "dependencies": {
35
35
  "@manypkg/find-root": "^3.1.0",
36
- "@universal-deploy/store": "^0.0.2",
36
+ "@universal-deploy/store": "^0.1.3",
37
37
  "@universal-middleware/core": "^0.4.13",
38
38
  "@universal-middleware/vercel": "^0.4.29",
39
39
  "@vercel/build-utils": "^13.2.3",
40
- "@vercel/nft": "^1.1.1",
40
+ "@vercel/nft": "^1.2.0",
41
41
  "@vercel/routing-utils": "^5.3.1",
42
- "@vite-plugin-vercel/schemas": "latest",
43
42
  "convert-route": "^1.0.0",
44
43
  "fast-glob": "^3.3.3",
45
44
  "magicast": "^0.5.1",
46
- "nf3": "^0.3.1",
45
+ "nf3": "^0.3.4",
46
+ "oxc-transform": "^0.108.0",
47
47
  "p-limit": "^7.2.0",
48
48
  "path-to-regexp": "^8.3.0",
49
- "rolldown": "^1.0.0-beta.58",
49
+ "rolldown": "^1.0.0-rc.4",
50
50
  "strip-ansi": "^7.1.2",
51
- "vite-plugin-wasm": "^3.5.0"
51
+ "vite-plugin-wasm": "^3.5.0",
52
+ "@vite-plugin-vercel/schemas": "^1.0.0"
52
53
  },
53
54
  "scripts": {
54
55
  "dev": "tsdown --watch",
@@ -1,70 +0,0 @@
1
- //#region src/utils/assert.ts
2
- function assert(condition, errorMessage) {
3
- if (condition) return;
4
- throw new Error(`[vite-plugin-vercel] ${errorMessage}`);
5
- }
6
-
7
- //#endregion
8
- //#region src/api.ts
9
- function createAPI(outfiles, pluginConfig) {
10
- return {
11
- getOutFiles() {
12
- return outfiles;
13
- },
14
- get config() {
15
- pluginConfig.config ??= {};
16
- return pluginConfig.config;
17
- },
18
- get defaultMaxDuration() {
19
- return pluginConfig.defaultMaxDuration;
20
- },
21
- set defaultMaxDuration(value) {
22
- pluginConfig.defaultMaxDuration = value;
23
- },
24
- get expiration() {
25
- return pluginConfig.expiration;
26
- },
27
- set expiration(value) {
28
- pluginConfig.expiration = value;
29
- },
30
- get rewrites() {
31
- pluginConfig.rewrites ??= [];
32
- return pluginConfig.rewrites;
33
- },
34
- get headers() {
35
- pluginConfig.headers ??= [];
36
- return pluginConfig.headers;
37
- },
38
- get redirects() {
39
- pluginConfig.redirects ??= [];
40
- return pluginConfig.redirects;
41
- },
42
- get cleanUrls() {
43
- return pluginConfig.cleanUrls;
44
- },
45
- set cleanUrls(value) {
46
- pluginConfig.cleanUrls = value;
47
- },
48
- get trailingSlash() {
49
- return pluginConfig.trailingSlash;
50
- },
51
- set trailingSlash(value) {
52
- pluginConfig.trailingSlash = value;
53
- },
54
- get defaultSupportsResponseStreaming() {
55
- return pluginConfig.defaultSupportsResponseStreaming;
56
- },
57
- set defaultSupportsResponseStreaming(value) {
58
- pluginConfig.defaultSupportsResponseStreaming = value;
59
- }
60
- };
61
- }
62
- function getVercelAPI(pluginContextOrServer) {
63
- const vpv = ("environment" in pluginContextOrServer ? pluginContextOrServer.environment.config : pluginContextOrServer.config).plugins.find((p) => p.name === "vite-plugin-vercel:api");
64
- assert(vpv, "Could not find vite-plugin-vercel:api plugin");
65
- assert(vpv.api, "Missing `api`. Make sure vite-plugin-vercel is up-to-date");
66
- return vpv.api("environment" in pluginContextOrServer ? pluginContextOrServer : void 0);
67
- }
68
-
69
- //#endregion
70
- export { getVercelAPI as n, assert as r, createAPI as t };
File without changes