vinext 1.0.0-beta.12 → 1.0.0-beta.13

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.
Files changed (132) hide show
  1. package/README.md +39 -12
  2. package/dist/build/action-owner-manifest.js +23 -5
  3. package/dist/build/lifecycle.d.ts +42 -0
  4. package/dist/build/lifecycle.js +246 -0
  5. package/dist/build/nitro-route-rules.js +1 -1
  6. package/dist/build/pages-client-assets-module.d.ts +0 -3
  7. package/dist/build/pages-client-assets-module.js +1 -13
  8. package/dist/build/precompress.js +1 -1
  9. package/dist/build/prerender-paths.d.ts +1 -1
  10. package/dist/build/prerender-paths.js +6 -6
  11. package/dist/build/prerender-server-pool.js +1 -1
  12. package/dist/build/prerender.d.ts +1 -1
  13. package/dist/build/prerender.js +5 -5
  14. package/dist/build/preview-credentials.d.ts +1 -1
  15. package/dist/build/preview-credentials.js +2 -2
  16. package/dist/build/report.js +1 -1
  17. package/dist/build/run-prerender.d.ts +2 -2
  18. package/dist/build/run-prerender.js +5 -5
  19. package/dist/build/standalone.js +2 -2
  20. package/dist/cli-args.d.ts +5 -13
  21. package/dist/cli-args.js +2 -45
  22. package/dist/cli-dev-config.d.ts +6 -2
  23. package/dist/cli-dev-config.js +160 -3
  24. package/dist/cli.js +104 -439
  25. package/dist/config/config-matchers.js +1 -1
  26. package/dist/config/next-config.d.ts +2 -2
  27. package/dist/config/next-config.js +5 -5
  28. package/dist/config/prerender.d.ts +3 -0
  29. package/dist/config/prerender.js +8 -2
  30. package/dist/entries/app-browser-entry.js +1 -1
  31. package/dist/entries/app-rsc-entry.js +1 -1
  32. package/dist/entries/pages-client-entry.d.ts +1 -0
  33. package/dist/entries/pages-client-entry.js +17 -2
  34. package/dist/index.d.ts +6 -8
  35. package/dist/index.js +262 -101
  36. package/dist/init-cloudflare.d.ts +3 -2
  37. package/dist/init-cloudflare.js +117 -5
  38. package/dist/init-platform.d.ts +2 -0
  39. package/dist/init-platform.js +9 -3
  40. package/dist/init.d.ts +7 -5
  41. package/dist/init.js +41 -22
  42. package/dist/plugins/dynamic-preload-metadata.js +1 -1
  43. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  44. package/dist/plugins/fonts.js +1 -1
  45. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  46. package/dist/plugins/import-meta-url.js +1 -1
  47. package/dist/plugins/instrumentation-client.js +1 -1
  48. package/dist/plugins/og-assets.js +32 -13
  49. package/dist/plugins/og-harfbuzz.d.ts +24 -0
  50. package/dist/plugins/og-harfbuzz.js +260 -0
  51. package/dist/plugins/optimize-imports.js +1 -1
  52. package/dist/plugins/require-condition-resolution.js +2 -2
  53. package/dist/plugins/require-context.js +2 -2
  54. package/dist/plugins/typeof-window.js +1 -1
  55. package/dist/plugins/use-cache-callable.d.ts +0 -2
  56. package/dist/plugins/use-cache-callable.js +8 -16
  57. package/dist/plugins/worker-image-imports.js +1 -1
  58. package/dist/routing/app-route-graph.js +1 -1
  59. package/dist/routing/app-router.js +1 -1
  60. package/dist/routing/pages-router.js +1 -1
  61. package/dist/server/app-action-forwarding.js +1 -1
  62. package/dist/server/app-browser-error.js +1 -1
  63. package/dist/server/app-elements-wire.js +2 -2
  64. package/dist/server/app-middleware.js +1 -1
  65. package/dist/server/app-optimistic-routing.js +1 -1
  66. package/dist/server/app-page-dispatch.js +1 -1
  67. package/dist/server/app-page-element-builder.js +3 -2
  68. package/dist/server/app-page-probe.js +3 -3
  69. package/dist/server/app-request-stage-independent-entry.js +2 -2
  70. package/dist/server/app-route-handler-dispatch.js +1 -1
  71. package/dist/server/app-route-handler-runtime.js +1 -1
  72. package/dist/server/app-router-entry.js +2 -2
  73. package/dist/server/app-rsc-handler.d.ts +1 -1
  74. package/dist/server/app-rsc-handler.js +4 -4
  75. package/dist/server/app-rsc-response-stage.js +1 -1
  76. package/dist/server/app-rsc-route-matching.js +1 -1
  77. package/dist/server/app-server-action-execution.js +4 -4
  78. package/dist/server/artifact-compatibility.js +1 -1
  79. package/dist/server/client-reuse-manifest.js +1 -1
  80. package/dist/server/dev-lockfile.d.ts +1 -1
  81. package/dist/server/dev-lockfile.js +4 -1
  82. package/dist/server/dev-server.d.ts +1 -1
  83. package/dist/server/dev-server.js +28 -6
  84. package/dist/server/dev-stack-sourcemap.js +1 -1
  85. package/dist/server/isr-cache.js +1 -1
  86. package/dist/server/metadata-route-response.js +8 -0
  87. package/dist/server/middleware-runtime.js +3 -3
  88. package/dist/server/pages-data-route.js +1 -1
  89. package/dist/server/pages-dev-hydration.d.ts +6 -0
  90. package/dist/server/pages-dev-hydration.js +19 -7
  91. package/dist/server/pages-page-data.js +2 -2
  92. package/dist/server/pages-page-handler.js +1 -1
  93. package/dist/server/pages-page-response.js +1 -1
  94. package/dist/server/pages-request-pipeline.js +3 -3
  95. package/dist/server/pages-request-stage-entry.js +3 -3
  96. package/dist/server/pages-revalidate.js +1 -1
  97. package/dist/server/prerender-route-params.js +1 -1
  98. package/dist/server/prod-server.js +7 -7
  99. package/dist/server/request-pipeline.js +2 -2
  100. package/dist/server/socket-error-backstop.js +1 -1
  101. package/dist/shims/cache-callable-runtime.d.ts +38 -0
  102. package/dist/shims/cache-callable-runtime.js +162 -11
  103. package/dist/shims/cache-runtime.d.ts +6 -8
  104. package/dist/shims/cache-runtime.js +82 -22
  105. package/dist/shims/font-local.js +1 -1
  106. package/dist/shims/form.js +1 -1
  107. package/dist/shims/headers.js +2 -2
  108. package/dist/shims/internal/app-page-props-cache-key.d.ts +29 -0
  109. package/dist/shims/internal/app-page-props-cache-key.js +53 -1
  110. package/dist/shims/internal/format-url-object.d.ts +7 -0
  111. package/dist/shims/internal/format-url-object.js +53 -0
  112. package/dist/shims/internal/normalize-router-href.d.ts +15 -0
  113. package/dist/shims/internal/normalize-router-href.js +41 -0
  114. package/dist/shims/internal/pages-data-target.d.ts +4 -1
  115. package/dist/shims/internal/pages-data-target.js +28 -35
  116. package/dist/shims/internal/route-pattern-for-warning.d.ts +2 -2
  117. package/dist/shims/internal/route-pattern-for-warning.js +3 -3
  118. package/dist/shims/link.js +31 -92
  119. package/dist/shims/metadata.js +5 -4
  120. package/dist/shims/navigation.js +2 -2
  121. package/dist/shims/router-state.js +1 -1
  122. package/dist/shims/router.d.ts +8 -7
  123. package/dist/shims/router.js +312 -148
  124. package/dist/shims/server.js +3 -3
  125. package/dist/utils/built-asset-url.js +1 -1
  126. package/dist/utils/project.d.ts +1 -11
  127. package/dist/utils/project.js +19 -28
  128. package/dist/utils/react-version.d.ts +3 -1
  129. package/dist/utils/react-version.js +19 -1
  130. package/dist/utils/vite-cli-invocation.d.ts +21 -0
  131. package/dist/utils/vite-cli-invocation.js +144 -0
  132. package/package.json +10 -2
package/dist/cli.js CHANGED
@@ -1,35 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import path, { toSlash } from "./deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
3
- import { detectPackageManager, ensureViteConfigCompatibility, hasAppDir, hasViteConfig } from "./utils/project.js";
3
+ import { detectPackageManager, ensureViteConfigCompatibility, findViteConfigPath } from "./utils/project.js";
4
4
  import { formatReport, runCheck } from "./check.js";
5
5
  import { parseArgs } from "./cli-args.js";
6
- import { createDevServerConfigPlugin, normalizeDevServerHostname } from "./cli-dev-config.js";
7
- import { findVinextCacheConfigInPlugins, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader } from "./cache/cache-adapters-virtual.js";
8
- import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
9
- import { createRscCompatibilityId, findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
10
- import { loadDotenv } from "./config/dotenv.js";
11
- import { generateRouteTypes } from "./typegen.js";
12
- import { clearPagesClientAssetsBuildMetadata } from "./build/pages-client-assets-module.js";
13
- import { runWithPreviewBuildCredentials } from "./build/preview-credentials.js";
14
- import { findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, resolveVinextPrerenderDecision } from "./config/prerender.js";
15
- import vinext from "./index.js";
16
- import { runPrerender } from "./build/run-prerender.js";
17
- import { emitPrerenderPathManifest } from "./build/prerender-paths.js";
18
- import { getReactUpgradeDeps } from "./utils/react-version.js";
6
+ import { findViteRoot, getViteCliInvocation, valueOptionName } from "./utils/vite-cli-invocation.js";
19
7
  import { init } from "./init.js";
20
8
  import { resolveInitOptions } from "./init-platform.js";
21
- import { resolveVinextPackageRoot } from "./utils/vinext-root.js";
22
- import { emitStandaloneOutput } from "./build/standalone.js";
23
- import { cleanBuildOutput } from "./build/clean-output.js";
24
- import { formatAlreadyRunningError, tryAcquireLockfile } from "./server/dev-lockfile.js";
9
+ import { loadDotenv } from "./config/dotenv.js";
10
+ import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
11
+ import { loadNextConfig, resolveNextConfig } from "./config/next-config.js";
12
+ import { generateRouteTypes } from "./typegen.js";
25
13
  import { createRequire } from "node:module";
26
14
  import fs from "node:fs";
27
15
  import { pathToFileURL } from "node:url";
28
- import { randomBytes } from "node:crypto";
29
16
  import { execFileSync } from "node:child_process";
30
17
  //#region src/cli.ts
31
18
  /**
32
- * vinext CLI — drop-in replacement for the `next` command
19
+ * vinext CLI — migration and compatibility commands for vinext projects
33
20
  *
34
21
  * vinext dev Start development server (Vite)
35
22
  * vinext build Build for production
@@ -37,393 +24,103 @@ import { execFileSync } from "node:child_process";
37
24
  * vinext typegen Generate App Router route helper types
38
25
  * vinext lint Run linter (delegates to eslint/oxlint)
39
26
  *
40
- * Automatically configures Vite with the vinext plugin — no vite.config.ts
41
- * needed for most Next.js apps.
42
- */
43
- let _viteModule = null;
44
- /**
45
- * Dynamically load Vite from the project root. Falls back to the bundled
46
- * copy if the project doesn't have its own Vite installation.
47
- */
48
- async function loadVite() {
49
- if (_viteModule) return _viteModule;
50
- const projectRoot = process.cwd();
51
- let vitePath;
52
- try {
53
- vitePath = createRequire(path.join(projectRoot, "package.json")).resolve("vite");
54
- } catch {
55
- vitePath = "vite";
56
- }
57
- const vite = await (vitePath === "vite" ? import(vitePath) : import(pathToFileURL(vitePath).href));
58
- _viteModule = vite;
59
- return vite;
60
- }
61
- /**
62
- * Get the Vite version string. Returns "unknown" before loadVite() is called.
27
+ * The dev and build commands delegate to the project-local Vite CLI.
63
28
  */
64
- function getViteVersion() {
65
- return _viteModule?.version ?? "unknown";
66
- }
67
29
  const VERSION = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8")).version;
68
30
  const command = process.argv[2];
69
31
  const rawArgs = process.argv.slice(3);
70
- /**
71
- * Create a custom Vite logger for build output.
72
- *
73
- * By default Vite/Rollup emit a lot of build noise: version banners, progress
74
- * lines, chunk size tables, minChunkSize diagnostics, and various internal
75
- * warnings that are either not actionable or already handled by vinext at
76
- * runtime. This logger suppresses all of that while keeping the things that
77
- * actually matter:
78
- *
79
- * KEPT
80
- * ✓ N modules transformed. — confirms the transform phase completed
81
- * ✓ built in Xs — build timing (useful perf signal)
82
- * Genuine warnings/errors — anything the user may need to act on
83
- *
84
- * SUPPRESSED (info)
85
- * vite vX.Y.Z building... — Vite version banner
86
- * transforming... / rendering chunks... / computing gzip size...
87
- * Initially, there are N chunks... — Rollup minChunkSize diagnostics
88
- * After merging chunks, there are...
89
- * X are below minChunkSize.
90
- * Blank lines
91
- * Chunk/asset size table rows — e.g. " dist/client/assets/foo.js 42 kB"
92
- * [rsc] / [ssr] / [client] / [worker] — RSC plugin env section headers
93
- *
94
- * SUPPRESSED (warn)
95
- * "dynamic import will not move module into another chunk" — internal chunking note
96
- * "X is not exported by virtual:vinext-*" — handled gracefully at runtime
97
- */
98
- function createBuildLogger(vite) {
99
- const logger = vite.createLogger("info", { allowClearScreen: false });
100
- const originalInfo = logger.info.bind(logger);
101
- const originalWarn = logger.warn.bind(logger);
102
- const strip = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
103
- logger.info = (msg, options) => {
104
- const plain = strip(msg);
105
- if (plain.trimStart().startsWith("✓")) {
106
- originalInfo(msg, options);
107
- return;
108
- }
109
- if (/^vite v\d/.test(plain.trim())) return;
110
- if (/^(transforming|rendering chunks|computing gzip size)/.test(plain.trim())) return;
111
- if (/^(Initially,|After merging|are below minChunkSize)/.test(plain.trim())) return;
112
- if (/^\s*$/.test(plain)) return;
113
- if (/^\s*(dist\/|\.\/)/.test(plain)) return;
114
- // @vitejs/plugin-rsc environment section headers ("[rsc]", "[ssr]", "[client]", "[worker]").
115
- if (/^\s*\[(rsc|ssr|client|worker)\]/.test(plain)) return;
116
- originalInfo(msg, options);
117
- };
118
- logger.warn = (msg, options) => {
119
- const plain = strip(msg);
120
- if (plain.includes("dynamic import will not move module into another chunk")) return;
121
- if (plain.includes("is not exported by") && plain.includes("virtual:vinext")) return;
122
- originalWarn(msg, options);
123
- };
124
- return logger;
125
- }
126
- function hasPagesDir() {
127
- return fs.existsSync(path.join(process.cwd(), "pages")) || fs.existsSync(path.join(process.cwd(), "src", "pages"));
128
- }
129
- async function loadBuildViteConfigMetadata(vite, root, mode) {
130
- if (!hasViteConfig(root)) return {
131
- cacheConfig: null,
132
- nextConfig: null,
133
- prerenderConfig: null,
134
- routeRootConfig: null
135
- };
136
- const loaded = await vite.loadConfigFromFile({
137
- command: "build",
138
- mode
139
- }, void 0, root);
140
- const emptyOutDir = loaded?.config.build?.emptyOutDir;
141
- return {
142
- cacheConfig: await findVinextCacheConfigInPlugins(loaded?.config.plugins),
143
- emptyOutDir: typeof emptyOutDir === "boolean" ? emptyOutDir : void 0,
144
- nextConfig: await findVinextNextConfigInPlugins(loaded?.config.plugins),
145
- prerenderConfig: await findVinextPrerenderConfigInPlugins(loaded?.config.plugins),
146
- routeRootConfig: await findVinextRouteRootConfigInPlugins(loaded?.config.plugins)
147
- };
32
+ const retiredVinextFlags = {
33
+ "-p": "This was a dev-server option; use --port with Vite dev instead.",
34
+ "-H": "This was a dev-server option; use --host with Vite dev instead.",
35
+ "--hostname": "This was a dev-server option; use --host with Vite dev instead.",
36
+ "--turbopack": "This was a no-op: vinext always uses Vite.",
37
+ "--experimental-https": "This was a no-op. Configure server.https in vite.config.ts for HTTPS.",
38
+ "--verbose": "Vite controls its own output; use --debug for more detail.",
39
+ "--prerender-all": "Configure vinext({ prerender: { routes: \"*\" } }) in vite.config.ts.",
40
+ "--prerender-concurrency": "Configure vinext({ prerender: { routes: \"*\", concurrency: 4 } }) in vite.config.ts.",
41
+ "--precompress": "Configure vinext({ precompress: true }) in vite.config.ts."
42
+ };
43
+ function rejectRetiredVinextFlags() {
44
+ for (const arg of rawArgs) {
45
+ if (arg === "--") break;
46
+ const flag = arg.split("=", 1)[0];
47
+ const reason = retiredVinextFlags[flag];
48
+ if (reason) throw new Error(`[vinext] ${flag} is no longer supported. ${reason}`);
49
+ }
148
50
  }
149
- /**
150
- * Build the Vite config automatically. If a vite.config.ts exists in the
151
- * project, Vite will merge our config with it (theirs takes precedence).
152
- * If there's no vite.config, this provides everything needed.
153
- */
154
- function buildViteConfig(overrides = {}, logger, mode) {
155
- if (hasViteConfig(process.cwd())) return {
156
- root: process.cwd(),
157
- ...mode ? { mode } : {},
158
- ...logger ? { customLogger: logger } : {},
159
- ...overrides
160
- };
161
- return {
162
- root: process.cwd(),
163
- ...mode ? { mode } : {},
164
- configFile: false,
165
- plugins: [vinext()],
166
- resolve: { dedupe: [
167
- "react",
168
- "react-dom",
169
- "react/jsx-runtime",
170
- "react/jsx-dev-runtime"
171
- ] },
172
- ...logger ? { customLogger: logger } : {},
173
- ...overrides
51
+ function configPreflight(command) {
52
+ const cwd = process.cwd();
53
+ const { root: positionalRoot, shouldPreflight } = findViteRoot(command, rawArgs);
54
+ const root = positionalRoot ? path.resolve(cwd, positionalRoot) : cwd;
55
+ if (!shouldPreflight) return { root };
56
+ let explicitConfig;
57
+ let explicitConfigCount = 0;
58
+ for (let index = 0; index < rawArgs.length; index += 1) {
59
+ const arg = rawArgs[index];
60
+ if (arg === "--") break;
61
+ if (valueOptionName(arg) !== "--config" && valueOptionName(arg) !== "-c") continue;
62
+ if (++explicitConfigCount > 1) return { root };
63
+ explicitConfig = arg.includes("=") ? arg.slice(arg.indexOf("=") + 1) : rawArgs[++index];
64
+ if (!explicitConfig || explicitConfig.startsWith("-")) return { root };
65
+ }
66
+ const configPath = explicitConfig ? path.resolve(cwd, explicitConfig) : findViteConfigPath(root);
67
+ if (configPath && fs.existsSync(configPath)) return {
68
+ root,
69
+ configPath
174
70
  };
71
+ throw new Error(`[vinext] No Vite config was found for this project. Run \`vinext init\` to create one, then retry \`vinext ${command}\`.`);
175
72
  }
176
- /**
177
- * Ensure the project's package.json has `"type": "module"` before Vite loads
178
- * the vite.config.ts. This prevents the esbuild CJS-bundling path that Vite
179
- * takes for projects without `"type": "module"`, which produces a `.mjs` temp
180
- * file containing `require()` calls — calls that fail on Node 22 when
181
- * targeting pure-ESM packages like `@cloudflare/vite-plugin`.
182
- *
183
- * This mirrors what `vinext init` does, but is applied lazily at dev/build
184
- * time for projects that were set up before `vinext init` added the step, or
185
- * that were migrated manually.
186
- */
187
- function applyViteConfigCompatibility(root) {
188
- const result = ensureViteConfigCompatibility(root);
189
- if (!result) return;
190
- for (const [oldName, newName] of result.renamed) console.warn(` [vinext] Renamed ${oldName} → ${newName} (required for "type": "module")`);
191
- if (result.addedTypeModule) console.warn(" [vinext] Added \"type\": \"module\" to package.json (required for Vite ESM config loading).\n Run `vinext init` to review all project configuration.");
192
- }
193
- async function dev() {
194
- const parsed = parseArgs(rawArgs);
195
- if (parsed.help) return printHelp("dev");
196
- loadDotenv({
197
- root: process.cwd(),
198
- mode: "development"
199
- });
200
- applyViteConfigCompatibility(process.cwd());
201
- const vite = await loadVite();
202
- const initialPort = parsed.port ?? 3e3;
203
- const initialHost = parsed.hostname ?? "localhost";
204
- let lockfile;
205
- const startedAt = Date.now();
206
- if (process.env.VINEXT_NO_DEV_LOCK !== "1") {
207
- const root = process.cwd();
208
- const initialDisplayHost = initialHost === "0.0.0.0" ? "localhost" : initialHost;
209
- const acquired = tryAcquireLockfile({
210
- root,
211
- info: {
212
- pid: process.pid,
213
- port: initialPort,
214
- hostname: initialHost,
215
- appUrl: `http://${initialDisplayHost}:${initialPort}`,
216
- startedAt,
217
- cwd: root
218
- }
219
- });
220
- if (!acquired.ok) {
221
- console.error("\n " + formatAlreadyRunningError({
222
- existing: acquired.existing,
223
- cwd: root,
224
- lockfilePath: acquired.lockfilePath
225
- }).replace(/\n/g, "\n ") + "\n");
226
- process.exit(1);
227
- }
228
- lockfile = acquired.lockfile;
229
- }
230
- console.log(`\n vinext dev (Vite ${getViteVersion()})\n`);
231
- const config = buildViteConfig();
232
- (config.plugins ??= []).push(createDevServerConfigPlugin(parsed));
233
- let server;
234
- try {
235
- server = await vite.createServer(config);
236
- const port = server.config.server.port ?? 3e3;
237
- const host = normalizeDevServerHostname(server.config.server.host);
238
- lockfile?.update({
239
- pid: process.pid,
240
- port,
241
- hostname: host,
242
- appUrl: `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`,
243
- startedAt,
244
- cwd: process.cwd()
245
- });
246
- await server.listen();
247
- } catch (err) {
248
- lockfile?.release();
249
- throw err;
250
- }
251
- server.printUrls();
252
- if (lockfile) {
253
- const configuredPort = server.config.server.port ?? 3e3;
254
- const configuredHost = normalizeDevServerHostname(server.config.server.host);
255
- const resolved = server.resolvedUrls?.local[0];
256
- let actualPort = configuredPort;
257
- let appUrl;
258
- if (resolved) {
259
- appUrl = resolved.replace(/\/$/, "");
260
- try {
261
- const parsed = new URL(appUrl);
262
- actualPort = parsed.port ? Number.parseInt(parsed.port, 10) : actualPort;
263
- } catch {}
264
- } else {
265
- const address = server.httpServer?.address();
266
- actualPort = typeof address === "object" && address ? address.port : configuredPort;
267
- appUrl = `http://${configuredHost === "0.0.0.0" ? "localhost" : configuredHost}:${actualPort}`;
73
+ function resolveProjectViteCli(root) {
74
+ const cwd = process.cwd();
75
+ const candidates = /* @__PURE__ */ new Set([root, cwd]);
76
+ for (const candidate of candidates) {
77
+ const require = createRequire(path.join(candidate, "package.json"));
78
+ let packagePath;
79
+ try {
80
+ packagePath = require.resolve("vite/package.json");
81
+ } catch {
82
+ continue;
268
83
  }
269
- lockfile.update({
270
- pid: process.pid,
271
- port: actualPort,
272
- hostname: configuredHost,
273
- appUrl,
274
- startedAt,
275
- cwd: process.cwd()
276
- });
84
+ const packageRoot = path.dirname(packagePath);
85
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
86
+ const bin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.vite;
87
+ const cliPath = bin ? path.resolve(packageRoot, bin) : path.join(path.dirname(require.resolve("vite")), "cli.js");
88
+ if (fs.existsSync(cliPath)) return cliPath;
277
89
  }
90
+ throw new Error("[vinext] Could not resolve the project-local Vite CLI. Run `vinext init` to install it.");
278
91
  }
279
- async function buildApp() {
280
- const parsed = parseArgs(rawArgs);
281
- if (parsed.help) return printHelp("build");
282
- const buildMode = parsed.mode ?? "production";
283
- if (!process.env.NODE_ENV) Reflect.set(process.env, "NODE_ENV", "production");
284
- if (parsed.precompress) process.env.VINEXT_PRECOMPRESS = "1";
285
- loadDotenv({
286
- root: process.cwd(),
287
- mode: buildMode
288
- });
289
- applyViteConfigCompatibility(process.cwd());
290
- const vite = await loadVite();
291
- const withBuildBundlerOptions = (bundlerOptions) => ({ rolldownOptions: bundlerOptions });
292
- console.log(`\n vinext build (Vite ${getViteVersion()})\n`);
293
- const root = toSlash(process.cwd());
294
- const isApp = hasAppDir(root);
295
- const buildConfigMetadata = await loadBuildViteConfigMetadata(vite, root, buildMode);
296
- const rawNextConfig = buildConfigMetadata.nextConfig ? await resolveNextConfigInput(buildConfigMetadata.nextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(root, PHASE_PRODUCTION_BUILD);
297
- const resolvedNextConfig = await resolveNextConfig(rawNextConfig, root);
298
- process.env.__VINEXT_SHARED_BUILD_ID = resolvedNextConfig.buildId;
299
- process.env.__VINEXT_SHARED_RSC_COMPATIBILITY_ID = createRscCompatibilityId(resolvedNextConfig);
300
- process.env.__VINEXT_SHARED_RSC_BUILD_IDENTITY = randomBytes(16).toString("hex");
301
- if (!process.env.__VINEXT_SHARED_REVALIDATE_SECRET) process.env.__VINEXT_SHARED_REVALIDATE_SECRET = randomBytes(32).toString("hex");
302
- if (!process.env.__VINEXT_SHARED_PRERENDER_SECRET) process.env.__VINEXT_SHARED_PRERENDER_SECRET = randomBytes(32).toString("hex");
303
- const outputMode = resolvedNextConfig.output;
304
- const distDir = path.resolve(root, "dist");
305
- if (outputMode === "standalone") {
306
- const vinextDistDir = path.join(resolveVinextPackageRoot(), "dist");
307
- if (!fs.existsSync(vinextDistDir)) {
308
- console.error(` Error: vinext dist/ not found at ${vinextDistDir}. Run \`pnpm run build\` in the vinext package first.`);
309
- process.exit(1);
310
- }
311
- }
312
- const logger = parsed.verbose ? vite.createLogger("info", { allowClearScreen: false }) : createBuildLogger(vite);
313
- if (isApp) {
314
- const reactUpgrade = getReactUpgradeDeps(process.cwd());
315
- if (reactUpgrade.length > 0) {
316
- const [pm, ...pmArgs] = detectPackageManager(process.cwd()).replace(/ -D$/, "").split(" ");
317
- console.log(" Upgrading React for RSC compatibility...");
318
- execFileSync(pm, [...pmArgs, ...reactUpgrade], {
319
- cwd: process.cwd(),
320
- stdio: "inherit",
321
- shell: process.platform === "win32"
92
+ async function proxyVite(command) {
93
+ console.warn(`[vinext] Tip: migrate from \`vinext ${command}\` to \`vite ${command}\`.`);
94
+ rejectRetiredVinextFlags();
95
+ const { root, configPath } = configPreflight(command);
96
+ const cliPath = resolveProjectViteCli(root);
97
+ process.argv = [
98
+ process.execPath,
99
+ cliPath,
100
+ command,
101
+ ...rawArgs
102
+ ];
103
+ if (configPath) {
104
+ const invocation = getViteCliInvocation();
105
+ if (invocation) {
106
+ if (!process.env.NODE_ENV) Reflect.set(process.env, "NODE_ENV", command === "build" ? "production" : invocation.mode === "test" ? "test" : "development");
107
+ loadDotenv({
108
+ root,
109
+ mode: invocation.mode
322
110
  });
323
111
  }
324
- }
325
- cleanBuildOutput({
326
- root,
327
- outDir: distDir,
328
- emptyOutDir: buildConfigMetadata.emptyOutDir
329
- });
330
- const isHybrid = isApp && hasPagesDir();
331
- const pagesClientAssetsBuildSession = isHybrid ? randomBytes(16).toString("hex") : null;
332
- if (pagesClientAssetsBuildSession) process.env.__VINEXT_PAGES_CLIENT_ASSETS_BUILD_SESSION = pagesClientAssetsBuildSession;
333
- await runWithPreviewBuildCredentials(async () => {
334
- try {
335
- const config = buildViteConfig({}, logger, buildMode);
336
- await (await vite.createBuilder(config)).buildApp();
337
- if (isHybrid) {
338
- console.log(" Building Pages Router server (hybrid)...");
339
- const root = process.cwd();
340
- let userTransformPlugins = [];
341
- if (hasViteConfig(process.cwd())) {
342
- const loaded = await vite.loadConfigFromFile({
343
- command: "build",
344
- mode: buildMode,
345
- isSsrBuild: true
346
- }, void 0, root);
347
- if (loaded?.config.plugins) userTransformPlugins = loaded.config.plugins.flat(Infinity).filter((p) => !!p && typeof p.name === "string" && !p.name.startsWith("vinext:") &&
348
- // @vitejs/plugin-react — auto-registered by vinext
349
- !p.name.startsWith("vite:react") &&
350
- // @vitejs/plugin-rsc and its sub-plugins — App Router only
351
- !p.name.startsWith("rsc:") && p.name !== "vite-rsc-load-module-dev-proxy" && !p.name.startsWith("vite-plugin-cloudflare"));
352
- }
353
- await vite.build({
354
- root,
355
- mode: buildMode,
356
- configFile: false,
357
- plugins: [...userTransformPlugins, vinext({ disableAppRouter: true })],
358
- resolve: { dedupe: [
359
- "react",
360
- "react-dom",
361
- "react/jsx-runtime",
362
- "react/jsx-dev-runtime"
363
- ] },
364
- ...logger ? { customLogger: logger } : {},
365
- build: {
366
- outDir: "dist/server",
367
- emptyOutDir: false,
368
- ssr: "virtual:vinext-server-entry",
369
- ...withBuildBundlerOptions({ output: { entryFileNames: "entry.js" } })
370
- }
371
- });
372
- }
373
- } finally {
374
- if (pagesClientAssetsBuildSession) {
375
- clearPagesClientAssetsBuildMetadata(pagesClientAssetsBuildSession);
376
- if (process.env.__VINEXT_PAGES_CLIENT_ASSETS_BUILD_SESSION === pagesClientAssetsBuildSession) delete process.env.__VINEXT_PAGES_CLIENT_ASSETS_BUILD_SESSION;
112
+ if (configPath === findViteConfigPath(root)) {
113
+ const migrated = ensureViteConfigCompatibility(root);
114
+ if (migrated) {
115
+ for (const [oldName, newName] of migrated.renamed) console.warn(` [vinext] Renamed ${oldName} → ${newName} (required for "type": "module")`);
116
+ console.warn(" [vinext] Added \"type\": \"module\" to package.json (required for Vite ESM config loading).\n Run `vinext init` to review all project configuration.");
377
117
  }
378
118
  }
379
- });
380
- if (outputMode === "standalone") {
381
- const standalone = emitStandaloneOutput({
382
- root: process.cwd(),
383
- outDir: distDir
384
- });
385
- console.log(` Generated standalone output in ${path.relative(process.cwd(), standalone.standaloneDir)}/`);
386
- console.log(" Start it with: node dist/standalone/server.js\n");
387
- return process.exit(0);
388
- }
389
- let prerenderResult;
390
- const prerenderDecision = resolveVinextPrerenderDecision({
391
- prerenderAllFlag: parsed.prerenderAll,
392
- vinextPrerenderConfig: buildConfigMetadata.prerenderConfig,
393
- nextOutput: resolvedNextConfig.output
394
- });
395
- if (prerenderDecision) {
396
- if (resolvedNextConfig.enablePrerenderSourceMaps) {
397
- process.setSourceMapsEnabled(true);
398
- Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 50);
399
- }
400
- process.stdout.write("\x1B[0m");
401
- console.log(` ${formatVinextPrerenderLabel(prerenderDecision)}`);
402
- prerenderResult = await runPrerender({
403
- root,
404
- concurrency: parsed.prerenderConcurrency,
405
- nextConfig: resolvedNextConfig,
406
- routeRootConfig: buildConfigMetadata.routeRootConfig
407
- });
408
- await emitPrerenderPathManifest({
409
- root,
410
- nextConfig: resolvedNextConfig,
411
- buildIdentity: hasBuildIdentityResponseHeader(buildConfigMetadata.cacheConfig) ? "response-header" : void 0,
412
- responseVary: hasVerbatimResponseVary(buildConfigMetadata.cacheConfig) ? "verbatim" : void 0,
413
- requestRouting: hasUncachedRequestRouting(buildConfigMetadata.cacheConfig) ? "uncached-stage" : void 0,
414
- isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(buildConfigMetadata.cacheConfig, name),
415
- routeRootConfig: buildConfigMetadata.routeRootConfig
416
- });
417
119
  }
418
- process.stdout.write("\x1B[0m");
419
- const { printBuildReport } = await import("./build/report.js");
420
- await printBuildReport({
421
- root,
422
- pageExtensions: resolvedNextConfig.pageExtensions,
423
- prerenderResult: prerenderResult ?? void 0
424
- });
425
- console.log("\n Build complete. Run `vinext start` to start the production server.\n");
426
- process.exit(0);
120
+ await import(
121
+ /* @vite-ignore */
122
+ pathToFileURL(cliPath).href
123
+ );
427
124
  }
428
125
  async function start() {
429
126
  const parsed = parseArgs(rawArgs);
@@ -514,55 +211,20 @@ async function initCommand() {
514
211
  const parsed = parseArgs(rawArgs);
515
212
  if (parsed.help) return printHelp("init");
516
213
  console.log(`\n vinext init\n`);
517
- const port = parsed.port ?? 3001;
518
214
  const skipCheck = rawArgs.includes("--skip-check");
519
215
  const force = rawArgs.includes("--force");
216
+ const install = !rawArgs.includes("--no-install");
520
217
  const initOptions = await resolveInitOptions(rawArgs);
521
218
  await init({
522
219
  root: process.cwd(),
523
- port,
220
+ port: parsed.port,
524
221
  skipCheck,
525
222
  force,
223
+ install,
526
224
  ...initOptions
527
225
  });
528
226
  }
529
227
  function printHelp(cmd) {
530
- if (cmd === "dev") {
531
- console.log(`
532
- vinext dev - Start development server
533
-
534
- Usage: vinext dev [options]
535
-
536
- Options:
537
- -p, --port <port> Port to listen on (default: 3000)
538
- -H, --hostname <host> Hostname to bind to (default: localhost)
539
- --turbopack Accepted for compatibility (no-op, Vite is always used)
540
- -h, --help Show this help
541
- `);
542
- return;
543
- }
544
- if (cmd === "build") {
545
- console.log(`
546
- vinext build - Build for production
547
-
548
- Usage: vinext build [options]
549
-
550
- Automatically detects App Router (app/) or Pages Router (pages/) and
551
- runs the appropriate multi-environment build via Vite.
552
- If next.config sets output: "standalone", also emits dist/standalone/server.js.
553
-
554
- Options:
555
- --verbose Show full Vite/Rollup build output (suppressed by default)
556
- --prerender-all Pre-render discovered routes after building. Equivalent
557
- to vinext({ prerender: true }) and takes priority.
558
- --prerender-concurrency <count>
559
- Maximum number of routes to pre-render in parallel
560
- --mode <mode> Load .env.<mode>* files and pass mode to Vite
561
- --precompress Precompress static assets at build time (.br, .gz, .zst)
562
- -h, --help Show this help
563
- `);
564
- return;
565
- }
566
228
  if (cmd === "start") {
567
229
  console.log(`
568
230
  vinext start - Start production server
@@ -607,15 +269,18 @@ function printHelp(cmd) {
607
269
  setup continues to work alongside vinext.
608
270
 
609
271
  Options:
610
- -p, --port <port> Dev server port for the vinext script (default: 3001)
272
+ -p, --port <port> Dev server port for the generated Vite script (default: 3001)
611
273
  --skip-check Skip the compatibility check step
274
+ --no-install Update dependency entries without installing them
612
275
  --force Overwrite existing vite.config.ts
613
276
  --platform <target> Deployment target: cloudflare or node
614
- --prerender Configure vinext build to pre-render all static routes
277
+ --prerender Configure Vite builds to pre-render all static routes
615
278
  (default: prompt, with No selected by default)
616
279
  --experimental-warm-cdn-cache
617
280
  Add experimental CDN pre-warming to the Cloudflare deploy script
618
281
  (Response Store or Workers Cache, default: prompt with No)
282
+ --experimental-cf Generate cloudflare.config.ts with the v2 Cloudflare Vite plugin
283
+ and cf CLI instead of Wrangler config and scripts
619
284
  --cdn-cache <type> Cloudflare CDN cache: none, response-store, workers-cache, or data-cache
620
285
  (default: none; response-store is the default cache choice)
621
286
  --response-store-mode <type>
@@ -695,7 +360,7 @@ function printHelp(cmd) {
695
360
 
696
361
  Examples:
697
362
  vinext dev Start dev server on port 3000
698
- vinext dev -p 4000 Start dev server on port 4000
363
+ vinext dev --port 4000 Start dev server on port 4000
699
364
  vinext build Build for production
700
365
  vinext typegen Generate route helper types
701
366
  vinext start Start production server
@@ -705,8 +370,8 @@ function printHelp(cmd) {
705
370
  npx @vinext/cloudflare deploy Deploy to Cloudflare Workers
706
371
  vp exec vinext-cloudflare deploy Deploy to Cloudflare Workers with Vite+
707
372
 
708
- vinext is a drop-in replacement for the \`next\` CLI.
709
- No vite.config.ts needed — just run \`vinext dev\` in your Next.js project.
373
+ The dev and build commands are thin proxies to the project-local Vite CLI.
374
+ Run \`vinext init\` first if the project does not have a Vite config.
710
375
  `);
711
376
  }
712
377
  if (command === "--version" || command === "-v") {
@@ -719,14 +384,14 @@ if (command === "--help" || command === "-h" || !command) {
719
384
  }
720
385
  switch (command) {
721
386
  case "dev":
722
- dev().catch((e) => {
723
- console.error(e);
387
+ proxyVite("dev").catch((error) => {
388
+ console.error(error instanceof Error ? error.message : error);
724
389
  process.exit(1);
725
390
  });
726
391
  break;
727
392
  case "build":
728
- buildApp().catch((e) => {
729
- console.error(e);
393
+ proxyVite("build").catch((error) => {
394
+ console.error(error instanceof Error ? error.message : error);
730
395
  process.exit(1);
731
396
  });
732
397
  break;
@@ -1,7 +1,7 @@
1
- import { normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
2
1
  import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
3
2
  import { buildRequestHeadersFromMiddlewareResponse, getUnconsumedMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
4
3
  import { analyzeRegexSafety } from "../utils/regex-safety.js";
4
+ import { normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
5
5
  import { isExternalUrl } from "../utils/external-url.js";
6
6
  //#region src/config/config-matchers.ts
7
7
  /**