@nuxt/vite-builder-nightly 4.3.0-29430616.754c35a4 → 4.3.0-29430640.29b20b87

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/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import fs, { existsSync, readFileSync } from 'node:fs';
2
2
  import { performance } from 'node:perf_hooks';
3
3
  import * as vite from 'vite';
4
4
  import { isCSSRequest, createLogger, mergeConfig, createBuilder, createServer } from 'vite';
5
- import { dirname, normalize, join, resolve, relative, basename, isAbsolute } from 'pathe';
5
+ import { normalize, join, relative, dirname, basename, resolve, isAbsolute } from 'pathe';
6
6
  import { tryUseNuxt, useNitro, logger, useNuxt, resolvePath, getLayerDirectories, createIsIgnored } from '@nuxt/kit';
7
7
  import { findStaticImports, sanitizeFilePath } from 'mlly';
8
8
  import viteJsxPlugin from '@vitejs/plugin-vue-jsx';
@@ -24,7 +24,7 @@ import { provider, hasTTY, isCI } from 'std-env';
24
24
  import { colorize } from 'consola/utils';
25
25
  import escapeStringRegexp from 'escape-string-regexp';
26
26
  import { transform } from 'esbuild';
27
- import defu from 'defu';
27
+ import { defu } from 'defu';
28
28
  import { getPort } from 'get-port-please';
29
29
  import { resolveTSConfig, readTSConfig } from 'pkg-types';
30
30
  import { serialize } from 'seroval';
@@ -205,12 +205,6 @@ function ModulePreloadPolyfillPlugin() {
205
205
  };
206
206
  }
207
207
 
208
- let _distDir = dirname(fileURLToPath(import.meta.url));
209
- if (/(?:chunks|shared)$/.test(_distDir)) {
210
- _distDir = dirname(_distDir);
211
- }
212
- const distDir = _distDir;
213
-
214
208
  function getManifest(nuxt, viteServer, clientEntry) {
215
209
  const css = /* @__PURE__ */ new Set();
216
210
  const ssrServer = nuxt.options.experimental.viteEnvironmentApi ? viteServer.environments.ssr : viteServer;
@@ -557,14 +551,17 @@ function sendError(socket, id, error) {
557
551
  });
558
552
  }
559
553
  async function writeDevServer(nuxt) {
560
- const serverResolvedPath = resolve(distDir, "runtime/vite-node.mjs");
561
- const manifestResolvedPath = resolve(distDir, "runtime/client.manifest.mjs");
554
+ const serverResolvedPath = resolveModulePath("#vite-node-entry", { from: import.meta.url });
555
+ const fetchResolvedPath = resolveModulePath("#vite-node", { from: import.meta.url });
562
556
  const serverDist = join(nuxt.options.buildDir, "dist/server");
563
557
  await mkdir(serverDist, { recursive: true });
564
558
  await Promise.all([
565
559
  writeFile(join(serverDist, "server.mjs"), `export { default } from ${JSON.stringify(pathToFileURL(serverResolvedPath).href)}`),
566
560
  writeFile(join(serverDist, "client.precomputed.mjs"), `export default undefined`),
567
- writeFile(join(serverDist, "client.manifest.mjs"), `export { default } from ${JSON.stringify(pathToFileURL(manifestResolvedPath).href)}`)
561
+ writeFile(join(serverDist, "client.manifest.mjs"), `
562
+ import { viteNodeFetch } from ${JSON.stringify(pathToFileURL(fetchResolvedPath))}
563
+ export default () => viteNodeFetch.getManifest()
564
+ `)
568
565
  ]);
569
566
  }
570
567
 
@@ -1924,6 +1921,12 @@ function LayerDepOptimizePlugin(nuxt) {
1924
1921
  }
1925
1922
  }
1926
1923
 
1924
+ let _distDir = dirname(fileURLToPath(import.meta.url));
1925
+ if (/(?:chunks|shared)$/.test(_distDir)) {
1926
+ _distDir = dirname(_distDir);
1927
+ }
1928
+ const distDir = _distDir;
1929
+
1927
1930
  function EnvironmentsPlugin(nuxt) {
1928
1931
  const fileNames = withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, "[hash].js"));
1929
1932
  const clientOutputDir = join(useNitro().options.output.publicDir, nuxt.options.app.buildAssetsDir);
@@ -0,0 +1,5 @@
1
+ import { NuxtSSRContext } from 'nuxt/app';
2
+
3
+ declare const _default: (ssrContext: NuxtSSRContext) => Promise<any>;
4
+
5
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { NuxtSSRContext } from 'nuxt/app';
2
+
3
+ declare const _default: (ssrContext: NuxtSSRContext) => Promise<any>;
4
+
5
+ export { _default as default };
@@ -0,0 +1,91 @@
1
+ import process from 'node:process';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { createError } from 'h3';
4
+ import { ViteNodeRunner } from 'vite-node/client';
5
+ import { consola } from 'consola';
6
+ import { viteNodeOptions, viteNodeFetch } from '#vite-node';
7
+
8
+ const runner = createRunner();
9
+ let render;
10
+ const viteNodeEntry = async (ssrContext) => {
11
+ process.server = true;
12
+ import.meta.server = true;
13
+ const invalidates = await viteNodeFetch.getInvalidates();
14
+ const updates = runner.moduleCache.invalidateDepTree(invalidates);
15
+ const start = performance.now();
16
+ render = updates.has(viteNodeOptions.entryPath) || !render ? (await runner.executeFile(viteNodeOptions.entryPath)).default : render;
17
+ if (updates.size) {
18
+ const time = Math.round((performance.now() - start) * 1e3) / 1e3;
19
+ consola.success(`Vite server hmr ${updates.size} files`, time ? `in ${time}ms` : "");
20
+ }
21
+ const result = await render(ssrContext);
22
+ return result;
23
+ };
24
+ function createRunner() {
25
+ return new ViteNodeRunner({
26
+ root: viteNodeOptions.root,
27
+ // Equals to Nuxt `srcDir`
28
+ base: viteNodeOptions.base,
29
+ async resolveId(id, importer) {
30
+ return await viteNodeFetch.resolveId(id, importer);
31
+ },
32
+ async fetchModule(id) {
33
+ id = id.replace(/\/\//g, "/");
34
+ return await viteNodeFetch.fetchModule(id).catch((err) => {
35
+ const errorData = err?.data?.data;
36
+ if (!errorData) {
37
+ throw err;
38
+ }
39
+ let _err;
40
+ try {
41
+ const { message, stack } = formatViteError(errorData, id);
42
+ _err = createError({
43
+ statusMessage: "Vite Error",
44
+ message,
45
+ stack
46
+ });
47
+ } catch (formatError) {
48
+ consola.warn("Internal nuxt error while formatting vite-node error. Please report this!", formatError);
49
+ const message = `[vite-node] [TransformError] ${errorData?.message || "-"}`;
50
+ consola.error(message, errorData);
51
+ throw createError({
52
+ statusMessage: "Vite Error",
53
+ message,
54
+ stack: `${message}
55
+ at ${id}
56
+ ` + (errorData?.stack || "")
57
+ });
58
+ }
59
+ throw _err;
60
+ });
61
+ }
62
+ });
63
+ }
64
+ function formatViteError(errorData, id) {
65
+ const errorCode = errorData.name || errorData.reasonCode || errorData.code;
66
+ const frame = errorData.frame || errorData.source || errorData.pluginCode;
67
+ const getLocId = (locObj = {}) => locObj.file || locObj.id || locObj.url || id || "";
68
+ const getLocPos = (locObj = {}) => locObj.line ? `${locObj.line}:${locObj.column || 0}` : "";
69
+ const locId = getLocId(errorData.loc) || getLocId(errorData.location) || getLocId(errorData.input) || getLocId(errorData);
70
+ const locPos = getLocPos(errorData.loc) || getLocPos(errorData.location) || getLocPos(errorData.input) || getLocPos(errorData);
71
+ const loc = locId.replace(process.cwd(), ".") + (locPos ? `:${locPos}` : "");
72
+ const message = [
73
+ "[vite-node]",
74
+ errorData.plugin && `[plugin:${errorData.plugin}]`,
75
+ errorCode && `[${errorCode}]`,
76
+ loc,
77
+ errorData.reason && `: ${errorData.reason}`,
78
+ frame && `<br><pre>${frame.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</pre><br>`
79
+ ].filter(Boolean).join(" ");
80
+ const stack = [
81
+ message,
82
+ `at ${loc}`,
83
+ errorData.stack
84
+ ].filter(Boolean).join("\n");
85
+ return {
86
+ message,
87
+ stack
88
+ };
89
+ }
90
+
91
+ export { viteNodeEntry as default };
@@ -0,0 +1,34 @@
1
+ import { Socket } from 'node:net';
2
+ import { PluginContainer } from 'vite';
3
+ import { FetchResult } from 'vite-node';
4
+ import { Manifest } from 'vue-bundle-renderer';
5
+
6
+ type ResolveIdResponse = Awaited<ReturnType<PluginContainer['resolveId']>>;
7
+ interface ViteNodeFetch {
8
+ /** Gets the client manifest. */
9
+ getManifest(): Promise<Manifest>;
10
+ /** Gets the list of invalidated files. */
11
+ getInvalidates(): Promise<string[]>;
12
+ /** Resolves a module ID. */
13
+ resolveId(id: string, importer?: string): Promise<ResolveIdResponse | null>;
14
+ /** Fetches a module. */
15
+ fetchModule(moduleId: string): Promise<FetchResult>;
16
+ /** Ensures the IPC socket is connected. */
17
+ ensureConnected(): Promise<Socket>;
18
+ }
19
+ type ViteNodeServerOptions = {
20
+ baseURL: string;
21
+ socketPath: string;
22
+ root: string;
23
+ entryPath: string;
24
+ base: string;
25
+ maxRetryAttempts?: number;
26
+ baseRetryDelay?: number;
27
+ maxRetryDelay?: number;
28
+ requestTimeout?: number;
29
+ };
30
+
31
+ declare const viteNodeOptions: ViteNodeServerOptions;
32
+ declare const viteNodeFetch: ViteNodeFetch;
33
+
34
+ export { viteNodeFetch, viteNodeOptions };
@@ -0,0 +1,34 @@
1
+ import { Socket } from 'node:net';
2
+ import { PluginContainer } from 'vite';
3
+ import { FetchResult } from 'vite-node';
4
+ import { Manifest } from 'vue-bundle-renderer';
5
+
6
+ type ResolveIdResponse = Awaited<ReturnType<PluginContainer['resolveId']>>;
7
+ interface ViteNodeFetch {
8
+ /** Gets the client manifest. */
9
+ getManifest(): Promise<Manifest>;
10
+ /** Gets the list of invalidated files. */
11
+ getInvalidates(): Promise<string[]>;
12
+ /** Resolves a module ID. */
13
+ resolveId(id: string, importer?: string): Promise<ResolveIdResponse | null>;
14
+ /** Fetches a module. */
15
+ fetchModule(moduleId: string): Promise<FetchResult>;
16
+ /** Ensures the IPC socket is connected. */
17
+ ensureConnected(): Promise<Socket>;
18
+ }
19
+ type ViteNodeServerOptions = {
20
+ baseURL: string;
21
+ socketPath: string;
22
+ root: string;
23
+ entryPath: string;
24
+ base: string;
25
+ maxRetryAttempts?: number;
26
+ baseRetryDelay?: number;
27
+ maxRetryDelay?: number;
28
+ requestTimeout?: number;
29
+ };
30
+
31
+ declare const viteNodeOptions: ViteNodeServerOptions;
32
+ declare const viteNodeFetch: ViteNodeFetch;
33
+
34
+ export { viteNodeFetch, viteNodeOptions };
@@ -0,0 +1,248 @@
1
+ import process from 'node:process';
2
+ import net from 'node:net';
3
+ import { Buffer } from 'node:buffer';
4
+ import { isTest } from 'std-env';
5
+
6
+ const viteNodeOptions = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS || "{}");
7
+ const pendingRequests = /* @__PURE__ */ new Map();
8
+ let requestIdCounter = 0;
9
+ let clientSocket;
10
+ let currentConnectPromise;
11
+ const MAX_RETRY_ATTEMPTS = viteNodeOptions.maxRetryAttempts ?? 5;
12
+ const BASE_RETRY_DELAY_MS = viteNodeOptions.baseRetryDelay ?? 100;
13
+ const MAX_RETRY_DELAY_MS = viteNodeOptions.maxRetryDelay ?? 2e3;
14
+ const REQUEST_TIMEOUT_MS = viteNodeOptions.requestTimeout ?? 6e4;
15
+ function calculateRetryDelay(attempt) {
16
+ const exponentialDelay = BASE_RETRY_DELAY_MS * Math.pow(2, attempt);
17
+ const jitter = Math.random() * 0.1 * exponentialDelay;
18
+ return Math.min(exponentialDelay + jitter, MAX_RETRY_DELAY_MS);
19
+ }
20
+ function connectSocket() {
21
+ if (clientSocket && !clientSocket.destroyed) {
22
+ return Promise.resolve(clientSocket);
23
+ }
24
+ if (currentConnectPromise) {
25
+ return currentConnectPromise;
26
+ }
27
+ const thisPromise = new Promise((resolve, reject) => {
28
+ if (!viteNodeOptions.socketPath) {
29
+ console.error("vite-node-shared: NUXT_VITE_NODE_OPTIONS.socketPath is not defined.");
30
+ return reject(new Error("Vite Node IPC socket path not configured."));
31
+ }
32
+ const attemptConnection = (attempt = 0) => {
33
+ const socket = net.createConnection(viteNodeOptions.socketPath);
34
+ const INITIAL_BUFFER_SIZE = 64 * 1024;
35
+ const MAX_BUFFER_SIZE = 1024 * 1024 * 1024;
36
+ let buffer = Buffer.alloc(INITIAL_BUFFER_SIZE);
37
+ let writeOffset = 0;
38
+ let readOffset = 0;
39
+ socket.setNoDelay(true);
40
+ socket.setKeepAlive(true, 3e4);
41
+ const cleanup = () => {
42
+ socket.off("connect", onConnect);
43
+ socket.off("data", onData);
44
+ socket.off("error", onError);
45
+ socket.off("close", onClose);
46
+ };
47
+ const resetBuffer = () => {
48
+ writeOffset = 0;
49
+ readOffset = 0;
50
+ };
51
+ const compactBuffer = () => {
52
+ if (readOffset > 0) {
53
+ const remainingData = writeOffset - readOffset;
54
+ if (remainingData > 0) {
55
+ buffer.copy(buffer, 0, readOffset, writeOffset);
56
+ }
57
+ writeOffset = remainingData;
58
+ readOffset = 0;
59
+ }
60
+ };
61
+ const ensureBufferCapacity = (additionalBytes) => {
62
+ const requiredSize = writeOffset + additionalBytes;
63
+ if (requiredSize > MAX_BUFFER_SIZE) {
64
+ throw new Error(`Buffer size limit exceeded: ${requiredSize} > ${MAX_BUFFER_SIZE}`);
65
+ }
66
+ if (requiredSize > buffer.length) {
67
+ compactBuffer();
68
+ if (writeOffset + additionalBytes > buffer.length) {
69
+ const newSize = Math.min(
70
+ Math.max(buffer.length * 2, requiredSize),
71
+ MAX_BUFFER_SIZE
72
+ );
73
+ const newBuffer = Buffer.alloc(newSize);
74
+ buffer.copy(newBuffer, 0, 0, writeOffset);
75
+ buffer = newBuffer;
76
+ }
77
+ }
78
+ };
79
+ const onConnect = () => {
80
+ clientSocket = socket;
81
+ resolve(socket);
82
+ };
83
+ const onData = (data) => {
84
+ try {
85
+ ensureBufferCapacity(data.length);
86
+ data.copy(buffer, writeOffset);
87
+ writeOffset += data.length;
88
+ while (writeOffset - readOffset >= 4) {
89
+ const messageLength = buffer.readUInt32BE(readOffset);
90
+ if (writeOffset - readOffset < 4 + messageLength) {
91
+ return;
92
+ }
93
+ const message = buffer.subarray(readOffset + 4, readOffset + 4 + messageLength).toString("utf-8");
94
+ readOffset += 4 + messageLength;
95
+ try {
96
+ const response = JSON.parse(message);
97
+ const requestHandlers = pendingRequests.get(response.id);
98
+ if (requestHandlers) {
99
+ const { resolve: resolveRequest, reject: rejectRequest } = requestHandlers;
100
+ if (response.type === "error") {
101
+ const err = new Error(response.error.message);
102
+ err.stack = response.error.stack;
103
+ err.data = response.error.data;
104
+ err.statusCode = response.error.statusCode;
105
+ rejectRequest(err);
106
+ } else {
107
+ resolveRequest(response.data);
108
+ }
109
+ pendingRequests.delete(response.id);
110
+ }
111
+ } catch (parseError) {
112
+ console.warn("vite-node-shared: Failed to parse IPC response:", parseError);
113
+ }
114
+ }
115
+ if (readOffset > buffer.length / 2) {
116
+ compactBuffer();
117
+ }
118
+ } catch (error) {
119
+ socket.destroy(error instanceof Error ? error : new Error("Buffer management error"));
120
+ }
121
+ };
122
+ const onError = (err) => {
123
+ cleanup();
124
+ resetBuffer();
125
+ if (attempt < MAX_RETRY_ATTEMPTS) {
126
+ const delay = calculateRetryDelay(attempt);
127
+ setTimeout(() => attemptConnection(attempt + 1), delay);
128
+ } else {
129
+ if (currentConnectPromise === thisPromise) {
130
+ reject(err);
131
+ }
132
+ for (const { reject: rejectRequest } of pendingRequests.values()) {
133
+ rejectRequest(err);
134
+ }
135
+ pendingRequests.clear();
136
+ if (clientSocket === socket) {
137
+ clientSocket = void 0;
138
+ }
139
+ if (currentConnectPromise === thisPromise) {
140
+ currentConnectPromise = void 0;
141
+ }
142
+ }
143
+ };
144
+ const onClose = () => {
145
+ cleanup();
146
+ resetBuffer();
147
+ for (const { reject: rejectRequest } of pendingRequests.values()) {
148
+ rejectRequest(new Error("IPC connection closed"));
149
+ }
150
+ pendingRequests.clear();
151
+ if (clientSocket === socket) {
152
+ clientSocket = void 0;
153
+ }
154
+ if (currentConnectPromise === thisPromise) {
155
+ currentConnectPromise = void 0;
156
+ }
157
+ };
158
+ socket.on("connect", onConnect);
159
+ socket.on("data", onData);
160
+ socket.on("error", onError);
161
+ socket.on("close", onClose);
162
+ };
163
+ attemptConnection();
164
+ });
165
+ currentConnectPromise = thisPromise;
166
+ return currentConnectPromise;
167
+ }
168
+ async function sendRequest(type, payload) {
169
+ const requestId = requestIdCounter++;
170
+ let lastError;
171
+ for (let requestAttempt = 0; requestAttempt <= MAX_RETRY_ATTEMPTS; requestAttempt++) {
172
+ try {
173
+ const socket = await connectSocket();
174
+ return new Promise((resolve, reject) => {
175
+ const timeoutId = setTimeout(() => {
176
+ pendingRequests.delete(requestId);
177
+ reject(new Error(`Request timeout after ${REQUEST_TIMEOUT_MS}ms for type: ${type}`));
178
+ }, REQUEST_TIMEOUT_MS);
179
+ pendingRequests.set(requestId, {
180
+ resolve: (value) => {
181
+ clearTimeout(timeoutId);
182
+ resolve(value);
183
+ },
184
+ reject: (reason) => {
185
+ clearTimeout(timeoutId);
186
+ reject(reason);
187
+ }
188
+ });
189
+ const message = JSON.stringify({ id: requestId, type, payload });
190
+ const messageBuffer = Buffer.from(message, "utf-8");
191
+ const messageLength = messageBuffer.length;
192
+ const fullMessage = Buffer.alloc(4 + messageLength);
193
+ fullMessage.writeUInt32BE(messageLength, 0);
194
+ messageBuffer.copy(fullMessage, 4);
195
+ try {
196
+ socket.write(fullMessage);
197
+ } catch (error) {
198
+ clearTimeout(timeoutId);
199
+ pendingRequests.delete(requestId);
200
+ reject(error);
201
+ }
202
+ });
203
+ } catch (error) {
204
+ lastError = error;
205
+ if (requestAttempt < MAX_RETRY_ATTEMPTS) {
206
+ const delay = calculateRetryDelay(requestAttempt);
207
+ await new Promise((resolve) => setTimeout(resolve, delay));
208
+ if (clientSocket) {
209
+ clientSocket.destroy();
210
+ clientSocket = void 0;
211
+ }
212
+ currentConnectPromise = void 0;
213
+ }
214
+ }
215
+ }
216
+ throw lastError || new Error("Request failed after all retry attempts");
217
+ }
218
+ const viteNodeFetch = {
219
+ getManifest() {
220
+ return sendRequest("manifest", void 0);
221
+ },
222
+ getInvalidates() {
223
+ return sendRequest("invalidates", void 0);
224
+ },
225
+ resolveId(id, importer) {
226
+ return sendRequest("resolve", { id, importer });
227
+ },
228
+ fetchModule(moduleId) {
229
+ return sendRequest("module", { moduleId });
230
+ },
231
+ ensureConnected() {
232
+ return connectSocket();
233
+ }
234
+ };
235
+ let preConnectAttempted = false;
236
+ function preConnect() {
237
+ if (preConnectAttempted || !viteNodeOptions.socketPath) {
238
+ return;
239
+ }
240
+ preConnectAttempted = true;
241
+ return connectSocket().catch(() => {
242
+ });
243
+ }
244
+ if (typeof process !== "undefined" && !isTest) {
245
+ setTimeout(preConnect, 100);
246
+ }
247
+
248
+ export { viteNodeFetch, viteNodeOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/vite-builder-nightly",
3
- "version": "4.3.0-29430616.754c35a4",
3
+ "version": "4.3.0-29430640.29b20b87",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nuxt/nuxt.git",
@@ -17,23 +17,27 @@
17
17
  "import": "./dist/index.mjs"
18
18
  }
19
19
  },
20
+ "imports": {
21
+ "#vite-node": "./dist/vite-node.mjs",
22
+ "#vite-node-entry": "./dist/vite-node-entry.mjs"
23
+ },
20
24
  "files": [
21
25
  "dist"
22
26
  ],
23
27
  "devDependencies": {
24
- "@nuxt/schema": "npm:@nuxt/schema-nightly@4.3.0-29430616.754c35a4",
28
+ "@nuxt/schema": "npm:@nuxt/schema-nightly@4.3.0-29430640.29b20b87",
25
29
  "nitropack": "2.12.9",
26
- "rolldown": "1.0.0-beta.53",
27
- "rollup": "4.53.3",
30
+ "rolldown": "1.0.0-beta.54",
31
+ "rollup": "4.53.4",
28
32
  "unbuild": "3.6.1",
29
33
  "vue": "3.5.25"
30
34
  },
31
35
  "dependencies": {
32
- "@nuxt/kit": "npm:@nuxt/kit-nightly@4.3.0-29430616.754c35a4",
36
+ "@nuxt/kit": "npm:@nuxt/kit-nightly@4.3.0-29430640.29b20b87",
33
37
  "@rollup/plugin-replace": "^6.0.3",
34
- "@vitejs/plugin-vue": "^6.0.2",
38
+ "@vitejs/plugin-vue": "^6.0.3",
35
39
  "@vitejs/plugin-vue-jsx": "^5.1.2",
36
- "autoprefixer": "^10.4.22",
40
+ "autoprefixer": "^10.4.23",
37
41
  "consola": "^3.4.2",
38
42
  "cssnano": "^7.1.2",
39
43
  "defu": "^6.1.4",
@@ -55,13 +59,13 @@
55
59
  "std-env": "^3.10.0",
56
60
  "ufo": "^1.6.1",
57
61
  "unenv": "^2.0.0-rc.24",
58
- "vite": "^7.2.7",
62
+ "vite": "^7.3.0",
59
63
  "vite-node": "^5.2.0",
60
64
  "vite-plugin-checker": "^0.12.0",
61
65
  "vue-bundle-renderer": "^2.2.0"
62
66
  },
63
67
  "peerDependencies": {
64
- "nuxt": "npm:nuxt-nightly@4.3.0-29430616.754c35a4",
68
+ "nuxt": "npm:nuxt-nightly@4.3.0-29430640.29b20b87",
65
69
  "rolldown": "^1.0.0-beta.38",
66
70
  "vue": "^3.3.4"
67
71
  },
@@ -1,2 +0,0 @@
1
- declare function _default(): Promise<import("vue-bundle-renderer").Manifest>;
2
- export default _default;
@@ -1,4 +0,0 @@
1
- // @ts-check
2
- import { viteNodeFetch } from './vite-node-shared.mjs'
3
-
4
- export default () => viteNodeFetch.getManifest()
@@ -1,10 +0,0 @@
1
- /** @typedef {import('node:net').Socket} Socket */
2
- /** @typedef {import('../plugins/vite-node').ViteNodeFetch} ViteNodeFetch */
3
- /** @type {import('../plugins/vite-node').ViteNodeServerOptions} */
4
- export const viteNodeOptions: import("../plugins/vite-node").ViteNodeServerOptions;
5
- /**
6
- * @type {ViteNodeFetch}
7
- */
8
- export const viteNodeFetch: ViteNodeFetch;
9
- export type Socket = import("node:net").Socket;
10
- export type ViteNodeFetch = import("../plugins/vite-node").ViteNodeFetch;
@@ -1,322 +0,0 @@
1
- // @ts-check
2
- import process from 'node:process'
3
- import net from 'node:net'
4
- import { Buffer } from 'node:buffer'
5
- import { isTest } from 'std-env'
6
-
7
- /** @typedef {import('node:net').Socket} Socket */
8
- /** @typedef {import('../plugins/vite-node').ViteNodeFetch} ViteNodeFetch */
9
-
10
- /** @type {import('../plugins/vite-node').ViteNodeServerOptions} */
11
- export const viteNodeOptions = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS || '{}')
12
-
13
- /** @type {Map<number, { resolve: (value: any) => void, reject: (reason?: any) => void }>} */
14
- const pendingRequests = new Map()
15
- let requestIdCounter = 0
16
- /** @type {Socket | undefined} */
17
- let clientSocket
18
- /** @type {Promise<Socket> | undefined} */
19
- let currentConnectPromise
20
- const MAX_RETRY_ATTEMPTS = viteNodeOptions.maxRetryAttempts ?? 5
21
- const BASE_RETRY_DELAY_MS = viteNodeOptions.baseRetryDelay ?? 100
22
- const MAX_RETRY_DELAY_MS = viteNodeOptions.maxRetryDelay ?? 2000
23
- const REQUEST_TIMEOUT_MS = viteNodeOptions.requestTimeout ?? 60000
24
-
25
- /**
26
- * Calculates exponential backoff delay with jitter.
27
- * @param {number} attempt - The current attempt number (0-based).
28
- * @returns {number} Delay in milliseconds.
29
- */
30
- function calculateRetryDelay (attempt) {
31
- const exponentialDelay = BASE_RETRY_DELAY_MS * Math.pow(2, attempt)
32
- const jitter = Math.random() * 0.1 * exponentialDelay // Add 10% jitter
33
- return Math.min(exponentialDelay + jitter, MAX_RETRY_DELAY_MS)
34
- }
35
-
36
- /**
37
- * Establishes or returns an existing IPC socket connection with retry logic.
38
- * @returns {Promise<Socket>} A promise that resolves with the connected socket.
39
- */
40
- function connectSocket () {
41
- if (clientSocket && !clientSocket.destroyed) {
42
- return Promise.resolve(clientSocket)
43
- }
44
-
45
- if (currentConnectPromise) {
46
- return currentConnectPromise
47
- }
48
-
49
- const thisPromise = new Promise((resolve, reject) => {
50
- if (!viteNodeOptions.socketPath) {
51
- console.error('vite-node-shared: NUXT_VITE_NODE_OPTIONS.socketPath is not defined.')
52
- return reject(new Error('Vite Node IPC socket path not configured.'))
53
- }
54
-
55
- const attemptConnection = (attempt = 0) => {
56
- const socket = net.createConnection(viteNodeOptions.socketPath)
57
-
58
- const INITIAL_BUFFER_SIZE = 64 * 1024 // 64KB
59
- const MAX_BUFFER_SIZE = 1024 * 1024 * 1024 // 1GB
60
-
61
- let buffer = Buffer.alloc(INITIAL_BUFFER_SIZE)
62
- let writeOffset = 0
63
- let readOffset = 0
64
-
65
- // optimize socket for high-frequency IPC
66
- socket.setNoDelay(true)
67
- socket.setKeepAlive(true, 30000) // 30s
68
-
69
- const cleanup = () => {
70
- socket.off('connect', onConnect)
71
- socket.off('data', onData)
72
- socket.off('error', onError)
73
- socket.off('close', onClose)
74
- }
75
-
76
- const resetBuffer = () => {
77
- writeOffset = 0
78
- readOffset = 0
79
- }
80
-
81
- const compactBuffer = () => {
82
- if (readOffset > 0) {
83
- const remainingData = writeOffset - readOffset
84
- if (remainingData > 0) {
85
- buffer.copy(buffer, 0, readOffset, writeOffset)
86
- }
87
- writeOffset = remainingData
88
- readOffset = 0
89
- }
90
- }
91
-
92
- /**
93
- * @param {number} additionalBytes
94
- */
95
- const ensureBufferCapacity = (additionalBytes) => {
96
- const requiredSize = writeOffset + additionalBytes
97
-
98
- if (requiredSize > MAX_BUFFER_SIZE) {
99
- throw new Error(`Buffer size limit exceeded: ${requiredSize} > ${MAX_BUFFER_SIZE}`)
100
- }
101
-
102
- if (requiredSize > buffer.length) {
103
- // Try compacting first
104
- compactBuffer()
105
-
106
- // ... then if we still need more space, grow the buffer
107
- if (writeOffset + additionalBytes > buffer.length) {
108
- const newSize = Math.min(
109
- Math.max(buffer.length * 2, requiredSize),
110
- MAX_BUFFER_SIZE,
111
- )
112
- const newBuffer = Buffer.alloc(newSize)
113
- buffer.copy(newBuffer, 0, 0, writeOffset)
114
- buffer = newBuffer
115
- }
116
- }
117
- }
118
-
119
- const onConnect = () => {
120
- clientSocket = socket
121
- resolve(socket)
122
- }
123
-
124
- /** @param {Buffer} data */
125
- const onData = (data) => {
126
- try {
127
- ensureBufferCapacity(data.length)
128
- data.copy(buffer, writeOffset)
129
- writeOffset += data.length
130
-
131
- while (writeOffset - readOffset >= 4) {
132
- const messageLength = buffer.readUInt32BE(readOffset)
133
-
134
- if (writeOffset - readOffset < 4 + messageLength) {
135
- return // Wait for more data
136
- }
137
-
138
- const message = buffer.subarray(readOffset + 4, readOffset + 4 + messageLength).toString('utf-8')
139
- readOffset += 4 + messageLength
140
-
141
- try {
142
- const response = JSON.parse(message)
143
- const requestHandlers = pendingRequests.get(response.id)
144
- if (requestHandlers) {
145
- const { resolve: resolveRequest, reject: rejectRequest } = requestHandlers
146
- if (response.type === 'error') {
147
- const err = new Error(response.error.message)
148
- // @ts-ignore We are augmenting the error object
149
- err.stack = response.error.stack
150
- // @ts-ignore
151
- err.data = response.error.data
152
- // @ts-ignore
153
- err.statusCode = response.error.statusCode
154
- rejectRequest(err)
155
- } else {
156
- resolveRequest(response.data)
157
- }
158
- pendingRequests.delete(response.id)
159
- }
160
- } catch (parseError) {
161
- console.warn('vite-node-shared: Failed to parse IPC response:', parseError)
162
- // ignore malformed messages
163
- }
164
- }
165
-
166
- // compact buffer periodically to prevent memory waste
167
- if (readOffset > buffer.length / 2) {
168
- compactBuffer()
169
- }
170
- } catch (error) {
171
- socket.destroy(error instanceof Error ? error : new Error('Buffer management error'))
172
- }
173
- }
174
-
175
- /** @param {Error} err */
176
- const onError = (err) => {
177
- cleanup()
178
- resetBuffer()
179
-
180
- if (attempt < MAX_RETRY_ATTEMPTS) {
181
- const delay = calculateRetryDelay(attempt)
182
- setTimeout(() => attemptConnection(attempt + 1), delay)
183
- } else {
184
- if (currentConnectPromise === thisPromise) {
185
- reject(err)
186
- }
187
- for (const { reject: rejectRequest } of pendingRequests.values()) {
188
- rejectRequest(err)
189
- }
190
- pendingRequests.clear()
191
- if (clientSocket === socket) { clientSocket = undefined }
192
- if (currentConnectPromise === thisPromise) { currentConnectPromise = undefined }
193
- }
194
- }
195
-
196
- const onClose = () => {
197
- cleanup()
198
- resetBuffer()
199
- for (const { reject: rejectRequest } of pendingRequests.values()) {
200
- rejectRequest(new Error('IPC connection closed'))
201
- }
202
- pendingRequests.clear()
203
- if (clientSocket === socket) { clientSocket = undefined }
204
- if (currentConnectPromise === thisPromise) { currentConnectPromise = undefined }
205
- }
206
-
207
- socket.on('connect', onConnect)
208
- socket.on('data', onData)
209
- socket.on('error', onError)
210
- socket.on('close', onClose)
211
- }
212
-
213
- attemptConnection()
214
- })
215
-
216
- currentConnectPromise = thisPromise
217
- return currentConnectPromise
218
- }
219
-
220
- /**
221
- * Sends a request over the IPC socket with automatic reconnection.
222
- * @template {keyof import('../plugins/vite-node').ViteNodeRequestMap} T
223
- * @param {T} type - The type of the request.
224
- * @param {import('../plugins/vite-node').ViteNodeRequestMap[T]['request']} [payload] - The payload for the request.
225
- * @returns {Promise<import('../plugins/vite-node').ViteNodeRequestMap[T]['response']>} A promise that resolves with the response data.
226
- */
227
- async function sendRequest (type, payload) {
228
- const requestId = requestIdCounter++
229
- let lastError
230
-
231
- // retry the entire request (including reconnection) up to MAX_RETRY_ATTEMPTS times
232
- for (let requestAttempt = 0; requestAttempt <= MAX_RETRY_ATTEMPTS; requestAttempt++) {
233
- try {
234
- const socket = await connectSocket()
235
-
236
- return new Promise((resolve, reject) => {
237
- const timeoutId = setTimeout(() => {
238
- pendingRequests.delete(requestId)
239
- reject(new Error(`Request timeout after ${REQUEST_TIMEOUT_MS}ms for type: ${type}`))
240
- }, REQUEST_TIMEOUT_MS)
241
-
242
- pendingRequests.set(requestId, {
243
- resolve: (value) => {
244
- clearTimeout(timeoutId)
245
- resolve(value)
246
- },
247
- reject: (reason) => {
248
- clearTimeout(timeoutId)
249
- reject(reason)
250
- },
251
- })
252
-
253
- const message = JSON.stringify({ id: requestId, type, payload })
254
- const messageBuffer = Buffer.from(message, 'utf-8')
255
- const messageLength = messageBuffer.length
256
-
257
- // pre-allocate single buffer for length + message to avoid Buffer.concat()
258
- const fullMessage = Buffer.alloc(4 + messageLength)
259
- fullMessage.writeUInt32BE(messageLength, 0)
260
- messageBuffer.copy(fullMessage, 4)
261
-
262
- try {
263
- socket.write(fullMessage)
264
- } catch (error) {
265
- clearTimeout(timeoutId)
266
- pendingRequests.delete(requestId)
267
- reject(error)
268
- }
269
- })
270
- } catch (error) {
271
- lastError = error
272
- if (requestAttempt < MAX_RETRY_ATTEMPTS) {
273
- const delay = calculateRetryDelay(requestAttempt)
274
- await new Promise(resolve => setTimeout(resolve, delay))
275
- // clear current connection state to force reconnection
276
- if (clientSocket) {
277
- clientSocket.destroy()
278
- clientSocket = undefined
279
- }
280
- currentConnectPromise = undefined
281
- }
282
- }
283
- }
284
-
285
- throw lastError || new Error('Request failed after all retry attempts')
286
- }
287
-
288
- /**
289
- * @type {ViteNodeFetch}
290
- */
291
- export const viteNodeFetch = {
292
- getManifest () {
293
- return sendRequest('manifest')
294
- },
295
- getInvalidates () {
296
- return sendRequest('invalidates')
297
- },
298
- resolveId (id, importer) {
299
- return sendRequest('resolve', { id, importer })
300
- },
301
- fetchModule (moduleId) {
302
- return sendRequest('module', { moduleId })
303
- },
304
- ensureConnected () {
305
- return connectSocket()
306
- },
307
- }
308
-
309
- // attempt to pre-establish the IPC connection to reduce latency on first request
310
- let preConnectAttempted = false
311
- function preConnect () {
312
- if (preConnectAttempted || !viteNodeOptions.socketPath) {
313
- return
314
- }
315
- preConnectAttempted = true
316
-
317
- return connectSocket().catch(() => {})
318
- }
319
-
320
- if (typeof process !== 'undefined' && !isTest) {
321
- setTimeout(preConnect, 100)
322
- }
@@ -1,2 +0,0 @@
1
- declare function _default(ssrContext: any): Promise<any>;
2
- export default _default;
@@ -1,112 +0,0 @@
1
- // @ts-check
2
-
3
- import process from 'node:process'
4
- import { performance } from 'node:perf_hooks'
5
- import { createError } from 'h3'
6
- import { ViteNodeRunner } from 'vite-node/client'
7
- import { consola } from 'consola'
8
- import { viteNodeFetch, viteNodeOptions } from './vite-node-shared.mjs'
9
-
10
- const runner = createRunner()
11
-
12
- /** @type {(ssrContext: import('#app').NuxtSSRContext) => Promise<any>} */
13
- let render
14
-
15
- /** @param {import('#app').NuxtSSRContext} ssrContext */
16
- export default async (ssrContext) => {
17
- // Workaround for stub mode
18
- // https://github.com/nuxt/framework/pull/3983
19
- // eslint-disable-next-line nuxt/prefer-import-meta,@typescript-eslint/no-deprecated
20
- process.server = true
21
- import.meta.server = true
22
-
23
- // Invalidate cache for files changed since last rendering
24
- const invalidates = await viteNodeFetch.getInvalidates()
25
- const updates = runner.moduleCache.invalidateDepTree(invalidates)
26
-
27
- // Execute SSR bundle on demand
28
- const start = performance.now()
29
- render = (updates.has(viteNodeOptions.entryPath) || !render) ? (await runner.executeFile(viteNodeOptions.entryPath)).default : render
30
- if (updates.size) {
31
- const time = Math.round((performance.now() - start) * 1000) / 1000
32
- consola.success(`Vite server hmr ${updates.size} files`, time ? `in ${time}ms` : '')
33
- }
34
-
35
- const result = await render(ssrContext)
36
- return result
37
- }
38
-
39
- function createRunner () {
40
- return new ViteNodeRunner({
41
- root: viteNodeOptions.root, // Equals to Nuxt `srcDir`
42
- base: viteNodeOptions.base,
43
- async resolveId (id, importer) {
44
- return await viteNodeFetch.resolveId(id, importer)
45
- },
46
- async fetchModule (id) {
47
- id = id.replace(/\/\//g, '/') // TODO: fix in vite-node
48
- return await viteNodeFetch.fetchModule(id).catch((err) => {
49
- const errorData = err?.data?.data
50
- if (!errorData) {
51
- throw err
52
- }
53
- let _err
54
- try {
55
- const { message, stack } = formatViteError(errorData, id)
56
- _err = createError({
57
- statusMessage: 'Vite Error',
58
- message,
59
- stack,
60
- })
61
- } catch (formatError) {
62
- consola.warn('Internal nuxt error while formatting vite-node error. Please report this!', formatError)
63
- const message = `[vite-node] [TransformError] ${errorData?.message || '-'}`
64
- consola.error(message, errorData)
65
- throw createError({
66
- statusMessage: 'Vite Error',
67
- message,
68
- stack: `${message}\nat ${id}\n` + (errorData?.stack || ''),
69
- })
70
- }
71
- throw _err
72
- })
73
- },
74
- })
75
- }
76
-
77
- /**
78
- * @param {any} errorData
79
- * @param {string} id
80
- */
81
- function formatViteError (errorData, id) {
82
- const errorCode = errorData.name || errorData.reasonCode || errorData.code
83
- const frame = errorData.frame || errorData.source || errorData.pluginCode
84
-
85
- /** @param {{ file?: string, id?: string, url?: string }} locObj */
86
- const getLocId = (locObj = {}) => locObj.file || locObj.id || locObj.url || id || ''
87
- /** @param {{ line?: string, column?: string }} locObj */
88
- const getLocPos = (locObj = {}) => locObj.line ? `${locObj.line}:${locObj.column || 0}` : ''
89
- const locId = getLocId(errorData.loc) || getLocId(errorData.location) || getLocId(errorData.input) || getLocId(errorData)
90
- const locPos = getLocPos(errorData.loc) || getLocPos(errorData.location) || getLocPos(errorData.input) || getLocPos(errorData)
91
- const loc = locId.replace(process.cwd(), '.') + (locPos ? `:${locPos}` : '')
92
-
93
- const message = [
94
- '[vite-node]',
95
- errorData.plugin && `[plugin:${errorData.plugin}]`,
96
- errorCode && `[${errorCode}]`,
97
- loc,
98
- errorData.reason && `: ${errorData.reason}`,
99
- frame && `<br><pre>${frame.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</pre><br>`,
100
- ].filter(Boolean).join(' ')
101
-
102
- const stack = [
103
- message,
104
- `at ${loc}`,
105
- errorData.stack,
106
- ].filter(Boolean).join('\n')
107
-
108
- return {
109
- message,
110
- stack,
111
- }
112
- }