vite-plugin-vercel 0.1.1 → 0.1.4

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
@@ -3,7 +3,7 @@
3
3
  This is a **Work In Progress** Vercel adapter for [`vite`](https://vitejs.dev/).
4
4
 
5
5
  Its purpose is to help you bundle your application in `.vercel` folder as supported by
6
- ([Vercel API v3](https://vercel.com/docs/build-output-api/v3)).
6
+ [Vercel API v3](https://vercel.com/docs/build-output-api/v3).
7
7
 
8
8
  ## Features
9
9
 
@@ -13,7 +13,7 @@ Its purpose is to help you bundle your application in `.vercel` folder as suppor
13
13
  - `.[jt]s` files under the `<root>/api` folder of your project are automatically bundled as Serverless functions under `.vercel/output/functions/api/*.func`
14
14
  - see [`additionalEndpoints` config](/packages/vercel/src/types.ts#L54)
15
15
  - [x] [ISR/Prerender functions support](https://vercel.com/docs/build-output-api/v3#vercel-primitives/prerender-functions)
16
- - see [`isr` config](/packages/vercel/src/types.ts#L81). Also see implementation of [vite-plugin-ssr](./prerender/vite-plugin-ssr.ts) for example
16
+ - see [`isr` config](/packages/vercel/src/types.ts#L81). Also see implementation of [vite-plugin-ssr](/packages/vite-plugin-ssr/vite-plugin-ssr.ts) for example
17
17
  - [ ] [Edge functions support](https://vercel.com/docs/build-output-api/v3#vercel-primitives/edge-functions)
18
18
  - [ ] [Images optimization support](https://vercel.com/docs/build-output-api/v3#build-output-configuration/supported-properties/images)
19
19
  - [ ] [Preview mode support](https://vercel.com/docs/build-output-api/v3#features/preview-mode)
@@ -38,8 +38,7 @@ export default defineConfig({
38
38
 
39
39
  ### Usage with vite-plugin-ssr
40
40
 
41
- [vite-plugin-ssr](https://vite-plugin-ssr.com/) will support this plugin when stable.
42
- In the meantime, you can add experimental support yourself.
41
+ [vite-plugin-ssr](https://vite-plugin-ssr.com/) is supported through [@magne4000/vite-plugin-vercel-ssr](/packages/vite-plugin-ssr/README.md) plugin.
43
42
 
44
43
  Install `@magne4000/vite-plugin-vercel-ssr` package, and update your vite config:
45
44
 
@@ -53,9 +52,6 @@ import vercelSsr from '@magne4000/vite-plugin-vercel-ssr';
53
52
  export default defineConfig(async ({ command, mode }) => {
54
53
  return {
55
54
  plugins: [ssr(), vercel(), vercelSsr()],
56
- build: {
57
- polyfillDynamicImport: false,
58
- },
59
55
  vercel: {
60
56
  // Tweak what you need, check TS definition for details
61
57
  },
package/dist/index.cjs CHANGED
@@ -1,38 +1,10 @@
1
+ "use strict";
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
- var __defProps = Object.defineProperties;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
6
  var __getProtoOf = Object.getPrototypeOf;
9
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
- var __spreadValues = (a, b) => {
13
- for (var prop in b || (b = {}))
14
- if (__hasOwnProp.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- if (__getOwnPropSymbols)
17
- for (var prop of __getOwnPropSymbols(b)) {
18
- if (__propIsEnum.call(b, prop))
19
- __defNormalProp(a, prop, b[prop]);
20
- }
21
- return a;
22
- };
23
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
- var __objRest = (source, exclude) => {
25
- var target = {};
26
- for (var prop in source)
27
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
28
- target[prop] = source[prop];
29
- if (source != null && __getOwnPropSymbols)
30
- for (var prop of __getOwnPropSymbols(source)) {
31
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
32
- target[prop] = source[prop];
33
- }
34
- return target;
35
- };
36
8
  var __export = (target, all) => {
37
9
  for (var name in all)
38
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -54,37 +26,24 @@ __export(src_exports, {
54
26
  default: () => allPlugins
55
27
  });
56
28
  module.exports = __toCommonJS(src_exports);
57
- var import_promises5 = __toESM(require("fs/promises"), 1);
29
+ var import_promises4 = __toESM(require("fs/promises"), 1);
58
30
 
59
31
  // src/utils.ts
60
32
  var import_vite = require("vite");
61
33
  var import_path = __toESM(require("path"), 1);
62
- var import_promises = __toESM(require("fs/promises"), 1);
63
34
  function getRoot(config) {
64
35
  return (0, import_vite.normalizePath)(config.root || process.cwd());
65
36
  }
66
- function getOutDir(config, force) {
67
- const p = (0, import_vite.normalizePath)(config.build.outDir);
68
- if (!force)
69
- return p;
70
- return import_path.default.join(import_path.default.dirname(p), force);
71
- }
72
37
  function getOutput(config, suffix) {
73
38
  var _a, _b;
74
39
  return import_path.default.join(((_a = config.vercel) == null ? void 0 : _a.outDir) ? "" : getRoot(config), ((_b = config.vercel) == null ? void 0 : _b.outDir) ?? ".vercel/output", suffix ?? "");
75
40
  }
76
- function pathRelativeToApi(filePath, config) {
77
- const root = getRoot(config);
78
- return (0, import_vite.normalizePath)(import_path.default.relative(import_path.default.join(root, "api"), filePath));
41
+ function getPublic(config) {
42
+ return import_path.default.join(getRoot(config), config.publicDir || "public");
79
43
  }
80
- async function copyDir(src, dest) {
81
- await import_promises.default.mkdir(dest, { recursive: true });
82
- const entries = await import_promises.default.readdir(src, { withFileTypes: true });
83
- for (const entry of entries) {
84
- const srcPath = import_path.default.join(src, entry.name);
85
- const destPath = import_path.default.join(dest, entry.name);
86
- entry.isDirectory() ? await copyDir(srcPath, destPath) : await import_promises.default.copyFile(srcPath, destPath);
87
- }
44
+ function pathRelativeTo(filePath, config, rel) {
45
+ const root = getRoot(config);
46
+ return (0, import_vite.normalizePath)(import_path.default.relative(import_path.default.join(root, rel), filePath));
88
47
  }
89
48
 
90
49
  // src/config.ts
@@ -169,31 +128,53 @@ var vercelOutputConfigSchema = import_zod.z.object({
169
128
  }).strict();
170
129
 
171
130
  // src/config.ts
172
- var import_promises2 = __toESM(require("fs/promises"), 1);
131
+ var import_promises = __toESM(require("fs/promises"), 1);
173
132
  var import_routing_utils = require("@vercel/routing-utils");
174
- function getConfig(resolvedConfig, config) {
175
- var _a, _b, _c, _d, _e;
176
- const { routes } = (0, import_routing_utils.getTransformedRoutes)({
133
+ function reorderEnforce(arr) {
134
+ return [
135
+ ...arr.filter((r) => r.enforce === "pre"),
136
+ ...arr.filter((r) => !r.enforce),
137
+ ...arr.filter((r) => r.enforce === "post")
138
+ ];
139
+ }
140
+ function getConfig(resolvedConfig, rewrites, overrides) {
141
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
142
+ const _rewrites = [
143
+ ...((_a = resolvedConfig.vercel) == null ? void 0 : _a.rewrites) ?? [],
144
+ ...rewrites ?? []
145
+ ];
146
+ const { routes, error } = (0, import_routing_utils.getTransformedRoutes)({
177
147
  nowConfig: {
178
- cleanUrls: true
148
+ cleanUrls: ((_b = resolvedConfig.vercel) == null ? void 0 : _b.cleanUrls) ?? true,
149
+ trailingSlash: (_c = resolvedConfig.vercel) == null ? void 0 : _c.trailingSlash,
150
+ rewrites: reorderEnforce(_rewrites),
151
+ redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0
179
152
  }
180
153
  });
181
- return vercelOutputConfigSchema.parse(__spreadProps(__spreadValues({
182
- version: 3
183
- }, (_a = resolvedConfig.vercel) == null ? void 0 : _a.config), {
154
+ if (error) {
155
+ throw error;
156
+ }
157
+ if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0) {
158
+ console.warn("It is discouraged to use `vercel.config.routes` to override routes. Prefer using `vercel.rewrites` and `vercel.redirects`.");
159
+ }
160
+ return vercelOutputConfigSchema.parse({
161
+ version: 3,
162
+ ...(_h = resolvedConfig.vercel) == null ? void 0 : _h.config,
184
163
  routes: [
185
164
  ...routes ?? [],
186
- ...(config == null ? void 0 : config.routes) ?? [],
187
- ...((_c = (_b = resolvedConfig.vercel) == null ? void 0 : _b.config) == null ? void 0 : _c.routes) ?? []
165
+ ...((_j = (_i = resolvedConfig.vercel) == null ? void 0 : _i.config) == null ? void 0 : _j.routes) ?? []
188
166
  ],
189
- overrides: __spreadValues(__spreadValues({}, (_e = (_d = resolvedConfig.vercel) == null ? void 0 : _d.config) == null ? void 0 : _e.overrides), config == null ? void 0 : config.overrides)
190
- }));
167
+ overrides: {
168
+ ...(_l = (_k = resolvedConfig.vercel) == null ? void 0 : _k.config) == null ? void 0 : _l.overrides,
169
+ ...overrides
170
+ }
171
+ });
191
172
  }
192
173
  function getConfigDestination(resolvedConfig) {
193
174
  return import_path2.default.join(getOutput(resolvedConfig), "config.json");
194
175
  }
195
- async function writeConfig(resolvedConfig, config) {
196
- await import_promises2.default.writeFile(getConfigDestination(resolvedConfig), JSON.stringify(getConfig(resolvedConfig, config), void 0, 2), "utf-8");
176
+ async function writeConfig(resolvedConfig, rewrites, overrides) {
177
+ await import_promises.default.writeFile(getConfigDestination(resolvedConfig), JSON.stringify(getConfig(resolvedConfig, rewrites, overrides), void 0, 2), "utf-8");
197
178
  }
198
179
 
199
180
  // src/build.ts
@@ -240,23 +221,29 @@ var vercelOutputVcConfigSchema = import_zod2.z.union([
240
221
  ]);
241
222
 
242
223
  // src/build.ts
243
- var import_promises3 = __toESM(require("fs/promises"), 1);
224
+ var import_promises2 = __toESM(require("fs/promises"), 1);
244
225
  function getAdditionalEndpoints(resolvedConfig) {
245
226
  var _a;
246
- return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => __spreadProps(__spreadValues({}, e), {
247
- destination: e.destination + ".func"
227
+ return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => ({
228
+ ...e,
229
+ addRoute: e.addRoute ?? true,
230
+ destination: import_path3.default.resolve("/", e.destination) + ".func"
248
231
  }));
249
232
  }
250
233
  function getEntries(resolvedConfig) {
251
234
  const apiEntries = import_fast_glob.default.sync(`${getRoot(resolvedConfig)}/api/**/*.*([a-zA-Z0-9])`).filter((filepath) => !import_path3.default.basename(filepath).startsWith("_"));
252
- return apiEntries.reduce((entryPoints, filePath) => {
253
- const outFilePath = pathRelativeToApi(filePath, resolvedConfig);
235
+ if (apiEntries.length > 0) {
236
+ console.warn("@vercel/build is currently force building /api files itself, with no way to disable it. In order to avoid double compilation, you should temporarily rename /api to /_api while using this plugin. /_api functions are compiled under .vercel/output/functions/api/*.func as if they were in /api.");
237
+ }
238
+ const otherApiEntries = import_fast_glob.default.sync(`${getRoot(resolvedConfig)}/_api/**/*.*([a-zA-Z0-9])`).filter((filepath) => !import_path3.default.basename(filepath).startsWith("_"));
239
+ return [...apiEntries, ...otherApiEntries].reduce((entryPoints, filePath) => {
240
+ const outFilePath = pathRelativeTo(filePath, resolvedConfig, filePath.includes("/_api/") ? "_api" : "api");
254
241
  const parsed = import_path3.default.parse(outFilePath);
255
- const entry = {
242
+ entryPoints.push({
256
243
  source: filePath,
257
- destination: `api/${import_path3.default.posix.join(parsed.dir, parsed.name)}.func`
258
- };
259
- entryPoints.push(entry);
244
+ destination: `api/${import_path3.default.posix.join(parsed.dir, parsed.name)}.func`,
245
+ addRoute: true
246
+ });
260
247
  return entryPoints;
261
248
  }, getAdditionalEndpoints(resolvedConfig));
262
249
  }
@@ -290,7 +277,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
290
277
  async function writeVcConfig(resolvedConfig, destination) {
291
278
  var _a;
292
279
  const vcConfig = import_path3.default.join(getOutput(resolvedConfig, "functions"), destination, ".vc-config.json");
293
- await import_promises3.default.writeFile(vcConfig, JSON.stringify(vercelOutputVcConfigSchema.parse({
280
+ await import_promises2.default.writeFile(vcConfig, JSON.stringify(vercelOutputVcConfigSchema.parse({
294
281
  runtime: "nodejs16.x",
295
282
  handler: "index.js",
296
283
  maxDuration: (_a = resolvedConfig.vercel) == null ? void 0 : _a.defaultMaxDuration,
@@ -298,11 +285,21 @@ async function writeVcConfig(resolvedConfig, destination) {
298
285
  shouldAddHelpers: true
299
286
  }), void 0, 2), "utf-8");
300
287
  }
288
+ function getSourceAndDestination(destination) {
289
+ if (destination.startsWith("api/")) {
290
+ return import_path3.default.posix.resolve("/", destination);
291
+ }
292
+ return import_path3.default.posix.resolve("/", destination, ":match*");
293
+ }
301
294
  async function buildEndpoints(resolvedConfig) {
302
295
  const entries = getEntries(resolvedConfig);
303
296
  for (const entry of entries) {
304
297
  await buildFn(resolvedConfig, entry);
305
298
  }
299
+ return entries.filter((e) => e.addRoute !== false).map((e) => e.destination.replace(/\.func$/, "")).map((destination) => ({
300
+ source: getSourceAndDestination(destination),
301
+ destination: getSourceAndDestination(destination)
302
+ }));
306
303
  }
307
304
 
308
305
  // src/prerender.ts
@@ -319,7 +316,7 @@ var vercelOutputPrerenderConfigSchema = import_zod3.z.object({
319
316
  }).strict();
320
317
 
321
318
  // src/prerender.ts
322
- var import_promises4 = __toESM(require("fs/promises"), 1);
319
+ var import_promises3 = __toESM(require("fs/promises"), 1);
323
320
  function execPrerender(resolvedConfig) {
324
321
  var _a;
325
322
  const prerender = (_a = resolvedConfig.vercel) == null ? void 0 : _a.prerender;
@@ -332,10 +329,11 @@ var group = 1;
332
329
  async function writePrerenderConfig(resolvedConfig, destination, isr) {
333
330
  const parsed = import_path4.default.parse(destination);
334
331
  const outfile = import_path4.default.join(getOutput(resolvedConfig, "functions"), parsed.dir, parsed.name + ".prerender-config.json");
335
- await import_promises4.default.mkdir(import_path4.default.join(getOutput(resolvedConfig, "functions"), parsed.dir), { recursive: true });
336
- await import_promises4.default.writeFile(outfile, JSON.stringify(vercelOutputPrerenderConfigSchema.parse(__spreadValues({
337
- group: group++
338
- }, isr)), void 0, 2), "utf-8");
332
+ await import_promises3.default.mkdir(import_path4.default.join(getOutput(resolvedConfig, "functions"), parsed.dir), { recursive: true });
333
+ await import_promises3.default.writeFile(outfile, JSON.stringify(vercelOutputPrerenderConfigSchema.parse({
334
+ group: group++,
335
+ ...isr
336
+ }), void 0, 2), "utf-8");
339
337
  }
340
338
  function getPrerenderSymlinkInfo(resolvedConfig, destination, target) {
341
339
  const parsed = import_path4.default.parse(destination);
@@ -349,8 +347,7 @@ async function buildPrerenderConfigs(resolvedConfig) {
349
347
  const isr = await getIsrConfig(resolvedConfig);
350
348
  const entries = Object.entries(isr);
351
349
  const rewrites = [];
352
- for (const _a of entries) {
353
- const [destination, _b] = _a, _c = _b, { symlink, route } = _c, isr2 = __objRest(_c, ["symlink", "route"]);
350
+ for (const [destination, { symlink, route, ...isr2 }] of entries) {
354
351
  await writePrerenderConfig(resolvedConfig, destination, isr2);
355
352
  if (symlink) {
356
353
  const info = getPrerenderSymlinkInfo(resolvedConfig, destination, symlink);
@@ -358,13 +355,22 @@ async function buildPrerenderConfigs(resolvedConfig) {
358
355
  }
359
356
  if (route) {
360
357
  rewrites.push({
361
- src: `(${route})`,
362
- dest: `${destination}/?__original_path=$1`
358
+ source: `(${route})`,
359
+ destination: `${destination}/?__original_path=$1`
363
360
  });
364
361
  }
365
362
  }
366
363
  return rewrites;
367
364
  }
365
+ async function copyDir(src, dest) {
366
+ await import_promises3.default.mkdir(dest, { recursive: true });
367
+ const entries = await import_promises3.default.readdir(src, { withFileTypes: true });
368
+ for (const entry of entries) {
369
+ const srcPath = import_path4.default.join(src, entry.name);
370
+ const destPath = import_path4.default.join(dest, entry.name);
371
+ entry.isDirectory() ? await copyDir(srcPath, destPath) : await import_promises3.default.copyFile(srcPath, destPath);
372
+ }
373
+ }
368
374
  async function getIsrConfig(resolvedConfig) {
369
375
  var _a;
370
376
  const isr = ((_a = resolvedConfig.vercel) == null ? void 0 : _a.isr) ?? {};
@@ -375,6 +381,7 @@ async function getIsrConfig(resolvedConfig) {
375
381
  }
376
382
 
377
383
  // src/index.ts
384
+ var import_path5 = __toESM(require("path"), 1);
378
385
  function vercelPlugin() {
379
386
  let resolvedConfig;
380
387
  return {
@@ -388,35 +395,60 @@ function vercelPlugin() {
388
395
  if (process.env.VERCEL_ENV === "production" && !process.env.ENABLE_VC_BUILD) {
389
396
  throw new Error("Missing ENABLE_VC_BUILD=1 to your environment variables in your project settings");
390
397
  }
391
- if (!resolvedConfig.build.ssr) {
392
- await cleanOutputDirectory(resolvedConfig);
393
- } else {
394
- await copyDistClientToOutputStatic(resolvedConfig);
395
- }
396
398
  },
397
399
  async writeBundle() {
398
400
  var _a;
399
- if (!((_a = resolvedConfig.build) == null ? void 0 : _a.ssr))
401
+ if (!((_a = resolvedConfig.build) == null ? void 0 : _a.ssr)) {
402
+ await cleanOutputDirectory(resolvedConfig);
400
403
  return;
404
+ }
401
405
  const overrides = await execPrerender(resolvedConfig);
402
- await buildEndpoints(resolvedConfig);
403
- const rewrites = await buildPrerenderConfigs(resolvedConfig);
404
- await writeConfig(resolvedConfig, {
405
- routes: [{ handle: "filesystem" }, ...rewrites],
406
- overrides
406
+ const userOverrides = await computeStaticHtmlOverrides(resolvedConfig);
407
+ const rewrites = await buildEndpoints(resolvedConfig);
408
+ rewrites.push(...await buildPrerenderConfigs(resolvedConfig));
409
+ await writeConfig(resolvedConfig, rewrites, {
410
+ ...userOverrides,
411
+ ...overrides
407
412
  });
408
413
  }
409
414
  };
410
415
  }
411
- async function copyDistClientToOutputStatic(resolvedConfig) {
412
- await copyDir(getOutDir(resolvedConfig, "client"), getOutput(resolvedConfig, "static"));
413
- }
414
416
  async function cleanOutputDirectory(resolvedConfig) {
415
- await import_promises5.default.rm(getOutput(resolvedConfig), {
417
+ await import_promises4.default.rm(getOutput(resolvedConfig), {
416
418
  recursive: true,
417
419
  force: true
418
420
  });
419
421
  }
422
+ async function computeStaticHtmlOverrides(resolvedConfig) {
423
+ const staticAbsolutePath = getOutput(resolvedConfig, "static");
424
+ const files = await getStaticHtmlFiles(staticAbsolutePath);
425
+ const publicDir = getPublic(resolvedConfig);
426
+ const publicFiles = await getStaticHtmlFiles(publicDir);
427
+ files.push(...publicFiles.map((f) => f.replace(publicDir, staticAbsolutePath)));
428
+ return files.reduce((acc, curr) => {
429
+ const relPath = import_path5.default.relative(staticAbsolutePath, curr);
430
+ const parsed = import_path5.default.parse(relPath);
431
+ const pathJoined = import_path5.default.join(parsed.dir, parsed.name);
432
+ acc[relPath] = {
433
+ path: pathJoined
434
+ };
435
+ return acc;
436
+ }, {});
437
+ }
438
+ async function getStaticHtmlFiles(src) {
439
+ try {
440
+ await import_promises4.default.stat(src);
441
+ } catch (e) {
442
+ return [];
443
+ }
444
+ const entries = await import_promises4.default.readdir(src, { withFileTypes: true });
445
+ const htmlFiles = [];
446
+ for (const entry of entries) {
447
+ const srcPath = import_path5.default.join(src, entry.name);
448
+ entry.isDirectory() ? htmlFiles.push(...await getStaticHtmlFiles(srcPath)) : srcPath.endsWith(".html") ? htmlFiles.push(srcPath) : void 0;
449
+ }
450
+ return htmlFiles;
451
+ }
420
452
  function allPlugins() {
421
453
  return [vercelPlugin()];
422
454
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ResolvedConfig, Plugin } from 'vite';
2
2
  import { StdinOptions, BuildOptions } from 'esbuild';
3
3
  import { z } from 'zod';
4
+ import { VercelConfig } from '@vercel/routing-utils';
4
5
 
5
6
  /**
6
7
  * Schema definition for `.vercel/output/config.json`
@@ -513,6 +514,12 @@ declare const vercelOutputPrerenderConfigSchema: z.ZodObject<{
513
514
  }>;
514
515
  declare type VercelOutputPrerenderConfig = z.infer<typeof vercelOutputPrerenderConfigSchema>;
515
516
 
517
+ declare type ViteVercelRewrite = NonNullable<VercelConfig['rewrites']>[number] & {
518
+ enforce?: 'pre' | 'post';
519
+ };
520
+ declare type ViteVercelRedirect = NonNullable<VercelConfig['redirects']>[number] & {
521
+ enforce?: 'pre' | 'post';
522
+ };
516
523
  interface ViteVercelConfig {
517
524
  /**
518
525
  * How long Functions should be allowed to run for every request in seconds.
@@ -552,6 +559,10 @@ interface ViteVercelConfig {
552
559
  * }
553
560
  * ```
554
561
  */
562
+ rewrites?: ViteVercelRewrite[];
563
+ redirects?: ViteVercelRedirect[];
564
+ cleanUrls?: VercelConfig['cleanUrls'];
565
+ trailingSlash?: VercelConfig['trailingSlash'];
555
566
  additionalEndpoints?: ViteVercelApiEntry[];
556
567
  /**
557
568
  * Advanced configuration to override .vercel/output/config.json
@@ -608,8 +619,13 @@ interface ViteVercelApiEntry {
608
619
  * Override esbuild options
609
620
  */
610
621
  buildOptions?: BuildOptions;
622
+ /**
623
+ * Automatically add a route for the function (mimics defaults Vercel behavior)
624
+ * Set to `false` to disable
625
+ */
626
+ addRoute?: boolean;
611
627
  }
612
628
 
613
629
  declare function allPlugins(): Plugin[];
614
630
 
615
- export { VercelOutputConfig, VercelOutputIsr, VercelOutputPrerenderConfig, VercelOutputVcConfig, ViteVercelApiEntry, ViteVercelConfig, ViteVercelPrerenderFn, ViteVercelPrerenderRoute, allPlugins as default };
631
+ export { VercelOutputConfig, VercelOutputIsr, VercelOutputPrerenderConfig, VercelOutputVcConfig, ViteVercelApiEntry, ViteVercelConfig, ViteVercelPrerenderFn, ViteVercelPrerenderRoute, ViteVercelRedirect, ViteVercelRewrite, allPlugins as default };
package/dist/index.js CHANGED
@@ -1,67 +1,22 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- var __objRest = (source, exclude) => {
21
- var target = {};
22
- for (var prop in source)
23
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
- target[prop] = source[prop];
25
- if (source != null && __getOwnPropSymbols)
26
- for (var prop of __getOwnPropSymbols(source)) {
27
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
- target[prop] = source[prop];
29
- }
30
- return target;
31
- };
32
-
33
1
  // src/index.ts
34
- import fs5 from "fs/promises";
2
+ import fs4 from "fs/promises";
35
3
 
36
4
  // src/utils.ts
37
5
  import { normalizePath } from "vite";
38
6
  import path from "path";
39
- import fs from "fs/promises";
40
7
  function getRoot(config) {
41
8
  return normalizePath(config.root || process.cwd());
42
9
  }
43
- function getOutDir(config, force) {
44
- const p = normalizePath(config.build.outDir);
45
- if (!force)
46
- return p;
47
- return path.join(path.dirname(p), force);
48
- }
49
10
  function getOutput(config, suffix) {
50
11
  var _a, _b;
51
12
  return path.join(((_a = config.vercel) == null ? void 0 : _a.outDir) ? "" : getRoot(config), ((_b = config.vercel) == null ? void 0 : _b.outDir) ?? ".vercel/output", suffix ?? "");
52
13
  }
53
- function pathRelativeToApi(filePath, config) {
54
- const root = getRoot(config);
55
- return normalizePath(path.relative(path.join(root, "api"), filePath));
14
+ function getPublic(config) {
15
+ return path.join(getRoot(config), config.publicDir || "public");
56
16
  }
57
- async function copyDir(src, dest) {
58
- await fs.mkdir(dest, { recursive: true });
59
- const entries = await fs.readdir(src, { withFileTypes: true });
60
- for (const entry of entries) {
61
- const srcPath = path.join(src, entry.name);
62
- const destPath = path.join(dest, entry.name);
63
- entry.isDirectory() ? await copyDir(srcPath, destPath) : await fs.copyFile(srcPath, destPath);
64
- }
17
+ function pathRelativeTo(filePath, config, rel) {
18
+ const root = getRoot(config);
19
+ return normalizePath(path.relative(path.join(root, rel), filePath));
65
20
  }
66
21
 
67
22
  // src/config.ts
@@ -146,31 +101,53 @@ var vercelOutputConfigSchema = z.object({
146
101
  }).strict();
147
102
 
148
103
  // src/config.ts
149
- import fs2 from "fs/promises";
104
+ import fs from "fs/promises";
150
105
  import { getTransformedRoutes } from "@vercel/routing-utils";
151
- function getConfig(resolvedConfig, config) {
152
- var _a, _b, _c, _d, _e;
153
- const { routes } = getTransformedRoutes({
106
+ function reorderEnforce(arr) {
107
+ return [
108
+ ...arr.filter((r) => r.enforce === "pre"),
109
+ ...arr.filter((r) => !r.enforce),
110
+ ...arr.filter((r) => r.enforce === "post")
111
+ ];
112
+ }
113
+ function getConfig(resolvedConfig, rewrites, overrides) {
114
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
115
+ const _rewrites = [
116
+ ...((_a = resolvedConfig.vercel) == null ? void 0 : _a.rewrites) ?? [],
117
+ ...rewrites ?? []
118
+ ];
119
+ const { routes, error } = getTransformedRoutes({
154
120
  nowConfig: {
155
- cleanUrls: true
121
+ cleanUrls: ((_b = resolvedConfig.vercel) == null ? void 0 : _b.cleanUrls) ?? true,
122
+ trailingSlash: (_c = resolvedConfig.vercel) == null ? void 0 : _c.trailingSlash,
123
+ rewrites: reorderEnforce(_rewrites),
124
+ redirects: ((_d = resolvedConfig.vercel) == null ? void 0 : _d.redirects) ? reorderEnforce((_e = resolvedConfig.vercel) == null ? void 0 : _e.redirects) : void 0
156
125
  }
157
126
  });
158
- return vercelOutputConfigSchema.parse(__spreadProps(__spreadValues({
159
- version: 3
160
- }, (_a = resolvedConfig.vercel) == null ? void 0 : _a.config), {
127
+ if (error) {
128
+ throw error;
129
+ }
130
+ if (((_g = (_f = resolvedConfig.vercel) == null ? void 0 : _f.config) == null ? void 0 : _g.routes) && resolvedConfig.vercel.config.routes.length > 0) {
131
+ console.warn("It is discouraged to use `vercel.config.routes` to override routes. Prefer using `vercel.rewrites` and `vercel.redirects`.");
132
+ }
133
+ return vercelOutputConfigSchema.parse({
134
+ version: 3,
135
+ ...(_h = resolvedConfig.vercel) == null ? void 0 : _h.config,
161
136
  routes: [
162
137
  ...routes ?? [],
163
- ...(config == null ? void 0 : config.routes) ?? [],
164
- ...((_c = (_b = resolvedConfig.vercel) == null ? void 0 : _b.config) == null ? void 0 : _c.routes) ?? []
138
+ ...((_j = (_i = resolvedConfig.vercel) == null ? void 0 : _i.config) == null ? void 0 : _j.routes) ?? []
165
139
  ],
166
- overrides: __spreadValues(__spreadValues({}, (_e = (_d = resolvedConfig.vercel) == null ? void 0 : _d.config) == null ? void 0 : _e.overrides), config == null ? void 0 : config.overrides)
167
- }));
140
+ overrides: {
141
+ ...(_l = (_k = resolvedConfig.vercel) == null ? void 0 : _k.config) == null ? void 0 : _l.overrides,
142
+ ...overrides
143
+ }
144
+ });
168
145
  }
169
146
  function getConfigDestination(resolvedConfig) {
170
147
  return path2.join(getOutput(resolvedConfig), "config.json");
171
148
  }
172
- async function writeConfig(resolvedConfig, config) {
173
- await fs2.writeFile(getConfigDestination(resolvedConfig), JSON.stringify(getConfig(resolvedConfig, config), void 0, 2), "utf-8");
149
+ async function writeConfig(resolvedConfig, rewrites, overrides) {
150
+ await fs.writeFile(getConfigDestination(resolvedConfig), JSON.stringify(getConfig(resolvedConfig, rewrites, overrides), void 0, 2), "utf-8");
174
151
  }
175
152
 
176
153
  // src/build.ts
@@ -217,23 +194,29 @@ var vercelOutputVcConfigSchema = z2.union([
217
194
  ]);
218
195
 
219
196
  // src/build.ts
220
- import fs3 from "fs/promises";
197
+ import fs2 from "fs/promises";
221
198
  function getAdditionalEndpoints(resolvedConfig) {
222
199
  var _a;
223
- return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => __spreadProps(__spreadValues({}, e), {
224
- destination: e.destination + ".func"
200
+ return (((_a = resolvedConfig.vercel) == null ? void 0 : _a.additionalEndpoints) ?? []).map((e) => ({
201
+ ...e,
202
+ addRoute: e.addRoute ?? true,
203
+ destination: path3.resolve("/", e.destination) + ".func"
225
204
  }));
226
205
  }
227
206
  function getEntries(resolvedConfig) {
228
207
  const apiEntries = glob.sync(`${getRoot(resolvedConfig)}/api/**/*.*([a-zA-Z0-9])`).filter((filepath) => !path3.basename(filepath).startsWith("_"));
229
- return apiEntries.reduce((entryPoints, filePath) => {
230
- const outFilePath = pathRelativeToApi(filePath, resolvedConfig);
208
+ if (apiEntries.length > 0) {
209
+ console.warn("@vercel/build is currently force building /api files itself, with no way to disable it. In order to avoid double compilation, you should temporarily rename /api to /_api while using this plugin. /_api functions are compiled under .vercel/output/functions/api/*.func as if they were in /api.");
210
+ }
211
+ const otherApiEntries = glob.sync(`${getRoot(resolvedConfig)}/_api/**/*.*([a-zA-Z0-9])`).filter((filepath) => !path3.basename(filepath).startsWith("_"));
212
+ return [...apiEntries, ...otherApiEntries].reduce((entryPoints, filePath) => {
213
+ const outFilePath = pathRelativeTo(filePath, resolvedConfig, filePath.includes("/_api/") ? "_api" : "api");
231
214
  const parsed = path3.parse(outFilePath);
232
- const entry = {
215
+ entryPoints.push({
233
216
  source: filePath,
234
- destination: `api/${path3.posix.join(parsed.dir, parsed.name)}.func`
235
- };
236
- entryPoints.push(entry);
217
+ destination: `api/${path3.posix.join(parsed.dir, parsed.name)}.func`,
218
+ addRoute: true
219
+ });
237
220
  return entryPoints;
238
221
  }, getAdditionalEndpoints(resolvedConfig));
239
222
  }
@@ -267,7 +250,7 @@ async function buildFn(resolvedConfig, entry, buildOptions) {
267
250
  async function writeVcConfig(resolvedConfig, destination) {
268
251
  var _a;
269
252
  const vcConfig = path3.join(getOutput(resolvedConfig, "functions"), destination, ".vc-config.json");
270
- await fs3.writeFile(vcConfig, JSON.stringify(vercelOutputVcConfigSchema.parse({
253
+ await fs2.writeFile(vcConfig, JSON.stringify(vercelOutputVcConfigSchema.parse({
271
254
  runtime: "nodejs16.x",
272
255
  handler: "index.js",
273
256
  maxDuration: (_a = resolvedConfig.vercel) == null ? void 0 : _a.defaultMaxDuration,
@@ -275,11 +258,21 @@ async function writeVcConfig(resolvedConfig, destination) {
275
258
  shouldAddHelpers: true
276
259
  }), void 0, 2), "utf-8");
277
260
  }
261
+ function getSourceAndDestination(destination) {
262
+ if (destination.startsWith("api/")) {
263
+ return path3.posix.resolve("/", destination);
264
+ }
265
+ return path3.posix.resolve("/", destination, ":match*");
266
+ }
278
267
  async function buildEndpoints(resolvedConfig) {
279
268
  const entries = getEntries(resolvedConfig);
280
269
  for (const entry of entries) {
281
270
  await buildFn(resolvedConfig, entry);
282
271
  }
272
+ return entries.filter((e) => e.addRoute !== false).map((e) => e.destination.replace(/\.func$/, "")).map((destination) => ({
273
+ source: getSourceAndDestination(destination),
274
+ destination: getSourceAndDestination(destination)
275
+ }));
283
276
  }
284
277
 
285
278
  // src/prerender.ts
@@ -296,7 +289,7 @@ var vercelOutputPrerenderConfigSchema = z3.object({
296
289
  }).strict();
297
290
 
298
291
  // src/prerender.ts
299
- import fs4 from "fs/promises";
292
+ import fs3 from "fs/promises";
300
293
  function execPrerender(resolvedConfig) {
301
294
  var _a;
302
295
  const prerender = (_a = resolvedConfig.vercel) == null ? void 0 : _a.prerender;
@@ -309,10 +302,11 @@ var group = 1;
309
302
  async function writePrerenderConfig(resolvedConfig, destination, isr) {
310
303
  const parsed = path4.parse(destination);
311
304
  const outfile = path4.join(getOutput(resolvedConfig, "functions"), parsed.dir, parsed.name + ".prerender-config.json");
312
- await fs4.mkdir(path4.join(getOutput(resolvedConfig, "functions"), parsed.dir), { recursive: true });
313
- await fs4.writeFile(outfile, JSON.stringify(vercelOutputPrerenderConfigSchema.parse(__spreadValues({
314
- group: group++
315
- }, isr)), void 0, 2), "utf-8");
305
+ await fs3.mkdir(path4.join(getOutput(resolvedConfig, "functions"), parsed.dir), { recursive: true });
306
+ await fs3.writeFile(outfile, JSON.stringify(vercelOutputPrerenderConfigSchema.parse({
307
+ group: group++,
308
+ ...isr
309
+ }), void 0, 2), "utf-8");
316
310
  }
317
311
  function getPrerenderSymlinkInfo(resolvedConfig, destination, target) {
318
312
  const parsed = path4.parse(destination);
@@ -326,8 +320,7 @@ async function buildPrerenderConfigs(resolvedConfig) {
326
320
  const isr = await getIsrConfig(resolvedConfig);
327
321
  const entries = Object.entries(isr);
328
322
  const rewrites = [];
329
- for (const _a of entries) {
330
- const [destination, _b] = _a, _c = _b, { symlink, route } = _c, isr2 = __objRest(_c, ["symlink", "route"]);
323
+ for (const [destination, { symlink, route, ...isr2 }] of entries) {
331
324
  await writePrerenderConfig(resolvedConfig, destination, isr2);
332
325
  if (symlink) {
333
326
  const info = getPrerenderSymlinkInfo(resolvedConfig, destination, symlink);
@@ -335,13 +328,22 @@ async function buildPrerenderConfigs(resolvedConfig) {
335
328
  }
336
329
  if (route) {
337
330
  rewrites.push({
338
- src: `(${route})`,
339
- dest: `${destination}/?__original_path=$1`
331
+ source: `(${route})`,
332
+ destination: `${destination}/?__original_path=$1`
340
333
  });
341
334
  }
342
335
  }
343
336
  return rewrites;
344
337
  }
338
+ async function copyDir(src, dest) {
339
+ await fs3.mkdir(dest, { recursive: true });
340
+ const entries = await fs3.readdir(src, { withFileTypes: true });
341
+ for (const entry of entries) {
342
+ const srcPath = path4.join(src, entry.name);
343
+ const destPath = path4.join(dest, entry.name);
344
+ entry.isDirectory() ? await copyDir(srcPath, destPath) : await fs3.copyFile(srcPath, destPath);
345
+ }
346
+ }
345
347
  async function getIsrConfig(resolvedConfig) {
346
348
  var _a;
347
349
  const isr = ((_a = resolvedConfig.vercel) == null ? void 0 : _a.isr) ?? {};
@@ -352,6 +354,7 @@ async function getIsrConfig(resolvedConfig) {
352
354
  }
353
355
 
354
356
  // src/index.ts
357
+ import path5 from "path";
355
358
  function vercelPlugin() {
356
359
  let resolvedConfig;
357
360
  return {
@@ -365,35 +368,60 @@ function vercelPlugin() {
365
368
  if (process.env.VERCEL_ENV === "production" && !process.env.ENABLE_VC_BUILD) {
366
369
  throw new Error("Missing ENABLE_VC_BUILD=1 to your environment variables in your project settings");
367
370
  }
368
- if (!resolvedConfig.build.ssr) {
369
- await cleanOutputDirectory(resolvedConfig);
370
- } else {
371
- await copyDistClientToOutputStatic(resolvedConfig);
372
- }
373
371
  },
374
372
  async writeBundle() {
375
373
  var _a;
376
- if (!((_a = resolvedConfig.build) == null ? void 0 : _a.ssr))
374
+ if (!((_a = resolvedConfig.build) == null ? void 0 : _a.ssr)) {
375
+ await cleanOutputDirectory(resolvedConfig);
377
376
  return;
377
+ }
378
378
  const overrides = await execPrerender(resolvedConfig);
379
- await buildEndpoints(resolvedConfig);
380
- const rewrites = await buildPrerenderConfigs(resolvedConfig);
381
- await writeConfig(resolvedConfig, {
382
- routes: [{ handle: "filesystem" }, ...rewrites],
383
- overrides
379
+ const userOverrides = await computeStaticHtmlOverrides(resolvedConfig);
380
+ const rewrites = await buildEndpoints(resolvedConfig);
381
+ rewrites.push(...await buildPrerenderConfigs(resolvedConfig));
382
+ await writeConfig(resolvedConfig, rewrites, {
383
+ ...userOverrides,
384
+ ...overrides
384
385
  });
385
386
  }
386
387
  };
387
388
  }
388
- async function copyDistClientToOutputStatic(resolvedConfig) {
389
- await copyDir(getOutDir(resolvedConfig, "client"), getOutput(resolvedConfig, "static"));
390
- }
391
389
  async function cleanOutputDirectory(resolvedConfig) {
392
- await fs5.rm(getOutput(resolvedConfig), {
390
+ await fs4.rm(getOutput(resolvedConfig), {
393
391
  recursive: true,
394
392
  force: true
395
393
  });
396
394
  }
395
+ async function computeStaticHtmlOverrides(resolvedConfig) {
396
+ const staticAbsolutePath = getOutput(resolvedConfig, "static");
397
+ const files = await getStaticHtmlFiles(staticAbsolutePath);
398
+ const publicDir = getPublic(resolvedConfig);
399
+ const publicFiles = await getStaticHtmlFiles(publicDir);
400
+ files.push(...publicFiles.map((f) => f.replace(publicDir, staticAbsolutePath)));
401
+ return files.reduce((acc, curr) => {
402
+ const relPath = path5.relative(staticAbsolutePath, curr);
403
+ const parsed = path5.parse(relPath);
404
+ const pathJoined = path5.join(parsed.dir, parsed.name);
405
+ acc[relPath] = {
406
+ path: pathJoined
407
+ };
408
+ return acc;
409
+ }, {});
410
+ }
411
+ async function getStaticHtmlFiles(src) {
412
+ try {
413
+ await fs4.stat(src);
414
+ } catch (e) {
415
+ return [];
416
+ }
417
+ const entries = await fs4.readdir(src, { withFileTypes: true });
418
+ const htmlFiles = [];
419
+ for (const entry of entries) {
420
+ const srcPath = path5.join(src, entry.name);
421
+ entry.isDirectory() ? htmlFiles.push(...await getStaticHtmlFiles(srcPath)) : srcPath.endsWith(".html") ? htmlFiles.push(srcPath) : void 0;
422
+ }
423
+ return htmlFiles;
424
+ }
397
425
  function allPlugins() {
398
426
  return [vercelPlugin()];
399
427
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-vercel",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -20,23 +20,23 @@
20
20
  "repository": "https://github.com/magne4000/vite-plugin-vercel",
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "vite": "^2.9.9"
23
+ "vite": "^3.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@types/node": "^17.0.36",
27
- "@typescript-eslint/eslint-plugin": "^5.26.0",
28
- "@typescript-eslint/parser": "^5.26.0",
29
- "eslint": "^8.16.0",
30
- "tsup": "^6.0.1",
31
- "typescript": "^4.7.2",
32
- "vite": "^2.9.9"
26
+ "@types/node": "^16.11.45",
27
+ "@typescript-eslint/eslint-plugin": "^5.31.0",
28
+ "@typescript-eslint/parser": "^5.31.0",
29
+ "eslint": "^8.20.0",
30
+ "tsup": "^6.2.0",
31
+ "typescript": "^4.7.4",
32
+ "vite": "^3.0.3"
33
33
  },
34
34
  "dependencies": {
35
- "@brillout/libassert": "^0.5.6",
36
- "@vercel/routing-utils": "^1.13.3",
37
- "esbuild": "^0.14.42",
35
+ "@brillout/libassert": "^0.5.8",
36
+ "@vercel/routing-utils": "^1.13.5",
37
+ "esbuild": "^0.14.50",
38
38
  "fast-glob": "^3.2.11",
39
- "zod": "^3.17.3"
39
+ "zod": "^3.17.10"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsup",