vite-plugin-vercel 10.0.0-beta.5 → 11.0.0-beta.2
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 +8 -8
- package/dist/api-DR2y7JVQ.js +70 -0
- package/dist/api.d.ts +53 -1
- package/dist/api.js +3 -2
- package/dist/index.d.ts +23 -3
- package/dist/index.js +70 -12
- package/dist/path-B4ThGm96.js +10 -0
- package/dist/types.d.ts +103 -1
- package/dist/types.js +1 -2
- package/dist/vite.d.ts +9 -0
- package/dist/vite.js +629 -0
- package/meta.d.ts +7 -0
- package/package.json +32 -16
- package/dist/universal-middleware-dev.d.ts +0 -3
- package/dist/universal-middleware-dev.js +0 -7
- package/dist/universal-middleware-prod.d.ts +0 -3
- package/dist/universal-middleware-prod.js +0 -7
- package/dist/utils.d.ts +0 -3
- package/dist/utils.js +0 -2
package/README.md
CHANGED
|
@@ -31,12 +31,12 @@ bun add -D vite-plugin-vercel
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
33
|
- [x] [SSG/Static files](https://vercel.com/docs/build-output-api/v3/primitives#static-files)
|
|
34
|
-
|
|
34
|
+
- see [`prerender` config](/packages/vercel/src/types.ts#L37)
|
|
35
35
|
- [x] [SSR/Serverless functions](https://vercel.com/docs/build-output-api/v3/primitives#serverless-functions)
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
- `.[jt]s` files under the `<root>/api` folder of your project are automatically bundled as Serverless functions under `.vercel/output/functions/api/*.func`
|
|
37
|
+
- see [`additionalEndpoints` config](/packages/vercel/src/types.ts#L62)
|
|
38
38
|
- [x] [ISR/Prerender functions](https://vercel.com/docs/build-output-api/v3/primitives#prerender-functions)
|
|
39
|
-
|
|
39
|
+
- see [`isr` config](/packages/vercel/src/types.ts#L89). Also see implementation of [vike](/packages/vike-integration/vike.ts) for example
|
|
40
40
|
- [x] [Edge functions](https://vercel.com/docs/build-output-api/v3/primitives#edge-functions)
|
|
41
41
|
- [x] [Edge middleware](https://vercel.com/docs/functions/edge-middleware/middleware-api)
|
|
42
42
|
- [ ] [Images optimization](https://vercel.com/docs/build-output-api/v3/configuration#images)
|
|
@@ -51,9 +51,9 @@ Install this package as a dev dependency and add it to your Vite config:
|
|
|
51
51
|
// vite.config.ts
|
|
52
52
|
import { defineConfig } from 'vite';
|
|
53
53
|
import vercel from 'vite-plugin-vercel';
|
|
54
|
-
import {
|
|
54
|
+
import { getVercelEntries } from "vite-plugin-vercel";
|
|
55
55
|
|
|
56
|
-
const entries = await
|
|
56
|
+
const entries = await getVercelEntries("endpoints/api", {
|
|
57
57
|
// Auto mapping examples:
|
|
58
58
|
// endpoints/api/page.ts -> /api/page
|
|
59
59
|
// endpoints/api/name/[name].ts -> /api/name/*
|
|
@@ -73,7 +73,7 @@ export default defineConfig({
|
|
|
73
73
|
|
|
74
74
|
### Configure endpoints
|
|
75
75
|
|
|
76
|
-
Endpoints added via `
|
|
76
|
+
Endpoints added via `getVercelEntries` can be configured by exporting values from the endpoint file:
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
79
|
// file: endpoints/api/endpoint.ts
|
|
@@ -164,7 +164,7 @@ export default defineConfig({
|
|
|
164
164
|
*/
|
|
165
165
|
trailingSlash: true,
|
|
166
166
|
/**
|
|
167
|
-
* Use `
|
|
167
|
+
* Use `getVercelEntries` for mapping your filesystem routes to entries.
|
|
168
168
|
* If you are interfacing this plugin with a framework, entries can also be added through the Photon API
|
|
169
169
|
*/
|
|
170
170
|
entries: {
|
|
@@ -0,0 +1,70 @@
|
|
|
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 };
|
package/dist/api.d.ts
CHANGED
|
@@ -1 +1,53 @@
|
|
|
1
|
-
|
|
1
|
+
import { PluginContext, ViteVercelConfig, ViteVercelRedirect, ViteVercelRewrite } from "./types.js";
|
|
2
|
+
import { VercelOutputConfig } from "@vite-plugin-vercel/schemas";
|
|
3
|
+
import { ViteDevServer } from "vite";
|
|
4
|
+
import { EntryMeta } from "@universal-deploy/store";
|
|
5
|
+
import * as _vercel_routing_utils0 from "@vercel/routing-utils";
|
|
6
|
+
|
|
7
|
+
//#region src/api.d.ts
|
|
8
|
+
declare function createAPI(outfiles: ViteVercelOutFile[], pluginConfig: ViteVercelConfig): {
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
getOutFiles(): ViteVercelOutFile[];
|
|
13
|
+
readonly config: Partial<Omit<VercelOutputConfig, "version">>;
|
|
14
|
+
defaultMaxDuration: number | undefined;
|
|
15
|
+
expiration: number | undefined;
|
|
16
|
+
readonly rewrites: ViteVercelRewrite[];
|
|
17
|
+
readonly headers: _vercel_routing_utils0.Header[];
|
|
18
|
+
readonly redirects: ViteVercelRedirect[];
|
|
19
|
+
cleanUrls: boolean | undefined;
|
|
20
|
+
trailingSlash: boolean | undefined;
|
|
21
|
+
defaultSupportsResponseStreaming: boolean | undefined;
|
|
22
|
+
};
|
|
23
|
+
declare function getVercelAPI(pluginContextOrServer: Pick<PluginContext, "environment"> | ViteDevServer): {
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
getOutFiles(): ViteVercelOutFile[];
|
|
28
|
+
readonly config: Partial<Omit<VercelOutputConfig, "version">>;
|
|
29
|
+
defaultMaxDuration: number | undefined;
|
|
30
|
+
expiration: number | undefined;
|
|
31
|
+
readonly rewrites: ViteVercelRewrite[];
|
|
32
|
+
readonly headers: _vercel_routing_utils0.Header[];
|
|
33
|
+
readonly redirects: ViteVercelRedirect[];
|
|
34
|
+
cleanUrls: boolean | undefined;
|
|
35
|
+
trailingSlash: boolean | undefined;
|
|
36
|
+
defaultSupportsResponseStreaming: boolean | undefined;
|
|
37
|
+
};
|
|
38
|
+
type ViteVercelApi = ReturnType<typeof createAPI>;
|
|
39
|
+
type ViteVercelOutFile = ViteVercelOutFileChunk | ViteVercelOutFileAsset;
|
|
40
|
+
interface ViteVercelOutFileCommon {
|
|
41
|
+
filepath: string;
|
|
42
|
+
root: string;
|
|
43
|
+
outdir: string;
|
|
44
|
+
}
|
|
45
|
+
interface ViteVercelOutFileChunk extends ViteVercelOutFileCommon {
|
|
46
|
+
type: "chunk";
|
|
47
|
+
relatedEntry: EntryMeta;
|
|
48
|
+
}
|
|
49
|
+
interface ViteVercelOutFileAsset extends ViteVercelOutFileCommon {
|
|
50
|
+
type: "asset";
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { ViteVercelApi, ViteVercelOutFile, ViteVercelOutFileAsset, ViteVercelOutFileChunk, createAPI, getVercelAPI };
|
package/dist/api.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { n as getVercelAPI, t as createAPI } from "./api-DR2y7JVQ.js";
|
|
2
|
+
|
|
3
|
+
export { createAPI, getVercelAPI };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { EntryMeta } from "@universal-deploy/store";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
//#region src/index.d.ts
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Scans the filesystem for entry points.
|
|
7
|
+
* @experimental
|
|
8
|
+
*/
|
|
9
|
+
declare function getVercelEntries(dir: string, {
|
|
10
|
+
destination,
|
|
11
|
+
tryParseExports
|
|
12
|
+
}: {
|
|
13
|
+
destination?: string | undefined;
|
|
14
|
+
tryParseExports?: boolean | undefined;
|
|
15
|
+
}): Promise<EntryMeta[]>;
|
|
16
|
+
declare function extractExports(filepath: string): Promise<{
|
|
17
|
+
edge?: boolean | undefined;
|
|
18
|
+
headers?: Record<string, string> | undefined;
|
|
19
|
+
streaming?: boolean | undefined;
|
|
20
|
+
isr?: {
|
|
21
|
+
expiration: number | false;
|
|
22
|
+
} | undefined;
|
|
23
|
+
} | null>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { extractExports, getVercelEntries };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { t as pathRelativeTo } from "./path-B4ThGm96.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { vercelEndpointExports } from "@vite-plugin-vercel/schemas";
|
|
4
|
+
import { fromNextFs } from "convert-route/next-fs";
|
|
5
|
+
import { toRou3 } from "convert-route/rou3";
|
|
6
|
+
import glob from "fast-glob";
|
|
7
|
+
import { generateCode, loadFile } from "magicast";
|
|
8
|
+
import { normalizePath } from "vite";
|
|
9
|
+
|
|
10
|
+
//#region src/index.ts
|
|
11
|
+
/**
|
|
12
|
+
* Scans the filesystem for entry points.
|
|
13
|
+
* @experimental
|
|
14
|
+
*/
|
|
15
|
+
async function getVercelEntries(dir, { destination = dir, tryParseExports = true }) {
|
|
16
|
+
const normalizedDir = normalizePath(dir);
|
|
17
|
+
destination = normalizePath(destination);
|
|
18
|
+
const apiEntries = glob.sync(`${path.posix.resolve(normalizedDir)}/**/*.?(m)[jt]s?(x)`).filter((filepath) => !path.basename(filepath).startsWith("_"));
|
|
19
|
+
const entryPoints = [];
|
|
20
|
+
for (const filePath of apiEntries) {
|
|
21
|
+
const outFilePath = pathRelativeTo(filePath, normalizedDir);
|
|
22
|
+
const parsed = path.posix.parse(outFilePath);
|
|
23
|
+
let xports;
|
|
24
|
+
if (tryParseExports) xports = await extractExports(filePath);
|
|
25
|
+
const key = path.posix.join(destination, parsed.dir, parsed.name);
|
|
26
|
+
const entry = {
|
|
27
|
+
id: filePath,
|
|
28
|
+
vercel: {}
|
|
29
|
+
};
|
|
30
|
+
if (xports?.edge) entry.vercel.edge = xports.edge;
|
|
31
|
+
if (xports?.isr) entry.vercel.isr = xports.isr;
|
|
32
|
+
if (xports?.headers) entry.vercel.headers = xports.headers;
|
|
33
|
+
if (xports?.streaming) entry.vercel.streaming = xports.streaming;
|
|
34
|
+
entry.pattern = entryToRou3(key);
|
|
35
|
+
if (key.includes("[...")) entry.vercel.enforce = "post";
|
|
36
|
+
entryPoints.push(entry);
|
|
37
|
+
}
|
|
38
|
+
return entryPoints;
|
|
39
|
+
}
|
|
40
|
+
function entryToRou3(key) {
|
|
41
|
+
return toRou3(fromNextFs(path.posix.resolve("/", key)))[0].replace(/\/index$/, "/");
|
|
42
|
+
}
|
|
43
|
+
async function extractExports(filepath) {
|
|
44
|
+
try {
|
|
45
|
+
const mod = await loadFile(filepath);
|
|
46
|
+
const subject = {
|
|
47
|
+
edge: evalExport(mod.exports.edge),
|
|
48
|
+
headers: evalExport(mod.exports.headers),
|
|
49
|
+
streaming: evalExport(mod.exports.streaming),
|
|
50
|
+
isr: evalExport(mod.exports.isr)
|
|
51
|
+
};
|
|
52
|
+
return vercelEndpointExports.parse(subject);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.warn(`Warning: failed to read exports of '${filepath}'`, e);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isPrimitive(test) {
|
|
59
|
+
return test !== Object(test);
|
|
60
|
+
}
|
|
61
|
+
function _eval(code) {
|
|
62
|
+
return new Function(`{ return function(){ return ${code} } };`).call(null).call(null);
|
|
63
|
+
}
|
|
64
|
+
function evalExport(exp) {
|
|
65
|
+
if (!exp) return;
|
|
66
|
+
return _eval(isPrimitive(exp) ? exp : generateCode(exp).code);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { extractExports, getVercelEntries };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { normalizePath } from "vite";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/path.ts
|
|
5
|
+
function pathRelativeTo(filePath, rel) {
|
|
6
|
+
return normalizePath(path.relative(normalizePath(path.resolve(rel)), path.resolve(filePath)));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { pathRelativeTo as t };
|
package/dist/types.d.ts
CHANGED
|
@@ -1 +1,103 @@
|
|
|
1
|
-
|
|
1
|
+
import { VercelOutputConfig, VercelOutputPrerenderConfig } from "@vite-plugin-vercel/schemas";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
import { EntryMeta } from "@universal-deploy/store";
|
|
4
|
+
import { Header, Redirect, Rewrite } from "@vercel/routing-utils";
|
|
5
|
+
|
|
6
|
+
//#region src/types.d.ts
|
|
7
|
+
type ViteVercelRewrite = Rewrite & {
|
|
8
|
+
enforce?: "pre" | "post";
|
|
9
|
+
};
|
|
10
|
+
type ViteVercelRedirect = Redirect & {
|
|
11
|
+
enforce?: "pre" | "post";
|
|
12
|
+
};
|
|
13
|
+
type PluginContext = ThisParameterType<Extract<Plugin["resolveId"], (...args: never) => any>>;
|
|
14
|
+
interface ViteVercelConfig {
|
|
15
|
+
/**
|
|
16
|
+
* How long Functions should be allowed to run for every request, in seconds.
|
|
17
|
+
* If left empty, default value for your plan will be used.
|
|
18
|
+
*/
|
|
19
|
+
defaultMaxDuration?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Default expiration time (in seconds) for prerender functions.
|
|
22
|
+
* Defaults to 86400 seconds (24h).
|
|
23
|
+
* @see {@link https://vercel.com/docs/concepts/next.js/incremental-static-regeneration}
|
|
24
|
+
* @see {@link https://vercel.com/docs/build-output-api/v3#vercel-primitives/prerender-functions/configuration}
|
|
25
|
+
*/
|
|
26
|
+
expiration?: number;
|
|
27
|
+
/**
|
|
28
|
+
* @see {@link https://vercel.com/docs/projects/project-configuration#rewrites}
|
|
29
|
+
*/
|
|
30
|
+
rewrites?: ViteVercelRewrite[];
|
|
31
|
+
/**
|
|
32
|
+
* @see {@link https://vercel.com/docs/projects/project-configuration#headers}
|
|
33
|
+
* @beta
|
|
34
|
+
*/
|
|
35
|
+
headers?: Header[];
|
|
36
|
+
/**
|
|
37
|
+
* @see {@link https://vercel.com/docs/projects/project-configuration#redirects}
|
|
38
|
+
*/
|
|
39
|
+
redirects?: ViteVercelRedirect[];
|
|
40
|
+
/**
|
|
41
|
+
* @see {@link https://vercel.com/docs/projects/project-configuration#cleanurls}
|
|
42
|
+
*/
|
|
43
|
+
cleanUrls?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* @see {@link https://vercel.com/docs/projects/project-configuration#trailingslash}
|
|
46
|
+
*/
|
|
47
|
+
trailingSlash?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* When true, the Serverless Function will stream the response to the client.
|
|
50
|
+
* @see {@link https://vercel.com/docs/build-output-api/v3/primitives#serverless-function-configuration}
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
53
|
+
defaultSupportsResponseStreaming?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Use `getVercelEntries` for mapping your filesystem routes to entries.
|
|
56
|
+
*/
|
|
57
|
+
entries?: EntryMeta[];
|
|
58
|
+
/**
|
|
59
|
+
* Advanced configuration to override .vercel/output/config.json
|
|
60
|
+
* @see {@link https://vercel.com/docs/build-output-api/v3/configuration#configuration}
|
|
61
|
+
* @protected
|
|
62
|
+
*/
|
|
63
|
+
config?: Partial<Omit<VercelOutputConfig, "version">>;
|
|
64
|
+
/**
|
|
65
|
+
* Defaults to `.vercel/output`. Mostly useful for testing purpose
|
|
66
|
+
* @protected
|
|
67
|
+
*/
|
|
68
|
+
outDir?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Keys are path relative to .vercel/output/static directory
|
|
72
|
+
*/
|
|
73
|
+
type ViteVercelRouteOverrides = VercelOutputConfig["overrides"];
|
|
74
|
+
interface VercelEntryOptions {
|
|
75
|
+
/**
|
|
76
|
+
* If `true`, guesses route for the function, and adds it to config.json (mimics defaults Vercel behavior).
|
|
77
|
+
* If a string is provided, it will be equivalent to a `rewrites` rule.
|
|
78
|
+
* Set to `false` to disable
|
|
79
|
+
*/
|
|
80
|
+
route?: string | boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Ensures that the route is added before or after others
|
|
83
|
+
*/
|
|
84
|
+
enforce?: "post" | "pre";
|
|
85
|
+
/**
|
|
86
|
+
* Set to `true` to mark this function as an Edge Function
|
|
87
|
+
*/
|
|
88
|
+
edge?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Additional headers
|
|
91
|
+
*/
|
|
92
|
+
headers?: Record<string, string> | null;
|
|
93
|
+
/**
|
|
94
|
+
* ISR config
|
|
95
|
+
*/
|
|
96
|
+
isr?: VercelOutputPrerenderConfig;
|
|
97
|
+
/**
|
|
98
|
+
* When true, the Serverless Function will stream the response to the client
|
|
99
|
+
*/
|
|
100
|
+
streaming?: boolean;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { PluginContext, VercelEntryOptions, ViteVercelConfig, ViteVercelRedirect, ViteVercelRewrite, ViteVercelRouteOverrides };
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export * from "@photonjs/vercel/types";
|
|
1
|
+
export { };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ViteVercelConfig } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/index.d.ts
|
|
4
|
+
type PluginInterop = Record<string, unknown> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
declare function vercel(pluginConfig?: ViteVercelConfig): PluginInterop[];
|
|
8
|
+
//#endregion
|
|
9
|
+
export { vercel as default, vercel };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
import { t as pathRelativeTo$1 } from "./path-B4ThGm96.js";
|
|
2
|
+
import { r as assert, t as createAPI } from "./api-DR2y7JVQ.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { vercelOutputConfigSchema, vercelOutputPrerenderConfigSchema, vercelOutputVcConfigSchema } from "@vite-plugin-vercel/schemas";
|
|
5
|
+
import { fromRou3 } from "convert-route/rou3";
|
|
6
|
+
import { BuildEnvironment, createRunnableDevEnvironment, mergeConfig, normalizePath } from "vite";
|
|
7
|
+
import { catchAll, devServer } from "@universal-deploy/store/vite";
|
|
8
|
+
import { store } from "@universal-deploy/store";
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import { cpus } from "node:os";
|
|
11
|
+
import { resolve } from "@vercel/nft";
|
|
12
|
+
import { externals } from "nf3/plugin";
|
|
13
|
+
import pLimit from "p-limit";
|
|
14
|
+
import { build } from "rolldown";
|
|
15
|
+
import { getNodeVersion } from "@vercel/build-utils";
|
|
16
|
+
import { toPathToRegexpV6 } from "convert-route/path-to-regexp-v6";
|
|
17
|
+
import { cp } from "node:fs/promises";
|
|
18
|
+
import { getTransformedRoutes, mergeRoutes, normalizeRoutes } from "@vercel/routing-utils";
|
|
19
|
+
|
|
20
|
+
//#region src/utils/dedupeRoutes.ts
|
|
21
|
+
/**
|
|
22
|
+
* When multiple entries point to the same module, we can deploy them as a single function.
|
|
23
|
+
* Create a separate function only when specific configuration is provided (`isr`, `headers`, `edge` or `streaming`).
|
|
24
|
+
*/
|
|
25
|
+
function dedupeRoutes() {
|
|
26
|
+
const entriesToKeep = [];
|
|
27
|
+
const entriesGroupedByModuleId = groupBy(store.entries, (e) => e.id);
|
|
28
|
+
for (const entries of entriesGroupedByModuleId.values()) {
|
|
29
|
+
let groupedEntry;
|
|
30
|
+
for (const entry of entries) if (entry.vercel && Object.keys(entry.vercel).length > 0) {
|
|
31
|
+
if (!Array.isArray(entry.pattern)) entry.pattern = [entry.pattern];
|
|
32
|
+
entriesToKeep.push(entry);
|
|
33
|
+
} else if (!groupedEntry) {
|
|
34
|
+
groupedEntry = structuredClone(entry);
|
|
35
|
+
if (!Array.isArray(groupedEntry.pattern)) groupedEntry.pattern = [groupedEntry.pattern];
|
|
36
|
+
entriesToKeep.push(groupedEntry);
|
|
37
|
+
} else groupedEntry.pattern.push(...[entry.pattern].flat());
|
|
38
|
+
}
|
|
39
|
+
return entriesToKeep;
|
|
40
|
+
}
|
|
41
|
+
function groupBy(list, fn, selector) {
|
|
42
|
+
return Array.from(list).reduce((acc, curr) => {
|
|
43
|
+
const key = fn(curr);
|
|
44
|
+
if (!acc.has(key)) acc.set(key, []);
|
|
45
|
+
if (selector) acc.get(key).push(...selector(curr));
|
|
46
|
+
else acc.get(key).push(curr);
|
|
47
|
+
return acc;
|
|
48
|
+
}, /* @__PURE__ */ new Map());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/utils/extension.ts
|
|
53
|
+
function removeExtension$1(subject) {
|
|
54
|
+
return subject.replace(/\.[^/.]+$/, "");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/utils/destination.ts
|
|
59
|
+
function entryDestinationDefault(root, entry) {
|
|
60
|
+
return `${removeExtension$1(pathRelativeTo$1(entry.id, root)).replace(/[^a-zA-Z0-9\-_[\]/]/g, "-")}`;
|
|
61
|
+
}
|
|
62
|
+
function entryDestination(root, entry, postfix) {
|
|
63
|
+
return `${path.posix.join("functions/", entryDestinationDefault(root, entry))}${postfix}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/plugins/api.ts
|
|
68
|
+
function apiPlugin(pluginConfig) {
|
|
69
|
+
const outfiles = [];
|
|
70
|
+
return {
|
|
71
|
+
name: "vite-plugin-vercel:api",
|
|
72
|
+
api() {
|
|
73
|
+
return createAPI(outfiles, pluginConfig);
|
|
74
|
+
},
|
|
75
|
+
applyToEnvironment({ name }) {
|
|
76
|
+
return name === "vercel_edge" || name === "vercel_node";
|
|
77
|
+
},
|
|
78
|
+
writeBundle(_opts, bundle$1) {
|
|
79
|
+
const root = this.environment.config.root ?? process.cwd();
|
|
80
|
+
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({
|
|
82
|
+
type: "chunk",
|
|
83
|
+
root: this.environment.config.root,
|
|
84
|
+
outdir: this.environment.config.build.outDir,
|
|
85
|
+
filepath: key,
|
|
86
|
+
relatedEntry: entryMapByDestination.get(removeExtension$1(key))
|
|
87
|
+
});
|
|
88
|
+
else if (value.type === "asset" && key.startsWith("functions/") || key === "config.json") outfiles.push({
|
|
89
|
+
type: "asset",
|
|
90
|
+
root: this.environment.config.root,
|
|
91
|
+
outdir: this.environment.config.build.outDir,
|
|
92
|
+
filepath: key
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
sharedDuringBuild: true
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/utils/external.ts
|
|
101
|
+
const _external = [
|
|
102
|
+
"async_hooks",
|
|
103
|
+
"events",
|
|
104
|
+
"buffer",
|
|
105
|
+
"assert",
|
|
106
|
+
"util"
|
|
107
|
+
];
|
|
108
|
+
const edgeExternal = [..._external, ..._external.map((e) => `node:${e}`)];
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/plugins/bundle.ts
|
|
112
|
+
function bundlePlugin() {
|
|
113
|
+
const externalsPlugin = externals({});
|
|
114
|
+
delete externalsPlugin.buildEnd;
|
|
115
|
+
let buildOutput;
|
|
116
|
+
return [{
|
|
117
|
+
...externalsPlugin,
|
|
118
|
+
applyToEnvironment(env) {
|
|
119
|
+
return env.config.consumer !== "client";
|
|
120
|
+
}
|
|
121
|
+
}, {
|
|
122
|
+
name: "vite-plugin-vercel:isolate-functions",
|
|
123
|
+
apply: "build",
|
|
124
|
+
applyToEnvironment(env) {
|
|
125
|
+
return env.config.consumer !== "client";
|
|
126
|
+
},
|
|
127
|
+
async writeBundle(_, output) {
|
|
128
|
+
const isEdge = this.environment.name === "vercel_edge";
|
|
129
|
+
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));
|
|
131
|
+
const entries = Object.entries(output).filter((e) => "isEntry" in e[1] && e[1].isEntry).map((e) => ({
|
|
132
|
+
name: e[1].name,
|
|
133
|
+
fileName: e[1].fileName,
|
|
134
|
+
outPath: path.join(outDir$1, e[1].fileName)
|
|
135
|
+
}));
|
|
136
|
+
assert(entries.length > 0, "No entry files found in build output");
|
|
137
|
+
const outPaths = entries.map((entry) => entry.outPath);
|
|
138
|
+
const input = Object.fromEntries(outPaths.map((e) => [removeExtension(pathRelativeTo(e, outDir$1)), e]));
|
|
139
|
+
const limit = pLimit(Math.max(1, Math.ceil(cpus().length / 2)));
|
|
140
|
+
const localOutput = (await Promise.all(Object.values(input).map((entryPath) => limit(async () => {
|
|
141
|
+
const outDir$2 = path.dirname(entryPath);
|
|
142
|
+
return { output: (await bundle({
|
|
143
|
+
isEdge,
|
|
144
|
+
input: { index: entryPath },
|
|
145
|
+
outDir: outDir$2,
|
|
146
|
+
externals: {
|
|
147
|
+
conditions: this.environment.config.resolve.conditions,
|
|
148
|
+
rootDir: this.environment.config.root,
|
|
149
|
+
trace: {
|
|
150
|
+
outDir: path.dirname(entryPath),
|
|
151
|
+
nft: { async resolve(id, parent, job, cjsResolve) {
|
|
152
|
+
return resolve(id.replace(/\.wasm\?module$/, ".wasm"), parent, job, cjsResolve);
|
|
153
|
+
} }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
})).output.map((o) => ({
|
|
157
|
+
...o,
|
|
158
|
+
fileName: path.join(outDir$2, o.fileName)
|
|
159
|
+
})) };
|
|
160
|
+
})))).flatMap((r) => r.output);
|
|
161
|
+
buildOutput = buildOutput ? [...buildOutput, ...localOutput] : localOutput;
|
|
162
|
+
cleanup(output, buildOutput, this.environment.config.build.outDir);
|
|
163
|
+
}
|
|
164
|
+
}];
|
|
165
|
+
}
|
|
166
|
+
function bundle(options) {
|
|
167
|
+
assert(options.input, "No input specified");
|
|
168
|
+
return build({
|
|
169
|
+
platform: options.isEdge ? "browser" : "node",
|
|
170
|
+
external: options.isEdge ? edgeExternal : [],
|
|
171
|
+
write: true,
|
|
172
|
+
plugins: [externals(options.externals)],
|
|
173
|
+
input: options.input,
|
|
174
|
+
resolve: { conditionNames: options.externals.conditions },
|
|
175
|
+
output: {
|
|
176
|
+
entryFileNames: options.isEdge ? "[name].js" : "[name].mjs",
|
|
177
|
+
sanitizeFileName: false,
|
|
178
|
+
dir: options.outDir,
|
|
179
|
+
hoistTransitiveImports: false
|
|
180
|
+
},
|
|
181
|
+
checks: { pluginTimings: false }
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function cleanup(viteOutput, rolldownOutput, outputDir) {
|
|
185
|
+
const viteFilenames = Object.values(viteOutput).map((o) => path.join(outputDir, o.fileName));
|
|
186
|
+
const rolldownFilenames = new Set(rolldownOutput.map((o) => o.fileName));
|
|
187
|
+
const rolldownModuleIds = new Set(rolldownOutput.flatMap((o) => o.type === "chunk" ? o.moduleIds : []));
|
|
188
|
+
const filesToDelete = viteFilenames.filter((id) => id.startsWith(outputDir) && rolldownModuleIds.has(id) && !rolldownFilenames.has(id));
|
|
189
|
+
const parentDirs = /* @__PURE__ */ new Set();
|
|
190
|
+
for (const file of filesToDelete) try {
|
|
191
|
+
fs.unlinkSync(file);
|
|
192
|
+
const mapFile = `${file}.map`;
|
|
193
|
+
if (fs.existsSync(mapFile)) fs.unlinkSync(mapFile);
|
|
194
|
+
parentDirs.add(path.dirname(file));
|
|
195
|
+
} catch {}
|
|
196
|
+
for (const dir of parentDirs) try {
|
|
197
|
+
if (fs.readdirSync(dir).length === 0) fs.rmdirSync(dir);
|
|
198
|
+
} catch {}
|
|
199
|
+
}
|
|
200
|
+
function pathRelativeTo(filePath, rel) {
|
|
201
|
+
return normalizePath(path.relative(normalizePath(path.resolve(rel)), path.resolve(filePath)));
|
|
202
|
+
}
|
|
203
|
+
function removeExtension(subject) {
|
|
204
|
+
return subject.replace(/\.[^/.]+$/, "");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/plugins/clean-outdir.ts
|
|
209
|
+
function vercelCleanupPlugin(pluginConfig) {
|
|
210
|
+
let alreadyRun = false;
|
|
211
|
+
return {
|
|
212
|
+
apply: "build",
|
|
213
|
+
name: "vite-plugin-vercel:cleanup",
|
|
214
|
+
enforce: "pre",
|
|
215
|
+
applyToEnvironment(env) {
|
|
216
|
+
return env.name === "vercel_client";
|
|
217
|
+
},
|
|
218
|
+
buildStart: {
|
|
219
|
+
order: "pre",
|
|
220
|
+
sequential: true,
|
|
221
|
+
handler() {
|
|
222
|
+
if (alreadyRun) return;
|
|
223
|
+
alreadyRun = true;
|
|
224
|
+
cleanOutputDirectory(pluginConfig?.outDir && path.isAbsolute(pluginConfig.outDir) ? pluginConfig.outDir : path.join(this.environment.config.root, pluginConfig?.outDir ?? ".vercel/output"));
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
sharedDuringBuild: true
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function cleanOutputDirectory(outdir) {
|
|
231
|
+
fs.rmSync(outdir, {
|
|
232
|
+
recursive: true,
|
|
233
|
+
force: true
|
|
234
|
+
});
|
|
235
|
+
fs.mkdirSync(outdir, { recursive: true });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/build.ts
|
|
240
|
+
function getVcConfig(pluginConfig, filename, options) {
|
|
241
|
+
return vercelOutputVcConfigSchema.parse(options.edge ? {
|
|
242
|
+
runtime: "edge",
|
|
243
|
+
entrypoint: filename
|
|
244
|
+
} : {
|
|
245
|
+
runtime: options.nodeVersion.runtime,
|
|
246
|
+
handler: filename,
|
|
247
|
+
maxDuration: pluginConfig.defaultMaxDuration,
|
|
248
|
+
launcherType: "Nodejs",
|
|
249
|
+
shouldAddHelpers: false,
|
|
250
|
+
supportsResponseStreaming: options.streaming ?? pluginConfig.defaultSupportsResponseStreaming ?? true
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/plugins/loader.ts
|
|
256
|
+
const re_DUMMY = /* @__PURE__ */ new RegExp(`__DUMMY__$`);
|
|
257
|
+
function loaderPlugin(pluginConfig) {
|
|
258
|
+
let root;
|
|
259
|
+
return [
|
|
260
|
+
{
|
|
261
|
+
name: "vite-plugin-vercel:dummy",
|
|
262
|
+
enforce: "pre",
|
|
263
|
+
resolveId: {
|
|
264
|
+
filter: { id: re_DUMMY },
|
|
265
|
+
handler(id) {
|
|
266
|
+
return id;
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
load: {
|
|
270
|
+
filter: { id: re_DUMMY },
|
|
271
|
+
handler() {
|
|
272
|
+
return "console.log('');export default {};";
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: "vite-plugin-vercel:load-edge",
|
|
278
|
+
apply: "build",
|
|
279
|
+
resolveId: {
|
|
280
|
+
filter: { id: [/\?edge$/] },
|
|
281
|
+
async handler(id, importer, opts) {
|
|
282
|
+
const resolved = await this.resolve(id.replace(/\?edge$/, ""), importer, opts);
|
|
283
|
+
if (!resolved) return null;
|
|
284
|
+
return `${resolved.id}?edge`;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
load: {
|
|
288
|
+
filter: { id: [/\?edge$/] },
|
|
289
|
+
async handler(id) {
|
|
290
|
+
const mod = id.replace(/\?edge$/, "");
|
|
291
|
+
return `import mod from ${JSON.stringify(mod)};
|
|
292
|
+
const def = mod.fetch;
|
|
293
|
+
export default def;`;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: "vite-plugin-vercel:build-functions",
|
|
299
|
+
apply: "build",
|
|
300
|
+
applyToEnvironment(env) {
|
|
301
|
+
return env.name === "vercel_node" || env.name === "vercel_edge";
|
|
302
|
+
},
|
|
303
|
+
config: {
|
|
304
|
+
order: "post",
|
|
305
|
+
handler(config) {
|
|
306
|
+
root = config.root;
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
configEnvironment: {
|
|
310
|
+
order: "post",
|
|
311
|
+
handler(name) {
|
|
312
|
+
const isEdge = name === "vercel_edge";
|
|
313
|
+
if (name === "vercel_node" || isEdge) {
|
|
314
|
+
const entries = dedupeRoutes().filter((e) => (e.vercel?.edge ?? false) === isEdge);
|
|
315
|
+
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 }
|
|
318
|
+
} } };
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
async buildStart() {
|
|
323
|
+
const isEdge = this.environment.name === "vercel_edge";
|
|
324
|
+
const nodeVersion = await getNodeVersion(process.cwd());
|
|
325
|
+
const entries = dedupeRoutes();
|
|
326
|
+
for (const entry of entries.filter((e) => (e.vercel?.edge ?? false) === isEdge)) {
|
|
327
|
+
const isEdge$1 = this.environment.name === "vercel_edge";
|
|
328
|
+
this.emitFile({
|
|
329
|
+
type: "asset",
|
|
330
|
+
fileName: entryDestination(root ?? process.cwd(), entry, ".func/.vc-config.json"),
|
|
331
|
+
source: JSON.stringify(getVcConfig(pluginConfig, isEdge$1 ? "index.js" : "index.mjs", {
|
|
332
|
+
nodeVersion,
|
|
333
|
+
edge: isEdge$1,
|
|
334
|
+
streaming: entry.vercel?.streaming
|
|
335
|
+
}), void 0, 2)
|
|
336
|
+
});
|
|
337
|
+
if (entry.vercel?.isr) this.emitFile({
|
|
338
|
+
type: "asset",
|
|
339
|
+
fileName: entryDestination(root ?? process.cwd(), entry, ".prerender-config.json"),
|
|
340
|
+
source: JSON.stringify(vercelOutputPrerenderConfigSchema.parse(entry.vercel.isr), void 0, 2)
|
|
341
|
+
});
|
|
342
|
+
pluginConfig.rewrites ??= [];
|
|
343
|
+
for (const pattern of [entry.pattern].flat()) {
|
|
344
|
+
const source = toPathToRegexpV6(fromRou3(pattern));
|
|
345
|
+
pluginConfig.rewrites.push({
|
|
346
|
+
enforce: entry.vercel?.enforce,
|
|
347
|
+
source,
|
|
348
|
+
destination: `/${entryDestinationDefault(root ?? process.cwd(), entry)}`
|
|
349
|
+
});
|
|
350
|
+
if (entry.vercel?.headers) {
|
|
351
|
+
pluginConfig.headers ??= [];
|
|
352
|
+
pluginConfig.headers.push({
|
|
353
|
+
source,
|
|
354
|
+
headers: Object.entries(entry.vercel.headers).map(([key, value]) => ({
|
|
355
|
+
key,
|
|
356
|
+
value
|
|
357
|
+
}))
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
sharedDuringBuild: true
|
|
364
|
+
}
|
|
365
|
+
];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/plugins/react-edge.ts
|
|
370
|
+
function reactEdgePlugin() {
|
|
371
|
+
return {
|
|
372
|
+
name: "vite-plugin-vercel:react-edge",
|
|
373
|
+
applyToEnvironment(env) {
|
|
374
|
+
return env.name === "vercel_edge";
|
|
375
|
+
},
|
|
376
|
+
resolveId: {
|
|
377
|
+
order: "pre",
|
|
378
|
+
filter: { id: [/^react-dom\/server$/] },
|
|
379
|
+
handler(_id, importer, opts) {
|
|
380
|
+
return this.resolve("react-dom/server.edge", importer, opts);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/config.ts
|
|
388
|
+
function reorderEnforce(arr) {
|
|
389
|
+
return [
|
|
390
|
+
...arr.filter((r) => r.enforce === "pre"),
|
|
391
|
+
...arr.filter((r) => !r.enforce),
|
|
392
|
+
...arr.filter((r) => r.enforce === "post")
|
|
393
|
+
];
|
|
394
|
+
}
|
|
395
|
+
function getConfig(pluginConfig) {
|
|
396
|
+
const _rewrites = [...pluginConfig.rewrites ?? []];
|
|
397
|
+
const { routes, error } = getTransformedRoutes({
|
|
398
|
+
cleanUrls: pluginConfig.cleanUrls ?? true,
|
|
399
|
+
trailingSlash: pluginConfig.trailingSlash,
|
|
400
|
+
rewrites: reorderEnforce(_rewrites),
|
|
401
|
+
redirects: pluginConfig.redirects ? reorderEnforce(pluginConfig.redirects) : void 0,
|
|
402
|
+
headers: pluginConfig.headers
|
|
403
|
+
});
|
|
404
|
+
if (error) throw error;
|
|
405
|
+
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`.");
|
|
406
|
+
let userRoutes = [];
|
|
407
|
+
let buildRoutes = [];
|
|
408
|
+
if (pluginConfig.config?.routes) {
|
|
409
|
+
const norm = normalizeRoutes(pluginConfig.config.routes);
|
|
410
|
+
if (norm.error) throw norm.error;
|
|
411
|
+
userRoutes = norm.routes ?? [];
|
|
412
|
+
}
|
|
413
|
+
if (routes) {
|
|
414
|
+
const norm = normalizeRoutes(routes);
|
|
415
|
+
if (norm.error) throw norm.error;
|
|
416
|
+
buildRoutes = norm.routes ?? [];
|
|
417
|
+
}
|
|
418
|
+
const cleanRoutes = mergeRoutes({
|
|
419
|
+
userRoutes,
|
|
420
|
+
builds: [{
|
|
421
|
+
use: "@vercel/node",
|
|
422
|
+
entrypoint: "index.mjs",
|
|
423
|
+
routes: buildRoutes
|
|
424
|
+
}]
|
|
425
|
+
});
|
|
426
|
+
return vercelOutputConfigSchema.parse({
|
|
427
|
+
version: 3,
|
|
428
|
+
...pluginConfig.config,
|
|
429
|
+
routes: cleanRoutes,
|
|
430
|
+
overrides: { ...pluginConfig.config?.overrides }
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/utils/const.ts
|
|
436
|
+
const virtualEntry = "virtual:vite-plugin-vercel:entry";
|
|
437
|
+
|
|
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
|
+
//#endregion
|
|
450
|
+
//#region src/plugins/setupEnvs.ts
|
|
451
|
+
const outDir = path.posix.join(process.cwd(), ".vercel/output");
|
|
452
|
+
const DUMMY = "__DUMMY__";
|
|
453
|
+
let injected = false;
|
|
454
|
+
function setupEnvs(pluginConfig) {
|
|
455
|
+
return [
|
|
456
|
+
{
|
|
457
|
+
name: "vite-plugin-vercel:setup-envs",
|
|
458
|
+
buildApp: {
|
|
459
|
+
order: "post",
|
|
460
|
+
async handler(builder) {
|
|
461
|
+
try {
|
|
462
|
+
await builder.build(builder.environments.vercel_client);
|
|
463
|
+
} catch (e) {
|
|
464
|
+
if (e instanceof Error && e.message.includes(`Could not resolve entry module "index.html"`)) {} else throw e;
|
|
465
|
+
}
|
|
466
|
+
await builder.build(builder.environments.vercel_edge);
|
|
467
|
+
await builder.build(builder.environments.vercel_node);
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
config() {
|
|
471
|
+
if (!injected) {
|
|
472
|
+
injected = true;
|
|
473
|
+
if (pluginConfig.entries) store.entries.push(...pluginConfig.entries);
|
|
474
|
+
}
|
|
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
|
+
},
|
|
492
|
+
sharedDuringBuild: true
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
name: "vite-plugin-vercel:setup-envs:vercel_edge",
|
|
496
|
+
applyToEnvironment(env) {
|
|
497
|
+
return env.name === "vercel_edge";
|
|
498
|
+
},
|
|
499
|
+
configEnvironment(name, config, env) {
|
|
500
|
+
if (name !== "vercel_edge") return;
|
|
501
|
+
return {
|
|
502
|
+
resolve: {
|
|
503
|
+
external: edgeExternal,
|
|
504
|
+
...!(env.command === "serve") ? { conditions: edgeConditions } : {}
|
|
505
|
+
},
|
|
506
|
+
build: {
|
|
507
|
+
target: "es2022",
|
|
508
|
+
rollupOptions: {
|
|
509
|
+
input: {},
|
|
510
|
+
treeshake: { preset: "smallest" }
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
optimizeDeps: {
|
|
514
|
+
...config.optimizeDeps,
|
|
515
|
+
...this.meta.rolldownVersion ? { rolldownOptions: {
|
|
516
|
+
target: "es2022",
|
|
517
|
+
format: "esm"
|
|
518
|
+
} } : { esbuildOptions: {
|
|
519
|
+
target: "es2022",
|
|
520
|
+
format: "esm"
|
|
521
|
+
} }
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
},
|
|
525
|
+
generateBundle: {
|
|
526
|
+
order: "post",
|
|
527
|
+
async handler(_opts, bundle$1) {
|
|
528
|
+
cleanupDummy(bundle$1);
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
sharedDuringBuild: true
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: "vite-plugin-vercel:setup-envs:vercel_node",
|
|
535
|
+
applyToEnvironment(env) {
|
|
536
|
+
return env.name === "vercel_node";
|
|
537
|
+
},
|
|
538
|
+
configEnvironment(name, config) {
|
|
539
|
+
if (name !== "vercel_node") return;
|
|
540
|
+
return { optimizeDeps: { ...config.optimizeDeps } };
|
|
541
|
+
},
|
|
542
|
+
generateBundle: {
|
|
543
|
+
order: "post",
|
|
544
|
+
async handler(_opts, bundle$1) {
|
|
545
|
+
cleanupDummy(bundle$1);
|
|
546
|
+
this.emitFile({
|
|
547
|
+
type: "asset",
|
|
548
|
+
fileName: "config.json",
|
|
549
|
+
source: JSON.stringify(getConfig(pluginConfig), void 0, 2)
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
sharedDuringBuild: true
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
name: "vite-plugin-vercel:setup-envs:vercel_client",
|
|
557
|
+
applyToEnvironment(env) {
|
|
558
|
+
return env.name === "vercel_client";
|
|
559
|
+
},
|
|
560
|
+
generateBundle: { async handler(_opts, bundle$1) {
|
|
561
|
+
cleanupDummy(bundle$1);
|
|
562
|
+
const topLevelConfig = this.environment.getTopLevelConfig();
|
|
563
|
+
const clientEnv = topLevelConfig.environments.client;
|
|
564
|
+
if (clientEnv) try {
|
|
565
|
+
await cp(path.join(topLevelConfig.root, clientEnv.build.outDir), this.environment.config.build.outDir, {
|
|
566
|
+
recursive: true,
|
|
567
|
+
force: true,
|
|
568
|
+
dereference: true
|
|
569
|
+
});
|
|
570
|
+
} catch (e) {
|
|
571
|
+
if (e instanceof Error && e.message.includes("ENOENT")) {} else throw e;
|
|
572
|
+
}
|
|
573
|
+
} },
|
|
574
|
+
sharedDuringBuild: true
|
|
575
|
+
}
|
|
576
|
+
];
|
|
577
|
+
}
|
|
578
|
+
function createVercelEnvironmentOptions(overrides) {
|
|
579
|
+
return mergeConfig({
|
|
580
|
+
dev: { async createEnvironment(name, config) {
|
|
581
|
+
return createRunnableDevEnvironment(name, config);
|
|
582
|
+
} },
|
|
583
|
+
build: {
|
|
584
|
+
createEnvironment(name, config) {
|
|
585
|
+
return new BuildEnvironment(name, config);
|
|
586
|
+
},
|
|
587
|
+
outDir,
|
|
588
|
+
copyPublicDir: false,
|
|
589
|
+
rollupOptions: {
|
|
590
|
+
input: getDummyInput(),
|
|
591
|
+
output: {
|
|
592
|
+
sanitizeFileName: false,
|
|
593
|
+
sourcemap: false
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
target: "es2022",
|
|
597
|
+
emptyOutDir: false,
|
|
598
|
+
emitAssets: true
|
|
599
|
+
},
|
|
600
|
+
consumer: "server",
|
|
601
|
+
keepProcessEnv: true
|
|
602
|
+
}, overrides ?? {});
|
|
603
|
+
}
|
|
604
|
+
function getDummyInput() {
|
|
605
|
+
return { [DUMMY]: `${virtualEntry}:${DUMMY}` };
|
|
606
|
+
}
|
|
607
|
+
function cleanupDummy(bundle$1) {
|
|
608
|
+
const dummy = Object.keys(bundle$1).find((key) => key.includes("_DUMMY_"));
|
|
609
|
+
if (dummy) delete bundle$1[dummy];
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region src/plugins/index.ts
|
|
614
|
+
function vercel(pluginConfig = {}) {
|
|
615
|
+
return [
|
|
616
|
+
reactEdgePlugin(),
|
|
617
|
+
vercelCleanupPlugin(),
|
|
618
|
+
apiPlugin(pluginConfig),
|
|
619
|
+
...setupEnvs(pluginConfig),
|
|
620
|
+
...loaderPlugin(pluginConfig),
|
|
621
|
+
...bundlePlugin(),
|
|
622
|
+
catchAll(),
|
|
623
|
+
devServer()
|
|
624
|
+
];
|
|
625
|
+
}
|
|
626
|
+
var plugins_default = vercel;
|
|
627
|
+
|
|
628
|
+
//#endregion
|
|
629
|
+
export { plugins_default as default, vercel };
|
package/meta.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-vercel",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0-beta.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
"module": "./dist/index.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./dist/index.js",
|
|
12
|
-
"./
|
|
13
|
-
"./universal-middleware/dev": "./dist/universal-middleware-dev.js",
|
|
14
|
-
"./utils": "./dist/utils.js",
|
|
12
|
+
"./vite": "./dist/vite.js",
|
|
15
13
|
"./api": "./dist/api.js",
|
|
16
14
|
"./types": {
|
|
17
15
|
"types": "./dist/types.d.ts"
|
|
@@ -21,23 +19,41 @@
|
|
|
21
19
|
"author": "Joël Charles <joel.charles91@gmail.com>",
|
|
22
20
|
"repository": "https://github.com/magne4000/vite-plugin-vercel",
|
|
23
21
|
"license": "MIT",
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"vite": ">=7.1"
|
|
24
|
+
},
|
|
24
25
|
"devDependencies": {
|
|
25
|
-
"
|
|
26
|
+
"@types/node": "^22.19.3",
|
|
27
|
+
"@universal-middleware/express": "^0.4.22",
|
|
28
|
+
"@vercel/node": "^5.5.15",
|
|
29
|
+
"tsdown": "^0.18.4",
|
|
26
30
|
"typescript": "^5.9.3",
|
|
27
|
-
"vite": "^7.
|
|
31
|
+
"vite": "^7.2.4",
|
|
32
|
+
"vitest": "^4.0.16"
|
|
28
33
|
},
|
|
29
34
|
"dependencies": {
|
|
30
|
-
"@
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
35
|
+
"@manypkg/find-root": "^3.1.0",
|
|
36
|
+
"@universal-deploy/store": "^0.0.2",
|
|
37
|
+
"@universal-middleware/core": "^0.4.13",
|
|
38
|
+
"@universal-middleware/vercel": "^0.4.29",
|
|
39
|
+
"@vercel/build-utils": "^13.2.3",
|
|
40
|
+
"@vercel/nft": "^1.1.1",
|
|
41
|
+
"@vercel/routing-utils": "^5.3.1",
|
|
42
|
+
"@vite-plugin-vercel/schemas": "latest",
|
|
43
|
+
"convert-route": "^1.0.0",
|
|
44
|
+
"fast-glob": "^3.3.3",
|
|
45
|
+
"magicast": "^0.5.1",
|
|
46
|
+
"nf3": "^0.3.1",
|
|
47
|
+
"p-limit": "^7.2.0",
|
|
48
|
+
"path-to-regexp": "^8.3.0",
|
|
49
|
+
"rolldown": "^1.0.0-beta.58",
|
|
50
|
+
"strip-ansi": "^7.1.2",
|
|
51
|
+
"vite-plugin-wasm": "^3.5.0"
|
|
37
52
|
},
|
|
38
53
|
"scripts": {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
54
|
+
"dev": "tsdown --watch",
|
|
55
|
+
"build": "tsdown",
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"test:types": "tsc --noEmit"
|
|
42
58
|
}
|
|
43
59
|
}
|
package/dist/utils.d.ts
DELETED
package/dist/utils.js
DELETED