@nuxt/vite-server-nightly 0.0.0 → 4.5.2-2610052030-052d82e
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/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.mjs +1194 -0
- package/dist/runtime/dev-error.mjs +92 -0
- package/dist/runtime/dev-handler.mjs +9 -0
- package/dist/runtime/event.mjs +16 -0
- package/dist/runtime/node.mjs +51 -0
- package/dist/runtime/prerender.mjs +58 -0
- package/dist/runtime/renderer.mjs +220 -0
- package/dist/runtime/server.mjs +15 -0
- package/package.json +47 -3
- package/dist/.gitkeep +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { ERROR_CHANNEL_ENV, clearErrorReport, createDevErrorReporter, createErrorReport, serializeErrorCause, setErrorChannelForwarding, useErrorChannel } from "nuxt/internal/dev-error";
|
|
3
|
+
import { isLoopbackAddress } from "nuxt/internal/dev/peer";
|
|
4
|
+
//#region src/runtime/dev-error.ts
|
|
5
|
+
let context;
|
|
6
|
+
/** Whether a dev server in front owns the channel. */
|
|
7
|
+
const forwarding = () => !!process.env[ERROR_CHANNEL_ENV];
|
|
8
|
+
setErrorChannelForwarding(forwarding);
|
|
9
|
+
/** Install the dev server the app renders from. */
|
|
10
|
+
function setDevErrorContext(next) {
|
|
11
|
+
context = next;
|
|
12
|
+
useErrorChannel().catch(() => {});
|
|
13
|
+
}
|
|
14
|
+
/** Whether `pathname` is a live channel route this process serves. */
|
|
15
|
+
function isErrorChannelRequest(pathname) {
|
|
16
|
+
if (!context || forwarding()) return false;
|
|
17
|
+
const base = context.channel.replace(/\/$/, "");
|
|
18
|
+
return pathname === base || pathname.startsWith(`${base}/`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Serve the live error channel: the SSE stream, report lookups and "open in editor".
|
|
22
|
+
*
|
|
23
|
+
* Trust follows the socket, since a request's origin headers are forgeable over a direct
|
|
24
|
+
* connection.
|
|
25
|
+
*/
|
|
26
|
+
async function fetchErrorChannel(request) {
|
|
27
|
+
return await (await useErrorChannel()).fetchHandler(request, { trusted: isLoopbackAddress(request.ip) }) ?? new Response("Not Found", { status: 404 });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a report from the stack as raised, publish it, then rewrite the stack in place so
|
|
31
|
+
* every later consumer sees source positions.
|
|
32
|
+
*/
|
|
33
|
+
function observeDevError(error, request, observe) {
|
|
34
|
+
if (!context) return Promise.resolve(void 0);
|
|
35
|
+
return reporter(error, request, observe);
|
|
36
|
+
}
|
|
37
|
+
const reporter = createDevErrorReporter({
|
|
38
|
+
get cwd() {
|
|
39
|
+
return context.cwd;
|
|
40
|
+
},
|
|
41
|
+
channel: channelPath,
|
|
42
|
+
createReport: (error) => buildReport(error),
|
|
43
|
+
requestInfo: (request) => ({
|
|
44
|
+
method: request.method,
|
|
45
|
+
url: new URL(request.url),
|
|
46
|
+
headers: request.headers
|
|
47
|
+
}),
|
|
48
|
+
mapStack: (error) => fixStacktraces(error, context.server)
|
|
49
|
+
});
|
|
50
|
+
async function buildReport(error) {
|
|
51
|
+
const { viteLoader } = await import("my-bad/vite");
|
|
52
|
+
return createErrorReport(error, {
|
|
53
|
+
cwd: context.cwd,
|
|
54
|
+
loaders: [viteLoader(ssrOnly(context.server), { fs: false })]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The dev server with only its SSR environment visible, since `viteLoader` maps through
|
|
59
|
+
* the first environment holding the file and an SSR frame belongs to the SSR transform.
|
|
60
|
+
*/
|
|
61
|
+
function ssrOnly(server) {
|
|
62
|
+
return Object.create(server, { environments: { value: { ssr: server.environments.ssr } } });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Ask Vite to map the stacks of an error and its causes. It maps in place and appends to
|
|
66
|
+
* `message` on a stack it has already rewritten, so each one is mapped on a carrier.
|
|
67
|
+
*/
|
|
68
|
+
function fixStacktraces(error, server, seen = /* @__PURE__ */ new Set()) {
|
|
69
|
+
if (!(error instanceof Error) || seen.has(error)) return;
|
|
70
|
+
seen.add(error);
|
|
71
|
+
if (typeof error.stack === "string") {
|
|
72
|
+
const carrier = { stack: error.stack };
|
|
73
|
+
server.ssrFixStacktrace(carrier);
|
|
74
|
+
if (carrier.stack) try {
|
|
75
|
+
Object.defineProperty(error, "stack", {
|
|
76
|
+
value: carrier.stack,
|
|
77
|
+
writable: true,
|
|
78
|
+
configurable: true
|
|
79
|
+
});
|
|
80
|
+
} catch {}
|
|
81
|
+
}
|
|
82
|
+
fixStacktraces(error.cause, server, seen);
|
|
83
|
+
}
|
|
84
|
+
/** The error's `cause` chain, as the error page receives it in the payload. */
|
|
85
|
+
function errorCause(error) {
|
|
86
|
+
return serializeErrorCause(error?.cause);
|
|
87
|
+
}
|
|
88
|
+
function channelPath() {
|
|
89
|
+
return process.env[ERROR_CHANNEL_ENV] || context.channel;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { clearErrorReport, errorCause, fetchErrorChannel, isErrorChannelRequest, observeDevError, setDevErrorContext };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/runtime/dev-handler.ts
|
|
2
|
+
/** Stands in for the render in development, where the dev server serves the app. */
|
|
3
|
+
const fetch = () => Promise.resolve(new Response("The Nuxt server handler is only emitted by a build. In development the app is served by the Nuxt dev server.", {
|
|
4
|
+
status: 503,
|
|
5
|
+
headers: { "content-type": "text/plain;charset=utf-8" }
|
|
6
|
+
}));
|
|
7
|
+
var dev_handler_default = { fetch };
|
|
8
|
+
//#endregion
|
|
9
|
+
export { dev_handler_default as default, fetch };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/runtime/event.ts
|
|
2
|
+
/**
|
|
3
|
+
* The request event the renderer reads, described in web standards only: a platform
|
|
4
|
+
* `Request`, its URL, a mutable response to influence, and a context the app layer stores
|
|
5
|
+
* per-request state in.
|
|
6
|
+
*/
|
|
7
|
+
function createRequestEvent(request) {
|
|
8
|
+
return {
|
|
9
|
+
req: request,
|
|
10
|
+
url: new URL(request.url),
|
|
11
|
+
res: { headers: new Headers() },
|
|
12
|
+
context: {}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { createRequestEvent };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { join, relative, sep } from "node:path";
|
|
4
|
+
import { serve } from "srvx/node";
|
|
5
|
+
import { staticMiddleware } from "srvx/static";
|
|
6
|
+
//#region src/runtime/node.ts
|
|
7
|
+
/**
|
|
8
|
+
* Serve the build's static assets, and hand everything else to the renderer.
|
|
9
|
+
*
|
|
10
|
+
* The static handler comes first so a request for a hashed asset never reaches a render.
|
|
11
|
+
*/
|
|
12
|
+
function createNodeServer(options) {
|
|
13
|
+
const dir = typeof options.publicDir === "string" ? options.publicDir : fileURLToPath(options.publicDir);
|
|
14
|
+
const serveStatic = staticMiddleware({ dir });
|
|
15
|
+
const publicFiles = listFiles(dir);
|
|
16
|
+
return { fetch: async (request) => {
|
|
17
|
+
const files = await publicFiles;
|
|
18
|
+
if (!files || mayBeStaticFile(files, request)) return serveStatic(request, () => options.fetch(request));
|
|
19
|
+
return options.fetch(request);
|
|
20
|
+
} };
|
|
21
|
+
}
|
|
22
|
+
async function listFiles(dir) {
|
|
23
|
+
try {
|
|
24
|
+
const entries = await readdir(dir, {
|
|
25
|
+
recursive: true,
|
|
26
|
+
withFileTypes: true
|
|
27
|
+
});
|
|
28
|
+
const files = /* @__PURE__ */ new Set();
|
|
29
|
+
for (const entry of entries) if (entry.isFile()) files.add("/" + relative(dir, join(entry.parentPath, entry.name)).split(sep).join("/"));
|
|
30
|
+
return files;
|
|
31
|
+
} catch {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Whether the request path, or one of the variants the static handler tries, is a public file. */
|
|
36
|
+
function mayBeStaticFile(files, request) {
|
|
37
|
+
let path;
|
|
38
|
+
try {
|
|
39
|
+
path = decodeURIComponent(new URL(request.url).pathname);
|
|
40
|
+
} catch {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (path.endsWith("/")) return files.has(path + "index.html");
|
|
44
|
+
return files.has(path) || files.has(path + ".html") || files.has(path + "/index.html");
|
|
45
|
+
}
|
|
46
|
+
/** Listen for requests, using the port and host the platform environment configures. */
|
|
47
|
+
function listen(server) {
|
|
48
|
+
serve({ fetch: server.fetch });
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { createNodeServer, listen };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { NuxtServerError } from "./renderer.mjs";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
//#region src/runtime/prerender.ts
|
|
4
|
+
/**
|
|
5
|
+
* The capabilities the renderer only has while prerendering. Everything is held in memory:
|
|
6
|
+
* the crawler drives the handler in-process, so nothing outlives the build.
|
|
7
|
+
*/
|
|
8
|
+
function createPrerenderOptions(options = {}) {
|
|
9
|
+
const payloads = /* @__PURE__ */ new Map();
|
|
10
|
+
return {
|
|
11
|
+
payloadCache: {
|
|
12
|
+
hasItem: (key) => payloads.has(key),
|
|
13
|
+
getItem: (key) => payloads.get(key),
|
|
14
|
+
setItem: (key, value) => void payloads.set(key, value)
|
|
15
|
+
},
|
|
16
|
+
sharedDataCache: options.sharedData === false ? void 0 : createSharedDataCache(),
|
|
17
|
+
wrapRender: (event, render) => {
|
|
18
|
+
const renderingURL = event.url.pathname + event.url.search;
|
|
19
|
+
const stack = renderingURLs.getStore();
|
|
20
|
+
if (stack?.includes(renderingURL)) {
|
|
21
|
+
const chain = [...stack, renderingURL].filter((url) => !url.startsWith("/__nuxt_error")).map((url) => `"${url}"`).join(" -> ");
|
|
22
|
+
throw new NuxtServerError({
|
|
23
|
+
status: 508,
|
|
24
|
+
statusText: `Loop detected while prerendering "${renderingURL}" (${chain}). Check for \`useFetch\`/\`$fetch\` calls targeting a URL that is currently being rendered.`
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return renderingURLs.run([...stack || [], renderingURL], render);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** URLs rendering in the active async context, oldest first. A repeat entry is a cycle. */
|
|
32
|
+
const renderingURLs = new AsyncLocalStorage();
|
|
33
|
+
function createSharedDataCache() {
|
|
34
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
35
|
+
const pending = /* @__PURE__ */ new Map();
|
|
36
|
+
const chains = /* @__PURE__ */ new Map();
|
|
37
|
+
return {
|
|
38
|
+
get(key) {
|
|
39
|
+
const chain = renderingURLs.getStore();
|
|
40
|
+
const setChain = chains.get(key);
|
|
41
|
+
if (chain?.length && setChain?.length && setChain.some((url) => chain.includes(url))) return;
|
|
42
|
+
return pending.get(key) ?? resolved.get(key);
|
|
43
|
+
},
|
|
44
|
+
async set(key, value) {
|
|
45
|
+
pending.set(key, value);
|
|
46
|
+
const chain = renderingURLs.getStore();
|
|
47
|
+
if (chain?.length) chains.set(key, chain);
|
|
48
|
+
try {
|
|
49
|
+
resolved.set(key, Promise.resolve(await value));
|
|
50
|
+
} catch {} finally {
|
|
51
|
+
pending.delete(key);
|
|
52
|
+
chains.delete(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { createPrerenderOptions };
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { createRequestEvent } from "./event.mjs";
|
|
2
|
+
import { joinURL, withQuery } from "ufo";
|
|
3
|
+
import { appendVary, describeError, isExpectedError, isJsonRequest } from "nuxt/internal/renderer/error";
|
|
4
|
+
import { mergeHeaders } from "nuxt/internal/renderer/headers";
|
|
5
|
+
import { useServerHooks } from "nuxt/server";
|
|
6
|
+
import { buildAssetsURL, publicAssetsURL } from "#internal/nuxt/paths";
|
|
7
|
+
//#region src/runtime/renderer.ts
|
|
8
|
+
/** An error carrying the HTTP status the renderer refused a request with. */
|
|
9
|
+
var NuxtServerError = class extends Error {
|
|
10
|
+
status;
|
|
11
|
+
statusText;
|
|
12
|
+
data;
|
|
13
|
+
headers;
|
|
14
|
+
constructor(init) {
|
|
15
|
+
super(init.statusText || `Request failed with status ${init.status}`);
|
|
16
|
+
this.name = "NuxtServerError";
|
|
17
|
+
this.status = init.status;
|
|
18
|
+
this.statusText = init.statusText || "";
|
|
19
|
+
this.data = init.data;
|
|
20
|
+
this.headers = init.headers;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The capabilities `@nuxt/vite-server` provides to the renderer. Everything comes from the
|
|
25
|
+
* platform or from values the build serialised, so the same options run on a node server
|
|
26
|
+
* and in a web-standard worker.
|
|
27
|
+
*
|
|
28
|
+
* Route rules come from the matcher the build compiled, so a route is server-rendered
|
|
29
|
+
* unless a rule says otherwise.
|
|
30
|
+
*/
|
|
31
|
+
function createRendererOptions(runtimeConfig, matchRouteRules, prerender) {
|
|
32
|
+
globalThis.__buildAssetsURL = buildAssetsURL;
|
|
33
|
+
globalThis.__publicAssetsURL = publicAssetsURL;
|
|
34
|
+
return {
|
|
35
|
+
runtimeConfig,
|
|
36
|
+
buildAssetsURL,
|
|
37
|
+
publicAssetsURL,
|
|
38
|
+
getRouteRules: (event) => ({
|
|
39
|
+
ssr: true,
|
|
40
|
+
...matchRouteRules(event.url.pathname)
|
|
41
|
+
}),
|
|
42
|
+
hooks: useServerHooks,
|
|
43
|
+
createResponse: (body, init) => new Response(body, init),
|
|
44
|
+
createError: (init) => new NuxtServerError(init),
|
|
45
|
+
prerender,
|
|
46
|
+
onRenderSuccess: import.meta.dev ? () => {
|
|
47
|
+
import("./dev-error.mjs").then(({ clearErrorReport }) => clearErrorReport()).catch(() => {});
|
|
48
|
+
} : void 0,
|
|
49
|
+
captureError: (error) => {
|
|
50
|
+
if (!import.meta.dev) console.error(error);
|
|
51
|
+
},
|
|
52
|
+
onDevError: import.meta.dev ? (error, event, options) => import("./dev-error.mjs").then(({ observeDevError }) => observeDevError(error, event.req, options)) : void 0
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Header the crawler reads additional routes from. The renderer collects them on the
|
|
57
|
+
* request event, which does not cross the handler boundary, so they ride the response.
|
|
58
|
+
*/
|
|
59
|
+
const PRERENDER_HINTS_HEADER = "x-nuxt-prerender";
|
|
60
|
+
/**
|
|
61
|
+
* A web-standard handler over the renderer: it renders the request, and renders the app's
|
|
62
|
+
* error page for a request the render refused. In development it also serves the live
|
|
63
|
+
* error channel and publishes what it failed on to it.
|
|
64
|
+
*/
|
|
65
|
+
function createFetchHandler(renderer, matchRouteRules) {
|
|
66
|
+
return async function fetch(request) {
|
|
67
|
+
if (import.meta.dev) {
|
|
68
|
+
const devErrors = await import("./dev-error.mjs");
|
|
69
|
+
if (devErrors.isErrorChannelRequest(new URL(request.url).pathname)) return devErrors.fetchErrorChannel(request);
|
|
70
|
+
}
|
|
71
|
+
const event = createRequestEvent(request);
|
|
72
|
+
const rules = matchRouteRules(event.url.pathname);
|
|
73
|
+
if (rules.redirect) return redirectResponse(event, rules.redirect, rules.headers);
|
|
74
|
+
try {
|
|
75
|
+
const response = await renderer.fetch(event);
|
|
76
|
+
applyHeaders(response, rules.headers);
|
|
77
|
+
if (import.meta.prerender) applyPrerenderHints(event, response);
|
|
78
|
+
return response;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
const response = await renderError(renderer, request, error, event);
|
|
81
|
+
applyHeaders(response, rules.headers);
|
|
82
|
+
if (import.meta.prerender) applyPrerenderHints(event, response);
|
|
83
|
+
return response;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function applyHeaders(response, headers) {
|
|
88
|
+
for (const name in headers) response.headers.set(name, headers[name]);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Answer a `redirect` rule. A target carrying `**` moves a whole subtree: the tail of the
|
|
92
|
+
* request past the prefix the rule matched under is interpolated into it. Targets naming a
|
|
93
|
+
* parameter of the matched pattern are not resolved; those need a server runtime.
|
|
94
|
+
*/
|
|
95
|
+
function redirectResponse(event, redirect, headers) {
|
|
96
|
+
let location = redirect.to;
|
|
97
|
+
if (location.includes("**")) {
|
|
98
|
+
const path = event.url.pathname;
|
|
99
|
+
const tail = redirect.base && path.startsWith(redirect.base) ? path.slice(redirect.base.length) : path;
|
|
100
|
+
location = location.endsWith("/**") ? joinURL(location.slice(0, -3), tail) : location.replace("**", tail.replace(/^\//, ""));
|
|
101
|
+
}
|
|
102
|
+
const target = appendSearch(location, event.url.search);
|
|
103
|
+
const response = new Response(redirectBody(target), {
|
|
104
|
+
status: redirect.status ?? 307,
|
|
105
|
+
headers: {
|
|
106
|
+
"location": target,
|
|
107
|
+
"content-type": "text/html"
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
applyHeaders(response, headers);
|
|
111
|
+
return response;
|
|
112
|
+
}
|
|
113
|
+
/** A meta-refresh document, so a prerendered redirect is followed when served as a static file. */
|
|
114
|
+
function redirectBody(location) {
|
|
115
|
+
return `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${location.replace(REDIRECT_UNSAFE_RE, (char) => REDIRECT_ESCAPES[char])}"></head></html>`;
|
|
116
|
+
}
|
|
117
|
+
const REDIRECT_ESCAPES = {
|
|
118
|
+
"\"": "%22",
|
|
119
|
+
"'": "%27",
|
|
120
|
+
"<": "%3C",
|
|
121
|
+
">": "%3E",
|
|
122
|
+
"&": "%26"
|
|
123
|
+
};
|
|
124
|
+
const REDIRECT_UNSAFE_RE = /["'<>&]/g;
|
|
125
|
+
/** Carry the request's query onto a redirect target, ahead of any fragment the target names. */
|
|
126
|
+
function appendSearch(target, search) {
|
|
127
|
+
if (!search) return target;
|
|
128
|
+
const hashIndex = target.indexOf("#");
|
|
129
|
+
const path = hashIndex === -1 ? target : target.slice(0, hashIndex);
|
|
130
|
+
const hash = hashIndex === -1 ? "" : target.slice(hashIndex);
|
|
131
|
+
return path + (!path.includes("?") ? "?" : path.endsWith("?") || path.endsWith("&") ? "" : "&") + search.slice(1) + hash;
|
|
132
|
+
}
|
|
133
|
+
function applyPrerenderHints(event, response) {
|
|
134
|
+
const paths = event.context.nuxt?.prerenderRoutes;
|
|
135
|
+
if (!paths?.length) return;
|
|
136
|
+
response.headers.append(PRERENDER_HINTS_HEADER, paths.map((path) => encodeURIComponent(path)).join(", "));
|
|
137
|
+
}
|
|
138
|
+
async function renderError(renderer, request, error, event) {
|
|
139
|
+
const described = describeError(error);
|
|
140
|
+
const { status, statusText, message } = described;
|
|
141
|
+
const url = new URL(request.url);
|
|
142
|
+
const devErrors = import.meta.dev ? await import("./dev-error.mjs") : void 0;
|
|
143
|
+
const report = devErrors ? await devErrors.observeDevError(error, request, { expected: isExpectedError(error, described) }).catch(() => void 0) : void 0;
|
|
144
|
+
if (isJsonRequest(request, url.pathname)) {
|
|
145
|
+
const body = {
|
|
146
|
+
error: true,
|
|
147
|
+
status,
|
|
148
|
+
statusText,
|
|
149
|
+
message,
|
|
150
|
+
data: described.data,
|
|
151
|
+
...import.meta.dev && { stack: error?.stack?.split("\n").map((line) => line.trim()) }
|
|
152
|
+
};
|
|
153
|
+
return new Response(JSON.stringify(body), {
|
|
154
|
+
status,
|
|
155
|
+
statusText,
|
|
156
|
+
headers: errorResponseHeaders(event, described, "application/json;charset=utf-8")
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const data = error?.data;
|
|
160
|
+
const stack = error?.stack;
|
|
161
|
+
const errorEvent = createRequestEvent(new Request(withQuery(new URL("/__nuxt_error", url).href, {
|
|
162
|
+
status: String(status),
|
|
163
|
+
statusCode: String(status),
|
|
164
|
+
statusText,
|
|
165
|
+
statusMessage: statusText,
|
|
166
|
+
message,
|
|
167
|
+
url: request.url,
|
|
168
|
+
...data === void 0 ? {} : { data: typeof data === "string" ? data : JSON.stringify(data) },
|
|
169
|
+
...import.meta.dev && stack ? { stack } : {}
|
|
170
|
+
}), { headers: request.headers }));
|
|
171
|
+
const state = (import.meta.prerender ? event.context.nuxt : void 0) || {};
|
|
172
|
+
state["~rendering-error"] = true;
|
|
173
|
+
if (devErrors) {
|
|
174
|
+
const cause = devErrors.errorCause(error);
|
|
175
|
+
if (cause !== void 0) state["~error-cause"] = cause;
|
|
176
|
+
}
|
|
177
|
+
errorEvent.context.nuxt = state;
|
|
178
|
+
if (import.meta.prerender) event.context.nuxt = state;
|
|
179
|
+
const rendered = await renderer.fetch(errorEvent).catch(() => null);
|
|
180
|
+
if (rendered) {
|
|
181
|
+
const responseHeaders = errorResponseHeaders(event, described, "text/html;charset=utf-8", rendered.headers);
|
|
182
|
+
if (report && !import.meta.test) {
|
|
183
|
+
const html = await rendered.text();
|
|
184
|
+
const body = await report.overlay(html).catch(() => html);
|
|
185
|
+
return new Response(body, {
|
|
186
|
+
status,
|
|
187
|
+
statusText,
|
|
188
|
+
headers: responseHeaders
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return new Response(rendered.body, {
|
|
192
|
+
status,
|
|
193
|
+
statusText,
|
|
194
|
+
headers: responseHeaders
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (report) {
|
|
198
|
+
const page = await report.page().catch(() => void 0);
|
|
199
|
+
if (page) return new Response(page, {
|
|
200
|
+
status,
|
|
201
|
+
statusText,
|
|
202
|
+
headers: errorResponseHeaders(event, described, "text/html;charset=utf-8")
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return new Response(message, {
|
|
206
|
+
status,
|
|
207
|
+
statusText,
|
|
208
|
+
headers: errorResponseHeaders(event, described, "text/plain;charset=utf-8")
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function errorResponseHeaders(event, described, contentType, page) {
|
|
212
|
+
const headers = new Headers(event.res.headers);
|
|
213
|
+
if (page) mergeHeaders(headers, page);
|
|
214
|
+
mergeHeaders(headers, described.headers);
|
|
215
|
+
headers.set("content-type", contentType);
|
|
216
|
+
appendVary(headers, "accept, sec-fetch-mode");
|
|
217
|
+
return headers;
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
export { NuxtServerError, createFetchHandler, createRendererOptions };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
import { resolveServerFetchInit } from "nuxt/internal/server-default";
|
|
3
|
+
//#region src/runtime/server.ts
|
|
4
|
+
/** The `nuxt/server` helpers backed by the build's route rules and app handler. */
|
|
5
|
+
function createServerHelpers(match, loadFetch, baseURL) {
|
|
6
|
+
return {
|
|
7
|
+
getRouteRules: (event) => match(event.url.pathname),
|
|
8
|
+
matchRouteRules: (path, _method) => match(joinURL(baseURL, path)),
|
|
9
|
+
serverFetch: async (event, path, init) => {
|
|
10
|
+
return (await loadFetch())(new Request(new URL(joinURL(baseURL, path), event.req.url), resolveServerFetchInit(event, init)));
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { createServerHelpers };
|
package/package.json
CHANGED
|
@@ -1,8 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/vite-server-nightly",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.5.2-2610052030-052d82e",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/nuxt/nuxt.git",
|
|
7
|
+
"directory": "packages/vite-server"
|
|
8
|
+
},
|
|
9
|
+
"description": "Experimental pure Vite server builder for Nuxt",
|
|
10
|
+
"homepage": "https://nuxt.com",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./dist/index.mjs",
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
4
18
|
"files": [
|
|
5
19
|
"dist"
|
|
6
20
|
],
|
|
7
|
-
"
|
|
8
|
-
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@nuxt/kit": "npm:@nuxt/kit-nightly@4.5.2-2610052030-052d82e",
|
|
23
|
+
"clickable-path": "^0.1.1",
|
|
24
|
+
"defu": "^6.1.7",
|
|
25
|
+
"exsolve": "^1.1.3",
|
|
26
|
+
"mocked-exports": "^0.1.1",
|
|
27
|
+
"my-bad": "^0.2.10",
|
|
28
|
+
"pathe": "^2.0.3",
|
|
29
|
+
"rou3": "^0.9.2",
|
|
30
|
+
"srvx": "1.0.5",
|
|
31
|
+
"ufo": "^1.6.4",
|
|
32
|
+
"ultrahtml": "^1.7.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@nuxt/schema": "npm:@nuxt/schema-nightly@4.5.2-2610052030-052d82e",
|
|
36
|
+
"nuxt": "npm:nuxt-nightly@4.5.2-2610052030-052d82e",
|
|
37
|
+
"tsdown": "0.23.0",
|
|
38
|
+
"vite": "^8.3.1",
|
|
39
|
+
"vitest": "5.0.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"nuxt": "npm:nuxt-nightly@4.5.2-2610052030-052d82e",
|
|
43
|
+
"vite": "^8.3.1"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": "^22.22.3 || ^24.15.0 || >=26.0.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsdown",
|
|
50
|
+
"test:attw": "node ../../scripts/test-attw.ts"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/.gitkeep
DELETED
|
File without changes
|