nitro-nightly 3.1.0-20251028-004953-57503e42 → 3.1.0-20251028-110430-e607b753
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/_build/assets.mjs +235 -0
- package/dist/_build/build.mjs +21 -0
- package/dist/_build/config.mjs +124 -0
- package/dist/_build/info.mjs +39 -0
- package/dist/_build/plugins.mjs +1041 -0
- package/dist/_build/prepare.mjs +17 -0
- package/dist/{_chunks/build2.mjs → _build/rolldown.mjs} +238 -64
- package/dist/_build/rollup.mjs +404 -0
- package/dist/_build/snapshot.mjs +61 -0
- package/dist/_build/types.mjs +268 -0
- package/dist/_build/vite.mjs +3266 -0
- package/dist/{cli → _cli}/build.mjs +2 -3
- package/dist/_cli/dev.mjs +205 -0
- package/dist/{cli/index2.mjs → _cli/index.mjs} +1 -2
- package/dist/{cli → _cli}/list.mjs +2 -3
- package/dist/{cli → _cli}/prepare.mjs +2 -3
- package/dist/{cli → _cli}/run.mjs +2 -3
- package/dist/_deps/@jridgewell/gen-mapping.mjs +189 -0
- package/dist/_deps/@jridgewell/remapping.mjs +137 -0
- package/dist/_deps/@jridgewell/resolve-uri.mjs +231 -0
- package/dist/_deps/@jridgewell/sourcemap-codec.mjs +173 -0
- package/dist/_deps/@jridgewell/trace-mapping.mjs +170 -0
- package/dist/_deps/@pi0/vite-plugin-fullstack.mjs +575 -0
- package/dist/_deps/@rollup/plugin-alias.mjs +89 -0
- package/dist/_deps/@rollup/plugin-commonjs.mjs +2376 -0
- package/dist/{_chunks/index2.mjs → _deps/@rollup/plugin-inject.mjs} +5 -90
- package/dist/_deps/@rollup/plugin-json.mjs +37 -0
- package/dist/_deps/@rollup/plugin-node-resolve.mjs +1386 -0
- package/dist/_deps/@rollup/plugin-replace.mjs +133 -0
- package/dist/_deps/@rollup/pluginutils.mjs +346 -0
- package/dist/_deps/acorn.mjs +6225 -0
- package/dist/_deps/c12.mjs +510 -0
- package/dist/_deps/chokidar.mjs +1428 -0
- package/dist/_deps/citty.mjs +460 -0
- package/dist/_deps/commondir.mjs +77 -0
- package/dist/_deps/compatx.mjs +76 -0
- package/dist/_deps/confbox.mjs +300 -0
- package/dist/_deps/debug.mjs +885 -0
- package/dist/_deps/deepmerge.mjs +147 -0
- package/dist/_deps/depd.mjs +550 -0
- package/dist/_deps/dot-prop.mjs +282 -0
- package/dist/_deps/dotenv.mjs +555 -0
- package/dist/_deps/duplexer.mjs +1 -0
- package/dist/_deps/ee-first.mjs +104 -0
- package/dist/_deps/encodeurl.mjs +69 -0
- package/dist/_deps/escape-html.mjs +87 -0
- package/dist/_deps/escape-string-regexp.mjs +13 -0
- package/dist/_deps/estree-walker.mjs +433 -0
- package/dist/_deps/etag.mjs +147 -0
- package/dist/_deps/exsolve.mjs +1416 -0
- package/dist/_deps/fdir.mjs +569 -0
- package/dist/_deps/fresh.mjs +145 -0
- package/dist/_deps/function-bind.mjs +106 -0
- package/dist/{_chunks/index4.mjs → _deps/giget.mjs} +21 -776
- package/dist/_deps/gzip-size.mjs +19 -0
- package/dist/_deps/hasown.mjs +19 -0
- package/dist/_deps/http-errors.mjs +307 -0
- package/dist/_deps/httpxy.mjs +580 -0
- package/dist/_deps/inherits.mjs +57 -0
- package/dist/_deps/is-core-module.mjs +596 -0
- package/dist/_deps/is-module.mjs +25 -0
- package/dist/_deps/is-reference.mjs +31 -0
- package/dist/_deps/js-tokens.mjs +411 -0
- package/dist/_deps/knitwork.mjs +172 -0
- package/dist/_deps/local-pkg.mjs +163 -0
- package/dist/_deps/magic-string.mjs +1296 -0
- package/dist/_deps/mime-db.mjs +11685 -0
- package/dist/_deps/mime-types.mjs +287 -0
- package/dist/_deps/mime.mjs +1172 -0
- package/dist/_deps/mlly.mjs +2413 -0
- package/dist/_deps/ms.mjs +172 -0
- package/dist/_deps/node-fetch-native.mjs +3 -0
- package/dist/_deps/nypm.mjs +219 -0
- package/dist/_deps/on-finished.mjs +246 -0
- package/dist/_deps/parseurl.mjs +168 -0
- package/dist/_deps/path-parse.mjs +85 -0
- package/dist/{_chunks/pathe.M-eThtNZ.mjs → _deps/pathe.mjs} +48 -1
- package/dist/_deps/perfect-debounce.mjs +88 -0
- package/dist/_deps/picomatch.mjs +2144 -0
- package/dist/_deps/pkg-types.mjs +247 -0
- package/dist/_deps/pretty-bytes.mjs +180 -0
- package/dist/_deps/quansync.mjs +99 -0
- package/dist/_deps/range-parser.mjs +171 -0
- package/dist/_deps/rc9.mjs +219 -0
- package/dist/_deps/readdirp.mjs +245 -0
- package/dist/_deps/resolve.mjs +1260 -0
- package/dist/_deps/rou3.mjs +326 -0
- package/dist/_deps/send.mjs +1022 -0
- package/dist/_deps/serve-static.mjs +228 -0
- package/dist/_deps/setprototypeof.mjs +26 -0
- package/dist/_deps/statuses.mjs +457 -0
- package/dist/_deps/strip-literal.mjs +67 -0
- package/dist/_deps/supports-color.mjs +44 -0
- package/dist/_deps/tinyexec.mjs +552 -0
- package/dist/_deps/tinyglobby.mjs +293 -0
- package/dist/_deps/toidentifier.mjs +41 -0
- package/dist/_deps/ultrahtml.mjs +3 -0
- package/dist/_deps/unimport.mjs +2267 -0
- package/dist/_deps/unplugin-utils.mjs +65 -0
- package/dist/_deps/unplugin.mjs +1294 -0
- package/dist/_deps/untyped.mjs +375 -0
- package/dist/{_chunks/info.mjs → _deps/unwasm.mjs} +8 -4122
- package/dist/_deps/webpack-virtual-modules.mjs +360 -0
- package/dist/_presets/_all.mjs +59 -0
- package/dist/_presets/_nitro.mjs +74 -0
- package/dist/_presets/_resolve.mjs +64 -0
- package/dist/_presets/_static.mjs +69 -0
- package/dist/_presets/_types.mjs +3 -0
- package/dist/_presets/_utils.mjs +31 -0
- package/dist/_presets/alwaysdata.mjs +17 -0
- package/dist/_presets/aws-amplify.mjs +111 -0
- package/dist/_presets/aws-lambda.mjs +23 -0
- package/dist/_presets/azure.mjs +162 -0
- package/dist/_presets/bun.mjs +19 -0
- package/dist/_presets/cleavr.mjs +15 -0
- package/dist/_presets/cloudflare.mjs +608 -0
- package/dist/_presets/deno.mjs +196 -0
- package/dist/_presets/digitalocean.mjs +14 -0
- package/dist/_presets/firebase.mjs +47 -0
- package/dist/_presets/flightcontrol.mjs +14 -0
- package/dist/_presets/genezio.mjs +13 -0
- package/dist/_presets/heroku.mjs +14 -0
- package/dist/_presets/iis.mjs +194 -0
- package/dist/_presets/index.mjs +62 -0
- package/dist/_presets/koyeb.mjs +14 -0
- package/dist/_presets/netlify.mjs +241 -0
- package/dist/_presets/node.mjs +54 -0
- package/dist/_presets/platform.mjs +14 -0
- package/dist/_presets/render.mjs +14 -0
- package/dist/_presets/standard.mjs +23 -0
- package/dist/_presets/stormkit.mjs +18 -0
- package/dist/_presets/vercel.mjs +365 -0
- package/dist/_presets/winterjs.mjs +22 -0
- package/dist/_presets/zeabur.mjs +69 -0
- package/dist/_presets/zerops.mjs +27 -0
- package/dist/cli/index.mjs +7 -464
- package/dist/index.mjs +122 -34
- package/dist/vite.mjs +118 -44
- package/package.json +1 -1
- package/dist/_chunks/app.mjs +0 -19797
- package/dist/_chunks/build.mjs +0 -86
- package/dist/_chunks/build3.mjs +0 -6538
- package/dist/_chunks/detect-acorn.mjs +0 -503
- package/dist/_chunks/index.mjs +0 -22256
- package/dist/_chunks/index3.mjs +0 -1062
- package/dist/_chunks/json5.mjs +0 -68
- package/dist/_chunks/jsonc.mjs +0 -51
- package/dist/_chunks/plugin.mjs +0 -1560
- package/dist/_chunks/server.mjs +0 -254
- package/dist/_chunks/snapshot.mjs +0 -376
- package/dist/_chunks/toml.mjs +0 -259
- package/dist/_chunks/yaml.mjs +0 -86
- package/dist/cli/dev.mjs +0 -95
- package/dist/presets.mjs +0 -2494
- /package/dist/{cli → _cli}/common.mjs +0 -0
|
@@ -0,0 +1,3266 @@
|
|
|
1
|
+
import { pathToFileURL } from 'node:url';
|
|
2
|
+
import { colors } from 'consola/utils';
|
|
3
|
+
import defu$1, { defu } from 'defu';
|
|
4
|
+
import { m as mime } from '../_deps/mime.mjs';
|
|
5
|
+
import { r as resolveNitroPath, p as prettyPath, s as scanUnprefixedPublicAssets, c as compressPublicAssets, w as writeFile, a as copyPublicAssets } from './assets.mjs';
|
|
6
|
+
import { c as createRouter, a as addRoute, b as compileRouterToString, f as findRoute, d as findAllRoutes } from '../_deps/rou3.mjs';
|
|
7
|
+
import { withLeadingSlash, withoutTrailingSlash, withTrailingSlash, parseURL, withBase, joinURL, withoutBase } from 'ufo';
|
|
8
|
+
import { b as build$1 } from './build.mjs';
|
|
9
|
+
import { a as scanAndSyncOptions, s as scanHandlers, r as runParallel } from './rolldown.mjs';
|
|
10
|
+
import { z, P } from '../_deps/ultrahtml.mjs';
|
|
11
|
+
import { a as resolve, j as join, n as normalize, r as relative, d as dirname$1, c as basename, i as isAbsolute } from '../_deps/pathe.mjs';
|
|
12
|
+
import { fromNodeHandler, HTTPError, defineHandler, getRequestIP, getRequestURL, H3, toEventHandler, withBase as withBase$1 } from 'h3';
|
|
13
|
+
import { version } from 'nitro/meta';
|
|
14
|
+
import consola, { consola as consola$1 } from 'consola';
|
|
15
|
+
import { readFile, rm, writeFile as writeFile$1, mkdir, readlink } from 'node:fs/promises';
|
|
16
|
+
import { watch } from '../_deps/chokidar.mjs';
|
|
17
|
+
import { serve, NodeRequest, sendNodeResponse } from 'srvx/node';
|
|
18
|
+
import { d as debounce } from '../_deps/perfect-debounce.mjs';
|
|
19
|
+
import { isDebug, isTest, isCI } from 'std-env';
|
|
20
|
+
import { p as prepare } from './prepare.mjs';
|
|
21
|
+
import './types.mjs';
|
|
22
|
+
import { Hookable, createDebugger } from 'hookable';
|
|
23
|
+
import { w as watchConfig, l as loadConfig } from '../_deps/c12.mjs';
|
|
24
|
+
import { r as resolveCompatibilityDatesFromEnv, a as resolveCompatibilityDates, f as formatCompatibilityDate } from '../_deps/compatx.mjs';
|
|
25
|
+
import { klona } from 'klona/full';
|
|
26
|
+
import { runtimeDir, pkgDir, runtimeDependencies } from 'nitro/runtime/meta';
|
|
27
|
+
import { existsSync, watch as watch$1 } from 'node:fs';
|
|
28
|
+
import { e as escapeStringRegexp } from '../_deps/escape-string-regexp.mjs';
|
|
29
|
+
import { r as resolveModuleExportNames, s as sanitizeFilePath } from '../_deps/mlly.mjs';
|
|
30
|
+
import { f as findWorkspaceDir } from '../_deps/pkg-types.mjs';
|
|
31
|
+
import { r as resolveModulePath } from '../_deps/exsolve.mjs';
|
|
32
|
+
import { createJiti } from 'jiti';
|
|
33
|
+
import { ofetch } from 'ofetch';
|
|
34
|
+
import { c as createStorage } from './snapshot.mjs';
|
|
35
|
+
import { hash } from 'ohash';
|
|
36
|
+
import { c as createUnimport } from '../_deps/unimport.mjs';
|
|
37
|
+
import 'node:zlib';
|
|
38
|
+
import { Worker } from 'node:worker_threads';
|
|
39
|
+
import { Agent } from 'undici';
|
|
40
|
+
import { s as serveStatic } from '../_deps/serve-static.mjs';
|
|
41
|
+
import { c as createProxyServer } from '../_deps/httpxy.mjs';
|
|
42
|
+
import { resolve as resolve$1, dirname, join as join$1 } from 'node:path';
|
|
43
|
+
import { ErrorParser } from 'youch-core';
|
|
44
|
+
import { Youch } from 'youch';
|
|
45
|
+
import { SourceMapConsumer } from 'source-map';
|
|
46
|
+
import { FastResponse } from 'srvx';
|
|
47
|
+
import { a as alias } from '../_deps/@rollup/plugin-alias.mjs';
|
|
48
|
+
import { i as inject } from '../_deps/@rollup/plugin-inject.mjs';
|
|
49
|
+
import { b as baseBuildPlugins, r as replace } from './plugins.mjs';
|
|
50
|
+
import { b as baseBuildConfig } from './config.mjs';
|
|
51
|
+
import 'klona';
|
|
52
|
+
import 'unstorage';
|
|
53
|
+
import { w as writeBuildInfo } from './info.mjs';
|
|
54
|
+
import { DevEnvironment } from 'vite';
|
|
55
|
+
import { getRandomPort } from 'get-port-please';
|
|
56
|
+
import { spawn } from 'node:child_process';
|
|
57
|
+
import { a as assetsPlugin } from '../_deps/@pi0/vite-plugin-fullstack.mjs';
|
|
58
|
+
|
|
59
|
+
const NitroDefaults = {
|
|
60
|
+
// General
|
|
61
|
+
compatibilityDate: "latest",
|
|
62
|
+
debug: isDebug,
|
|
63
|
+
logLevel: isTest ? 1 : 3,
|
|
64
|
+
runtimeConfig: { app: {}, nitro: {} },
|
|
65
|
+
// Dirs
|
|
66
|
+
scanDirs: [],
|
|
67
|
+
buildDir: ".nitro",
|
|
68
|
+
output: {
|
|
69
|
+
dir: "{{ rootDir }}/.output",
|
|
70
|
+
serverDir: "{{ output.dir }}/server",
|
|
71
|
+
publicDir: "{{ output.dir }}/public"
|
|
72
|
+
},
|
|
73
|
+
// Features
|
|
74
|
+
experimental: {},
|
|
75
|
+
future: {},
|
|
76
|
+
storage: {},
|
|
77
|
+
devStorage: {},
|
|
78
|
+
bundledStorage: [],
|
|
79
|
+
publicAssets: [],
|
|
80
|
+
serverAssets: [],
|
|
81
|
+
plugins: [],
|
|
82
|
+
tasks: {},
|
|
83
|
+
scheduledTasks: {},
|
|
84
|
+
imports: false,
|
|
85
|
+
virtual: {},
|
|
86
|
+
compressPublicAssets: false,
|
|
87
|
+
ignore: [],
|
|
88
|
+
// Dev
|
|
89
|
+
dev: false,
|
|
90
|
+
devServer: { watch: [] },
|
|
91
|
+
watchOptions: { ignoreInitial: true },
|
|
92
|
+
devProxy: {},
|
|
93
|
+
// Logging
|
|
94
|
+
logging: {
|
|
95
|
+
compressedSizes: true,
|
|
96
|
+
buildSuccess: true
|
|
97
|
+
},
|
|
98
|
+
// Routing
|
|
99
|
+
baseURL: process.env.NITRO_APP_BASE_URL || "/",
|
|
100
|
+
handlers: [],
|
|
101
|
+
devHandlers: [],
|
|
102
|
+
errorHandler: void 0,
|
|
103
|
+
routeRules: {},
|
|
104
|
+
prerender: {
|
|
105
|
+
autoSubfolderIndex: true,
|
|
106
|
+
concurrency: 1,
|
|
107
|
+
interval: 0,
|
|
108
|
+
retry: 3,
|
|
109
|
+
retryDelay: 500,
|
|
110
|
+
failOnError: false,
|
|
111
|
+
crawlLinks: false,
|
|
112
|
+
ignore: [],
|
|
113
|
+
routes: []
|
|
114
|
+
},
|
|
115
|
+
// Rollup
|
|
116
|
+
builder: void 0,
|
|
117
|
+
moduleSideEffects: ["unenv/polyfill/", resolve(runtimeDir, "polyfill/")],
|
|
118
|
+
replace: {},
|
|
119
|
+
node: true,
|
|
120
|
+
sourceMap: true,
|
|
121
|
+
esbuild: {
|
|
122
|
+
options: {
|
|
123
|
+
jsxFactory: "h",
|
|
124
|
+
jsxFragment: "Fragment"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
// Advanced
|
|
128
|
+
typescript: {
|
|
129
|
+
strict: true,
|
|
130
|
+
generateRuntimeConfigTypes: false,
|
|
131
|
+
generateTsConfig: false,
|
|
132
|
+
tsconfigPath: "types/tsconfig.json",
|
|
133
|
+
internalPaths: false,
|
|
134
|
+
tsConfig: {}
|
|
135
|
+
},
|
|
136
|
+
nodeModulesDirs: [],
|
|
137
|
+
hooks: {},
|
|
138
|
+
commands: {},
|
|
139
|
+
// Framework
|
|
140
|
+
framework: {
|
|
141
|
+
name: "nitro",
|
|
142
|
+
version: ""
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
async function resolveAssetsOptions(options) {
|
|
147
|
+
for (const publicAsset of options.publicAssets) {
|
|
148
|
+
publicAsset.dir = resolve(options.srcDir, publicAsset.dir);
|
|
149
|
+
publicAsset.baseURL = withLeadingSlash(
|
|
150
|
+
withoutTrailingSlash(publicAsset.baseURL || "/")
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
for (const dir of options.scanDirs) {
|
|
154
|
+
const publicDir = resolve(dir, "public");
|
|
155
|
+
if (!existsSync(publicDir)) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (options.publicAssets.some((asset) => asset.dir === publicDir)) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
options.publicAssets.push({ dir: publicDir });
|
|
162
|
+
}
|
|
163
|
+
for (const serverAsset of options.serverAssets) {
|
|
164
|
+
serverAsset.dir = resolve(options.srcDir, serverAsset.dir);
|
|
165
|
+
}
|
|
166
|
+
options.serverAssets.push({
|
|
167
|
+
baseName: "server",
|
|
168
|
+
dir: resolve(options.srcDir, "assets")
|
|
169
|
+
});
|
|
170
|
+
for (const asset of options.publicAssets) {
|
|
171
|
+
asset.baseURL = asset.baseURL || "/";
|
|
172
|
+
const isTopLevel = asset.baseURL === "/";
|
|
173
|
+
asset.fallthrough = asset.fallthrough ?? isTopLevel;
|
|
174
|
+
const routeRule = options.routeRules[asset.baseURL + "/**"];
|
|
175
|
+
asset.maxAge = routeRule?.cache?.maxAge ?? asset.maxAge ?? 0;
|
|
176
|
+
if (asset.maxAge && !asset.fallthrough) {
|
|
177
|
+
options.routeRules[asset.baseURL + "/**"] = defu(routeRule, {
|
|
178
|
+
headers: {
|
|
179
|
+
"cache-control": `public, max-age=${asset.maxAge}, immutable`
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function resolveCompatibilityOptions(options) {
|
|
187
|
+
options.compatibilityDate = resolveCompatibilityDatesFromEnv(
|
|
188
|
+
options.compatibilityDate
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function resolveDatabaseOptions(options) {
|
|
193
|
+
if (options.experimental.database && options.imports) {
|
|
194
|
+
options.imports.presets.push({
|
|
195
|
+
from: "nitro/runtime/internal/database",
|
|
196
|
+
imports: ["useDatabase"]
|
|
197
|
+
});
|
|
198
|
+
if (options.dev && !options.database && !options.devDatabase) {
|
|
199
|
+
options.devDatabase = {
|
|
200
|
+
default: {
|
|
201
|
+
connector: "sqlite",
|
|
202
|
+
options: {
|
|
203
|
+
cwd: options.rootDir
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
} else if (options.node && !options.database) {
|
|
208
|
+
options.database = {
|
|
209
|
+
default: {
|
|
210
|
+
connector: "sqlite",
|
|
211
|
+
options: {}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function resolveExportConditionsOptions(options) {
|
|
219
|
+
options.exportConditions = _resolveExportConditions(
|
|
220
|
+
options.exportConditions || [],
|
|
221
|
+
{ dev: options.dev, node: options.node, wasm: options.experimental.wasm }
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function _resolveExportConditions(conditions, opts) {
|
|
225
|
+
const resolvedConditions = [];
|
|
226
|
+
resolvedConditions.push(opts.dev ? "development" : "production");
|
|
227
|
+
resolvedConditions.push(...conditions);
|
|
228
|
+
if (opts.node) {
|
|
229
|
+
resolvedConditions.push("node");
|
|
230
|
+
} else {
|
|
231
|
+
resolvedConditions.push(
|
|
232
|
+
"wintercg",
|
|
233
|
+
"worker",
|
|
234
|
+
"web",
|
|
235
|
+
"browser",
|
|
236
|
+
"workerd",
|
|
237
|
+
"edge-light",
|
|
238
|
+
"netlify",
|
|
239
|
+
"edge-routine",
|
|
240
|
+
"deno"
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (opts.wasm) {
|
|
244
|
+
resolvedConditions.push("wasm", "unwasm");
|
|
245
|
+
}
|
|
246
|
+
resolvedConditions.push("import", "default");
|
|
247
|
+
return resolvedConditions.filter(
|
|
248
|
+
(c, i) => resolvedConditions.indexOf(c) === i
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function resolveImportsOptions(options) {
|
|
253
|
+
if (options.imports === false) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
options.imports.presets ??= [];
|
|
257
|
+
options.imports.presets.push(...getNitroImportsPreset());
|
|
258
|
+
const h3Exports = await resolveModuleExportNames("h3", {
|
|
259
|
+
url: import.meta.url
|
|
260
|
+
});
|
|
261
|
+
options.imports.presets ??= [];
|
|
262
|
+
options.imports.presets.push({
|
|
263
|
+
from: "h3",
|
|
264
|
+
imports: h3Exports.filter((n) => !/^[A-Z]/.test(n) && n !== "use")
|
|
265
|
+
});
|
|
266
|
+
options.imports.dirs ??= [];
|
|
267
|
+
options.imports.dirs.push(
|
|
268
|
+
...options.scanDirs.map((dir) => join(dir, "utils/**/*"))
|
|
269
|
+
);
|
|
270
|
+
if (Array.isArray(options.imports.exclude) && options.imports.exclude.length === 0) {
|
|
271
|
+
options.imports.exclude.push(/[/\\]\.git[/\\]/);
|
|
272
|
+
options.imports.exclude.push(options.buildDir);
|
|
273
|
+
const scanDirsInNodeModules = options.scanDirs.map((dir) => dir.match(/(?<=\/)node_modules\/(.+)$/)?.[1]).filter(Boolean);
|
|
274
|
+
options.imports.exclude.push(
|
|
275
|
+
scanDirsInNodeModules.length > 0 ? new RegExp(
|
|
276
|
+
`node_modules\\/(?!${scanDirsInNodeModules.map((dir) => escapeStringRegexp(dir)).join("|")})`
|
|
277
|
+
) : /[/\\]node_modules[/\\]/
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function getNitroImportsPreset() {
|
|
282
|
+
return [
|
|
283
|
+
{
|
|
284
|
+
from: "nitro/runtime/internal/app",
|
|
285
|
+
imports: ["useNitroApp"]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
from: "nitro/runtime/internal/runtime-config",
|
|
289
|
+
imports: ["useRuntimeConfig"]
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
from: "nitro/runtime/internal/plugin",
|
|
293
|
+
imports: ["defineNitroPlugin", "nitroPlugin"]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
from: "nitro/runtime/internal/cache",
|
|
297
|
+
imports: [
|
|
298
|
+
"defineCachedFunction",
|
|
299
|
+
"defineCachedEventHandler",
|
|
300
|
+
"defineCachedHandler",
|
|
301
|
+
"cachedFunction",
|
|
302
|
+
"cachedEventHandler"
|
|
303
|
+
]
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
from: "nitro/runtime/internal/storage",
|
|
307
|
+
imports: ["useStorage"]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
from: "nitro/runtime/internal/renderer",
|
|
311
|
+
imports: ["defineRenderHandler"]
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
from: "nitro/runtime/internal/meta",
|
|
315
|
+
imports: ["defineRouteMeta"]
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
from: "nitro/runtime/internal/route-rules",
|
|
319
|
+
imports: ["getRouteRules"]
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
from: "nitro/runtime/internal/context",
|
|
323
|
+
imports: ["useRequest"]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
from: "nitro/runtime/internal/task",
|
|
327
|
+
imports: ["defineTask", "runTask"]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
from: "nitro/runtime/internal/error/utils",
|
|
331
|
+
imports: ["defineNitroErrorHandler"]
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
from: "nitro/deps/ofetch",
|
|
335
|
+
imports: ["$fetch"]
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function resolveOpenAPIOptions(options) {
|
|
341
|
+
if (!options.experimental.openAPI) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (!options.dev && !options.openAPI?.production) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const shouldPrerender = !options.dev && options.openAPI?.production === "prerender";
|
|
348
|
+
const handlersEnv = shouldPrerender ? "prerender" : "";
|
|
349
|
+
const prerenderRoutes = [];
|
|
350
|
+
const jsonRoute = options.openAPI?.route || "/_openapi.json";
|
|
351
|
+
prerenderRoutes.push(jsonRoute);
|
|
352
|
+
options.handlers.push({
|
|
353
|
+
route: jsonRoute,
|
|
354
|
+
env: handlersEnv,
|
|
355
|
+
handler: join(runtimeDir, "internal/routes/openapi")
|
|
356
|
+
});
|
|
357
|
+
if (options.openAPI?.ui?.scalar !== false) {
|
|
358
|
+
const scalarRoute = options.openAPI?.ui?.scalar?.route || "/_scalar";
|
|
359
|
+
prerenderRoutes.push(scalarRoute);
|
|
360
|
+
options.handlers.push({
|
|
361
|
+
route: options.openAPI?.ui?.scalar?.route || "/_scalar",
|
|
362
|
+
env: handlersEnv,
|
|
363
|
+
handler: join(runtimeDir, "internal/routes/scalar")
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (options.openAPI?.ui?.swagger !== false) {
|
|
367
|
+
const swaggerRoute = options.openAPI?.ui?.swagger?.route || "/_swagger";
|
|
368
|
+
prerenderRoutes.push(swaggerRoute);
|
|
369
|
+
options.handlers.push({
|
|
370
|
+
route: swaggerRoute,
|
|
371
|
+
env: handlersEnv,
|
|
372
|
+
handler: join(runtimeDir, "internal/routes/swagger")
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
if (shouldPrerender) {
|
|
376
|
+
options.prerender ??= {};
|
|
377
|
+
options.prerender.routes ??= [];
|
|
378
|
+
options.prerender.routes.push(...prerenderRoutes);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const RESOLVE_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"];
|
|
383
|
+
async function resolvePathOptions(options) {
|
|
384
|
+
options.rootDir = resolve(options.rootDir || ".") + "/";
|
|
385
|
+
options.workspaceDir ||= await findWorkspaceDir(options.rootDir).catch(() => options.rootDir) + "/";
|
|
386
|
+
for (const key of ["srcDir", "buildDir"]) {
|
|
387
|
+
options[key] = resolve(options.rootDir, options[key] || ".");
|
|
388
|
+
}
|
|
389
|
+
options.alias ??= {};
|
|
390
|
+
if (!options.static && !options.entry) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
`Nitro entry is missing! Is "${options.preset}" preset correct?`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
if (options.entry) {
|
|
396
|
+
options.entry = resolveNitroPath(options.entry, options);
|
|
397
|
+
}
|
|
398
|
+
options.output.dir = resolveNitroPath(
|
|
399
|
+
options.output.dir || NitroDefaults.output.dir,
|
|
400
|
+
options,
|
|
401
|
+
options.rootDir
|
|
402
|
+
) + "/";
|
|
403
|
+
options.output.publicDir = resolveNitroPath(
|
|
404
|
+
options.output.publicDir || NitroDefaults.output.publicDir,
|
|
405
|
+
options,
|
|
406
|
+
options.rootDir
|
|
407
|
+
) + "/";
|
|
408
|
+
options.output.serverDir = resolveNitroPath(
|
|
409
|
+
options.output.serverDir || NitroDefaults.output.serverDir,
|
|
410
|
+
options,
|
|
411
|
+
options.rootDir
|
|
412
|
+
) + "/";
|
|
413
|
+
options.nodeModulesDirs.push(resolve(options.rootDir, "node_modules"));
|
|
414
|
+
options.nodeModulesDirs.push(resolve(options.workspaceDir, "node_modules"));
|
|
415
|
+
options.nodeModulesDirs.push(resolve(pkgDir, "dist/node_modules"));
|
|
416
|
+
options.nodeModulesDirs.push(resolve(pkgDir, "node_modules"));
|
|
417
|
+
options.nodeModulesDirs.push(resolve(pkgDir, ".."));
|
|
418
|
+
options.nodeModulesDirs = [
|
|
419
|
+
...new Set(
|
|
420
|
+
// Adding trailing slash to optimize resolve performance (path is explicitly a dir)
|
|
421
|
+
options.nodeModulesDirs.map((dir) => resolve(options.rootDir, dir) + "/")
|
|
422
|
+
)
|
|
423
|
+
];
|
|
424
|
+
options.plugins = options.plugins.map((p) => resolveNitroPath(p, options));
|
|
425
|
+
options.scanDirs.unshift(options.srcDir);
|
|
426
|
+
options.scanDirs = options.scanDirs.map(
|
|
427
|
+
(dir) => resolve(options.srcDir, dir)
|
|
428
|
+
);
|
|
429
|
+
options.scanDirs = [...new Set(options.scanDirs.map((dir) => dir + "/"))];
|
|
430
|
+
if (options.serverEntry) {
|
|
431
|
+
options.serverEntry = resolveModulePath(
|
|
432
|
+
resolveNitroPath(options.serverEntry, options),
|
|
433
|
+
{
|
|
434
|
+
from: options.scanDirs,
|
|
435
|
+
extensions: RESOLVE_EXTENSIONS
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
} else {
|
|
439
|
+
const defaultServerEntry = resolveModulePath("./server", {
|
|
440
|
+
from: options.scanDirs,
|
|
441
|
+
extensions: RESOLVE_EXTENSIONS,
|
|
442
|
+
try: true
|
|
443
|
+
});
|
|
444
|
+
if (defaultServerEntry) {
|
|
445
|
+
options.serverEntry = defaultServerEntry;
|
|
446
|
+
consola.info(
|
|
447
|
+
`Using \`${prettyPath(defaultServerEntry)}\` as server entry.`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (options.renderer?.entry) {
|
|
452
|
+
options.renderer.entry = resolveModulePath(
|
|
453
|
+
resolveNitroPath(options.renderer?.entry, options),
|
|
454
|
+
{
|
|
455
|
+
from: options.scanDirs,
|
|
456
|
+
extensions: RESOLVE_EXTENSIONS
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
if (options.renderer?.template) {
|
|
461
|
+
options.renderer.template = resolveModulePath(
|
|
462
|
+
resolveNitroPath(options.renderer?.template, options),
|
|
463
|
+
{
|
|
464
|
+
from: options.scanDirs,
|
|
465
|
+
extensions: [".html"]
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
} else if (!options.renderer?.entry) {
|
|
469
|
+
const defaultIndex = resolveModulePath("./index.html", {
|
|
470
|
+
from: options.scanDirs,
|
|
471
|
+
extensions: [".html"],
|
|
472
|
+
try: true
|
|
473
|
+
});
|
|
474
|
+
if (defaultIndex) {
|
|
475
|
+
options.renderer ??= {};
|
|
476
|
+
options.renderer.template = defaultIndex;
|
|
477
|
+
consola.info(
|
|
478
|
+
`Using \`${prettyPath(defaultIndex)}\` as renderer template.`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (options.renderer?.template && !options.renderer?.entry) {
|
|
483
|
+
options.renderer ??= {};
|
|
484
|
+
options.renderer.entry = join(
|
|
485
|
+
runtimeDir,
|
|
486
|
+
"internal/routes/renderer-template" + (options.dev ? ".dev" : "")
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
async function resolveRouteRulesOptions(options) {
|
|
492
|
+
options.routeRules = defu(options.routeRules, options.routes || {});
|
|
493
|
+
options.routeRules = normalizeRouteRules(options);
|
|
494
|
+
}
|
|
495
|
+
function normalizeRouteRules(config) {
|
|
496
|
+
const normalizedRules = {};
|
|
497
|
+
for (let path in config.routeRules) {
|
|
498
|
+
const routeConfig = config.routeRules[path];
|
|
499
|
+
path = withLeadingSlash(path);
|
|
500
|
+
const routeRules = {
|
|
501
|
+
...routeConfig,
|
|
502
|
+
redirect: void 0,
|
|
503
|
+
proxy: void 0
|
|
504
|
+
};
|
|
505
|
+
if (routeConfig.redirect) {
|
|
506
|
+
routeRules.redirect = {
|
|
507
|
+
// @ts-ignore
|
|
508
|
+
to: "/",
|
|
509
|
+
status: 307,
|
|
510
|
+
...typeof routeConfig.redirect === "string" ? { to: routeConfig.redirect } : routeConfig.redirect
|
|
511
|
+
};
|
|
512
|
+
if (path.endsWith("/**")) {
|
|
513
|
+
routeRules.redirect._redirectStripBase = path.slice(0, -3);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (routeConfig.proxy) {
|
|
517
|
+
routeRules.proxy = typeof routeConfig.proxy === "string" ? { to: routeConfig.proxy } : routeConfig.proxy;
|
|
518
|
+
if (path.endsWith("/**")) {
|
|
519
|
+
routeRules.proxy._proxyStripBase = path.slice(0, -3);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (routeConfig.cors) {
|
|
523
|
+
routeRules.headers = {
|
|
524
|
+
"access-control-allow-origin": "*",
|
|
525
|
+
"access-control-allow-methods": "*",
|
|
526
|
+
"access-control-allow-headers": "*",
|
|
527
|
+
"access-control-max-age": "0",
|
|
528
|
+
...routeRules.headers
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (routeConfig.swr) {
|
|
532
|
+
routeRules.cache = routeRules.cache || {};
|
|
533
|
+
routeRules.cache.swr = true;
|
|
534
|
+
if (typeof routeConfig.swr === "number") {
|
|
535
|
+
routeRules.cache.maxAge = routeConfig.swr;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (routeConfig.cache === false) {
|
|
539
|
+
routeRules.cache = false;
|
|
540
|
+
}
|
|
541
|
+
normalizedRules[path] = routeRules;
|
|
542
|
+
}
|
|
543
|
+
return normalizedRules;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
async function resolveRuntimeConfigOptions(options) {
|
|
547
|
+
options.runtimeConfig = normalizeRuntimeConfig(options);
|
|
548
|
+
}
|
|
549
|
+
function normalizeRuntimeConfig(config) {
|
|
550
|
+
provideFallbackValues(config.runtimeConfig || {});
|
|
551
|
+
const runtimeConfig = defu$1(
|
|
552
|
+
config.runtimeConfig,
|
|
553
|
+
{
|
|
554
|
+
app: {
|
|
555
|
+
baseURL: config.baseURL
|
|
556
|
+
},
|
|
557
|
+
nitro: {
|
|
558
|
+
envExpansion: config.experimental?.envExpansion,
|
|
559
|
+
openAPI: config.openAPI
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
runtimeConfig.nitro.routeRules = config.routeRules;
|
|
564
|
+
checkSerializableRuntimeConfig(runtimeConfig);
|
|
565
|
+
return runtimeConfig;
|
|
566
|
+
}
|
|
567
|
+
function provideFallbackValues(obj) {
|
|
568
|
+
for (const key in obj) {
|
|
569
|
+
if (obj[key] === void 0 || obj[key] === null) {
|
|
570
|
+
obj[key] = "";
|
|
571
|
+
} else if (typeof obj[key] === "object") {
|
|
572
|
+
provideFallbackValues(obj[key]);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function checkSerializableRuntimeConfig(obj, path = []) {
|
|
577
|
+
if (isPrimitiveValue(obj)) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
for (const key in obj) {
|
|
581
|
+
const value = obj[key];
|
|
582
|
+
if (value === null || value === void 0 || isPrimitiveValue(value)) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
if (Array.isArray(value)) {
|
|
586
|
+
for (const [index, item] of value.entries())
|
|
587
|
+
checkSerializableRuntimeConfig(item, [...path, `${key}[${index}]`]);
|
|
588
|
+
} else if (typeof value === "object" && value.constructor === Object && (!value.constructor?.name || value.constructor.name === "Object")) {
|
|
589
|
+
checkSerializableRuntimeConfig(value, [...path, key]);
|
|
590
|
+
} else {
|
|
591
|
+
console.warn(
|
|
592
|
+
`Runtime config option \`${[...path, key].join(".")}\` may not be able to be serialized.`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function isPrimitiveValue(value) {
|
|
598
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
async function resolveStorageOptions(options) {
|
|
602
|
+
const fsMounts = {
|
|
603
|
+
root: resolve(options.rootDir),
|
|
604
|
+
src: resolve(options.srcDir),
|
|
605
|
+
build: resolve(options.buildDir),
|
|
606
|
+
cache: resolve(options.buildDir, "cache")
|
|
607
|
+
};
|
|
608
|
+
for (const p in fsMounts) {
|
|
609
|
+
options.devStorage[p] = options.devStorage[p] || {
|
|
610
|
+
driver: "fs",
|
|
611
|
+
readOnly: p === "root" || p === "src",
|
|
612
|
+
base: fsMounts[p]
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
if (options.dev && options.storage.data === void 0 && options.devStorage.data === void 0) {
|
|
616
|
+
options.devStorage.data = {
|
|
617
|
+
driver: "fs",
|
|
618
|
+
base: resolve(options.rootDir, ".data/kv")
|
|
619
|
+
};
|
|
620
|
+
} else if (options.node && options.storage.data === void 0) {
|
|
621
|
+
options.storage.data = {
|
|
622
|
+
driver: "fsLite",
|
|
623
|
+
base: "./.data/kv"
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async function resolveURLOptions(options) {
|
|
629
|
+
options.baseURL = withLeadingSlash(withTrailingSlash(options.baseURL));
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
async function resolveErrorOptions(options) {
|
|
633
|
+
if (!options.errorHandler) {
|
|
634
|
+
options.errorHandler = [];
|
|
635
|
+
} else if (!Array.isArray(options.errorHandler)) {
|
|
636
|
+
options.errorHandler = [options.errorHandler];
|
|
637
|
+
}
|
|
638
|
+
options.errorHandler.push(
|
|
639
|
+
join(runtimeDir, `internal/error/${options.dev ? "dev" : "prod"}`)
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const common = {
|
|
644
|
+
meta: {
|
|
645
|
+
name: "nitro-common",
|
|
646
|
+
url: import.meta.url
|
|
647
|
+
},
|
|
648
|
+
alias: {
|
|
649
|
+
"buffer/": "node:buffer",
|
|
650
|
+
"buffer/index": "node:buffer",
|
|
651
|
+
"buffer/index.js": "node:buffer",
|
|
652
|
+
"string_decoder/": "node:string_decoder",
|
|
653
|
+
"process/": "node:process"
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
const nodeless = {
|
|
657
|
+
meta: {
|
|
658
|
+
name: "nitro-nodeless",
|
|
659
|
+
url: import.meta.url
|
|
660
|
+
},
|
|
661
|
+
inject: {
|
|
662
|
+
global: "unenv/polyfill/globalthis",
|
|
663
|
+
process: "node:process",
|
|
664
|
+
Buffer: ["node:buffer", "Buffer"],
|
|
665
|
+
clearImmediate: ["node:timers", "clearImmediate"],
|
|
666
|
+
setImmediate: ["node:timers", "setImmediate"],
|
|
667
|
+
performance: "unenv/polyfill/performance",
|
|
668
|
+
PerformanceObserver: ["node:perf_hooks", "PerformanceObserver"],
|
|
669
|
+
BroadcastChannel: ["node:worker_threads", "BroadcastChannel"]
|
|
670
|
+
},
|
|
671
|
+
polyfill: [
|
|
672
|
+
"unenv/polyfill/globalthis-global",
|
|
673
|
+
"unenv/polyfill/process",
|
|
674
|
+
"unenv/polyfill/buffer",
|
|
675
|
+
"unenv/polyfill/timers"
|
|
676
|
+
]
|
|
677
|
+
};
|
|
678
|
+
async function resolveUnenv(options) {
|
|
679
|
+
options.unenv ??= [];
|
|
680
|
+
if (!Array.isArray(options.unenv)) {
|
|
681
|
+
options.unenv = [options.unenv];
|
|
682
|
+
}
|
|
683
|
+
options.unenv = options.unenv.filter(Boolean);
|
|
684
|
+
if (!options.node) {
|
|
685
|
+
options.unenv.unshift(nodeless);
|
|
686
|
+
}
|
|
687
|
+
options.unenv.unshift(common);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
async function resolveBuilder(options) {
|
|
691
|
+
if (!options.builder) {
|
|
692
|
+
options.builder = process.env.NITRO_BUILDER || "rollup";
|
|
693
|
+
}
|
|
694
|
+
if (options.builder === "rolldown") {
|
|
695
|
+
try {
|
|
696
|
+
await import('rolldown');
|
|
697
|
+
} catch {
|
|
698
|
+
throw new Error(
|
|
699
|
+
`Builder "rolldown" is not available. Make sure to install "rolldown" package.`
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
} else if (options.builder === "vite") {
|
|
703
|
+
try {
|
|
704
|
+
await import('vite');
|
|
705
|
+
} catch {
|
|
706
|
+
throw new Error(
|
|
707
|
+
`Builder "vite" is not available. Make sure to install "vite" package.`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (!["rollup", "rolldown", "vite"].includes(options.builder)) {
|
|
712
|
+
throw new Error(`Builder "${options.builder}" is not supported.`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const configResolvers = [
|
|
717
|
+
resolveCompatibilityOptions,
|
|
718
|
+
resolvePathOptions,
|
|
719
|
+
resolveImportsOptions,
|
|
720
|
+
resolveRouteRulesOptions,
|
|
721
|
+
resolveDatabaseOptions,
|
|
722
|
+
resolveExportConditionsOptions,
|
|
723
|
+
resolveRuntimeConfigOptions,
|
|
724
|
+
resolveOpenAPIOptions,
|
|
725
|
+
resolveURLOptions,
|
|
726
|
+
resolveAssetsOptions,
|
|
727
|
+
resolveStorageOptions,
|
|
728
|
+
resolveErrorOptions,
|
|
729
|
+
resolveUnenv,
|
|
730
|
+
resolveBuilder
|
|
731
|
+
];
|
|
732
|
+
async function loadOptions(configOverrides = {}, opts = {}) {
|
|
733
|
+
const options = await _loadUserConfig(configOverrides, opts);
|
|
734
|
+
for (const resolver of configResolvers) {
|
|
735
|
+
await resolver(options);
|
|
736
|
+
}
|
|
737
|
+
return options;
|
|
738
|
+
}
|
|
739
|
+
async function _loadUserConfig(configOverrides = {}, opts = {}) {
|
|
740
|
+
configOverrides = klona(configOverrides);
|
|
741
|
+
globalThis.defineNitroConfig = globalThis.defineNitroConfig || ((c) => c);
|
|
742
|
+
let compatibilityDate = configOverrides.compatibilityDate || opts.compatibilityDate || (process.env.NITRO_COMPATIBILITY_DATE || process.env.SERVER_COMPATIBILITY_DATE || process.env.COMPATIBILITY_DATE);
|
|
743
|
+
const { resolvePreset } = await import('../_presets/index.mjs');
|
|
744
|
+
let preset = configOverrides.preset || process.env.NITRO_PRESET || process.env.SERVER_PRESET;
|
|
745
|
+
const _dotenv = opts.dotenv ?? (configOverrides.dev && { fileName: [".env", ".env.local"] });
|
|
746
|
+
const loadedConfig = await (opts.watch ? watchConfig : loadConfig)({
|
|
747
|
+
name: "nitro",
|
|
748
|
+
cwd: configOverrides.rootDir,
|
|
749
|
+
dotenv: _dotenv,
|
|
750
|
+
extend: { extendKey: ["extends", "preset"] },
|
|
751
|
+
defaults: NitroDefaults,
|
|
752
|
+
jitiOptions: {
|
|
753
|
+
alias: {
|
|
754
|
+
nitropack: "nitro/config",
|
|
755
|
+
"nitro/config": "nitro/config"
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
async overrides({ rawConfigs }) {
|
|
759
|
+
const getConf = (key) => configOverrides[key] ?? rawConfigs.main?.[key] ?? rawConfigs.rc?.[key] ?? rawConfigs.packageJson?.[key];
|
|
760
|
+
if (!compatibilityDate) {
|
|
761
|
+
compatibilityDate = getConf("compatibilityDate");
|
|
762
|
+
}
|
|
763
|
+
const framework = getConf("framework");
|
|
764
|
+
const isCustomFramework = framework?.name && framework.name !== "nitro";
|
|
765
|
+
if (!preset) {
|
|
766
|
+
preset = getConf("preset");
|
|
767
|
+
}
|
|
768
|
+
if (configOverrides.dev) {
|
|
769
|
+
preset = preset && preset !== "nitro-dev" ? await resolvePreset(preset, {
|
|
770
|
+
static: getConf("static"),
|
|
771
|
+
dev: true,
|
|
772
|
+
compatibilityDate: compatibilityDate || "latest"
|
|
773
|
+
}).then((p) => p?._meta?.name || "nitro-dev").catch(() => "nitro-dev") : "nitro-dev";
|
|
774
|
+
} else if (!preset) {
|
|
775
|
+
preset = await resolvePreset("", {
|
|
776
|
+
static: getConf("static"),
|
|
777
|
+
dev: false,
|
|
778
|
+
compatibilityDate: compatibilityDate || "latest"
|
|
779
|
+
}).then((p) => p?._meta?.name);
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
...configOverrides,
|
|
783
|
+
preset,
|
|
784
|
+
typescript: {
|
|
785
|
+
generateRuntimeConfigTypes: !isCustomFramework,
|
|
786
|
+
...getConf("typescript"),
|
|
787
|
+
...configOverrides.typescript
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
},
|
|
791
|
+
async resolve(id) {
|
|
792
|
+
const preset2 = await resolvePreset(id, {
|
|
793
|
+
static: configOverrides.static,
|
|
794
|
+
compatibilityDate: compatibilityDate || "latest",
|
|
795
|
+
dev: configOverrides.dev
|
|
796
|
+
});
|
|
797
|
+
if (preset2) {
|
|
798
|
+
return {
|
|
799
|
+
config: klona(preset2)
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
...opts.c12
|
|
804
|
+
});
|
|
805
|
+
const options = klona(loadedConfig.config);
|
|
806
|
+
options._config = configOverrides;
|
|
807
|
+
options._c12 = loadedConfig;
|
|
808
|
+
const _presetName = (loadedConfig.layers || []).find((l) => l.config?._meta?.name)?.config?._meta?.name || preset;
|
|
809
|
+
options.preset = _presetName;
|
|
810
|
+
options.compatibilityDate = resolveCompatibilityDates(
|
|
811
|
+
compatibilityDate,
|
|
812
|
+
options.compatibilityDate
|
|
813
|
+
);
|
|
814
|
+
if (options.dev && options.preset !== "nitro-dev") {
|
|
815
|
+
consola.info(`Using \`${options.preset}\` emulation in development mode.`);
|
|
816
|
+
}
|
|
817
|
+
return options;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
async function updateNitroConfig(nitro, config) {
|
|
821
|
+
nitro.options.routeRules = normalizeRouteRules(
|
|
822
|
+
config.routeRules ? config : nitro.options
|
|
823
|
+
);
|
|
824
|
+
nitro.options.runtimeConfig = normalizeRuntimeConfig(
|
|
825
|
+
config.runtimeConfig ? config : nitro.options
|
|
826
|
+
);
|
|
827
|
+
await nitro.hooks.callHook("rollup:reload");
|
|
828
|
+
consola.success("Nitro config hot reloaded!");
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
async function installModules(nitro) {
|
|
832
|
+
const _modules = [...nitro.options.modules || []];
|
|
833
|
+
const modules = await Promise.all(
|
|
834
|
+
_modules.map((mod) => _resolveNitroModule(mod, nitro.options))
|
|
835
|
+
);
|
|
836
|
+
const _installedURLs = /* @__PURE__ */ new Set();
|
|
837
|
+
for (const mod of modules) {
|
|
838
|
+
if (mod._url) {
|
|
839
|
+
if (_installedURLs.has(mod._url)) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
_installedURLs.add(mod._url);
|
|
843
|
+
}
|
|
844
|
+
await mod.setup(nitro);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
async function _resolveNitroModule(mod, nitroOptions) {
|
|
848
|
+
let _url;
|
|
849
|
+
if (typeof mod === "string") {
|
|
850
|
+
globalThis.defineNitroModule = // @ts-ignore
|
|
851
|
+
globalThis.defineNitroModule || ((mod2) => mod2);
|
|
852
|
+
const jiti = createJiti(nitroOptions.rootDir, {
|
|
853
|
+
alias: nitroOptions.alias
|
|
854
|
+
});
|
|
855
|
+
const _modPath = jiti.esmResolve(mod);
|
|
856
|
+
_url = _modPath;
|
|
857
|
+
mod = await jiti.import(_modPath, { default: true });
|
|
858
|
+
}
|
|
859
|
+
if (typeof mod === "function") {
|
|
860
|
+
mod = { setup: mod };
|
|
861
|
+
}
|
|
862
|
+
if (!mod.setup) {
|
|
863
|
+
mod.setup = () => {
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
_url,
|
|
868
|
+
...mod
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
async function runTask(taskEvent, opts) {
|
|
873
|
+
const ctx = await _getTasksContext(opts);
|
|
874
|
+
const result = await ctx.devFetch(`/_nitro/tasks/${taskEvent.name}`, {
|
|
875
|
+
method: "POST",
|
|
876
|
+
body: taskEvent
|
|
877
|
+
});
|
|
878
|
+
return result;
|
|
879
|
+
}
|
|
880
|
+
async function listTasks(opts) {
|
|
881
|
+
const ctx = await _getTasksContext(opts);
|
|
882
|
+
const res = await ctx.devFetch("/_nitro/tasks");
|
|
883
|
+
return res.tasks;
|
|
884
|
+
}
|
|
885
|
+
function addNitroTasksVirtualFile(nitro) {
|
|
886
|
+
nitro.options.virtual["#nitro-internal-virtual/tasks"] = () => {
|
|
887
|
+
const _scheduledTasks = Object.entries(nitro.options.scheduledTasks || {}).map(([cron, _tasks]) => {
|
|
888
|
+
const tasks = (Array.isArray(_tasks) ? _tasks : [_tasks]).filter(
|
|
889
|
+
(name) => {
|
|
890
|
+
if (!nitro.options.tasks[name]) {
|
|
891
|
+
nitro.logger.warn(`Scheduled task \`${name}\` is not defined!`);
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
return true;
|
|
895
|
+
}
|
|
896
|
+
);
|
|
897
|
+
return { cron, tasks };
|
|
898
|
+
}).filter((e) => e.tasks.length > 0);
|
|
899
|
+
const scheduledTasks = _scheduledTasks.length > 0 ? _scheduledTasks : false;
|
|
900
|
+
return (
|
|
901
|
+
/* js */
|
|
902
|
+
`
|
|
903
|
+
export const scheduledTasks = ${JSON.stringify(scheduledTasks)};
|
|
904
|
+
|
|
905
|
+
export const tasks = {
|
|
906
|
+
${Object.entries(nitro.options.tasks).map(
|
|
907
|
+
([name, task]) => `"${name}": {
|
|
908
|
+
meta: {
|
|
909
|
+
description: ${JSON.stringify(task.description)},
|
|
910
|
+
},
|
|
911
|
+
resolve: ${task.handler ? `() => import("${normalize(
|
|
912
|
+
task.handler
|
|
913
|
+
)}").then(r => r.default || r)` : "undefined"},
|
|
914
|
+
}`
|
|
915
|
+
).join(",\n")}
|
|
916
|
+
};`
|
|
917
|
+
);
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
const _devHint = `(is dev server running?)`;
|
|
921
|
+
async function _getTasksContext(opts) {
|
|
922
|
+
const cwd = resolve(process.cwd(), opts?.cwd || ".");
|
|
923
|
+
const outDir = resolve(cwd, opts?.buildDir || ".nitro");
|
|
924
|
+
const buildInfoPath = resolve(outDir, "nitro.json");
|
|
925
|
+
if (!existsSync(buildInfoPath)) {
|
|
926
|
+
throw new Error(`Missing info file: \`${buildInfoPath}\` ${_devHint}`);
|
|
927
|
+
}
|
|
928
|
+
const buildInfo = JSON.parse(
|
|
929
|
+
await readFile(buildInfoPath, "utf8")
|
|
930
|
+
);
|
|
931
|
+
if (!buildInfo.dev?.pid || !buildInfo.dev?.workerAddress) {
|
|
932
|
+
throw new Error(
|
|
933
|
+
`Missing dev server info in: \`${buildInfoPath}\` ${_devHint}`
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
if (!_pidIsRunning(buildInfo.dev.pid)) {
|
|
937
|
+
throw new Error(`Dev server is not running (pid: ${buildInfo.dev.pid})`);
|
|
938
|
+
}
|
|
939
|
+
const devFetch = ofetch.create({
|
|
940
|
+
baseURL: `http://${buildInfo.dev.workerAddress.host || "localhost"}:${buildInfo.dev.workerAddress.port || "3000"}`,
|
|
941
|
+
// @ts-expect-error
|
|
942
|
+
socketPath: buildInfo.dev.workerAddress.socketPath
|
|
943
|
+
});
|
|
944
|
+
return {
|
|
945
|
+
buildInfo,
|
|
946
|
+
devFetch
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
function _pidIsRunning(pid) {
|
|
950
|
+
try {
|
|
951
|
+
process.kill(pid, 0);
|
|
952
|
+
return true;
|
|
953
|
+
} catch {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const isGlobalMiddleware = (h) => !h.method && (!h.route || h.route === "/**");
|
|
959
|
+
function initNitroRouting(nitro) {
|
|
960
|
+
const envConditions = new Set(
|
|
961
|
+
[
|
|
962
|
+
nitro.options.dev ? "dev" : "prod",
|
|
963
|
+
nitro.options.preset,
|
|
964
|
+
nitro.options.preset === "nitro-prerender" ? "prerender" : void 0
|
|
965
|
+
].filter(Boolean)
|
|
966
|
+
);
|
|
967
|
+
const matchesEnv = (h) => {
|
|
968
|
+
const hEnv = Array.isArray(h.env) ? h.env : [h.env];
|
|
969
|
+
const envs = hEnv.filter(Boolean);
|
|
970
|
+
return envs.length === 0 || envs.some((env) => envConditions.has(env));
|
|
971
|
+
};
|
|
972
|
+
const routes = new Router();
|
|
973
|
+
const routeRules = new Router(
|
|
974
|
+
true
|
|
975
|
+
/* matchAll */
|
|
976
|
+
);
|
|
977
|
+
const globalMiddleware = [];
|
|
978
|
+
const routedMiddleware = new Router(
|
|
979
|
+
true
|
|
980
|
+
/* matchAll */
|
|
981
|
+
);
|
|
982
|
+
const warns = /* @__PURE__ */ new Set();
|
|
983
|
+
const sync = () => {
|
|
984
|
+
routeRules._update(
|
|
985
|
+
Object.entries(nitro.options.routeRules).map(([route, data]) => ({
|
|
986
|
+
route,
|
|
987
|
+
method: "",
|
|
988
|
+
data: {
|
|
989
|
+
...data,
|
|
990
|
+
_route: route
|
|
991
|
+
}
|
|
992
|
+
}))
|
|
993
|
+
);
|
|
994
|
+
const _routes = [
|
|
995
|
+
...nitro.scannedHandlers,
|
|
996
|
+
...nitro.options.handlers
|
|
997
|
+
].filter((h) => h && !h.middleware && matchesEnv(h));
|
|
998
|
+
if (nitro.options.renderer?.entry) {
|
|
999
|
+
const existingWildcard = _routes.findIndex(
|
|
1000
|
+
(h) => /^\/\*\*(:.+)?$/.test(h.route) && (!h.method || h.method === "GET")
|
|
1001
|
+
);
|
|
1002
|
+
if (existingWildcard !== -1) {
|
|
1003
|
+
const h = _routes[existingWildcard];
|
|
1004
|
+
const warn = `The renderer will override \`${relative(".", h.handler)}\` (route: \`${h.route}\`). Use a more specific route or different HTTP method.`;
|
|
1005
|
+
if (!warns.has(warn)) {
|
|
1006
|
+
warns.add(warn);
|
|
1007
|
+
nitro.logger.warn(warn);
|
|
1008
|
+
}
|
|
1009
|
+
_routes.splice(existingWildcard, 1);
|
|
1010
|
+
}
|
|
1011
|
+
_routes.push({
|
|
1012
|
+
route: "/**",
|
|
1013
|
+
lazy: true,
|
|
1014
|
+
handler: nitro.options.renderer?.entry
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
routes._update(
|
|
1018
|
+
_routes.map((h) => ({
|
|
1019
|
+
...h,
|
|
1020
|
+
method: h.method || "",
|
|
1021
|
+
data: handlerWithImportHash(h)
|
|
1022
|
+
}))
|
|
1023
|
+
);
|
|
1024
|
+
const _middleware = [
|
|
1025
|
+
...nitro.scannedHandlers,
|
|
1026
|
+
...nitro.options.handlers
|
|
1027
|
+
].filter((h) => h && h.middleware && matchesEnv(h));
|
|
1028
|
+
if (nitro.options.serveStatic) {
|
|
1029
|
+
_middleware.unshift({
|
|
1030
|
+
route: "/**",
|
|
1031
|
+
middleware: true,
|
|
1032
|
+
handler: join(runtimeDir, "internal/static")
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
globalMiddleware.splice(
|
|
1036
|
+
0,
|
|
1037
|
+
globalMiddleware.length,
|
|
1038
|
+
..._middleware.filter((h) => isGlobalMiddleware(h)).map((m) => handlerWithImportHash(m))
|
|
1039
|
+
);
|
|
1040
|
+
routedMiddleware._update(
|
|
1041
|
+
_middleware.filter((h) => !isGlobalMiddleware(h)).map((h) => ({
|
|
1042
|
+
...h,
|
|
1043
|
+
method: h.method || "",
|
|
1044
|
+
data: handlerWithImportHash(h)
|
|
1045
|
+
}))
|
|
1046
|
+
);
|
|
1047
|
+
};
|
|
1048
|
+
nitro.routing = Object.freeze({
|
|
1049
|
+
sync,
|
|
1050
|
+
routes,
|
|
1051
|
+
routeRules,
|
|
1052
|
+
globalMiddleware,
|
|
1053
|
+
routedMiddleware
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
function handlerWithImportHash(h) {
|
|
1057
|
+
const id = (h.lazy ? "_lazy_" : "_") + hash(h.handler).replace(/-/g, "").slice(0, 6);
|
|
1058
|
+
return { ...h, _importHash: id };
|
|
1059
|
+
}
|
|
1060
|
+
class Router {
|
|
1061
|
+
#routes;
|
|
1062
|
+
#router;
|
|
1063
|
+
#compiled;
|
|
1064
|
+
constructor(matchAll) {
|
|
1065
|
+
this._update([]);
|
|
1066
|
+
}
|
|
1067
|
+
get routes() {
|
|
1068
|
+
return this.#routes;
|
|
1069
|
+
}
|
|
1070
|
+
_update(routes) {
|
|
1071
|
+
this.#routes = routes;
|
|
1072
|
+
this.#router = createRouter();
|
|
1073
|
+
this.#compiled = void 0;
|
|
1074
|
+
for (const route of routes) {
|
|
1075
|
+
addRoute(this.#router, route.method, route.route, route.data);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
hasRoutes() {
|
|
1079
|
+
return this.#routes.length > 0;
|
|
1080
|
+
}
|
|
1081
|
+
compileToString(opts) {
|
|
1082
|
+
return this.#compiled || (this.#compiled = compileRouterToString(this.#router, void 0, opts));
|
|
1083
|
+
}
|
|
1084
|
+
match(method, path) {
|
|
1085
|
+
return findRoute(this.#router, method, path)?.data;
|
|
1086
|
+
}
|
|
1087
|
+
matchAll(method, path) {
|
|
1088
|
+
return findAllRoutes(this.#router, method, path).map(
|
|
1089
|
+
(route) => route.data
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
async function createNitro(config = {}, opts = {}) {
|
|
1095
|
+
const options = await loadOptions(config, opts);
|
|
1096
|
+
const nitro = {
|
|
1097
|
+
options,
|
|
1098
|
+
hooks: new Hookable(),
|
|
1099
|
+
vfs: {},
|
|
1100
|
+
routing: {},
|
|
1101
|
+
logger: consola$1.withTag("nitro"),
|
|
1102
|
+
scannedHandlers: [],
|
|
1103
|
+
close: () => nitro.hooks.callHook("close"),
|
|
1104
|
+
storage: void 0,
|
|
1105
|
+
async updateConfig(config2) {
|
|
1106
|
+
updateNitroConfig(nitro, config2);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
initNitroRouting(nitro);
|
|
1110
|
+
await scanAndSyncOptions(nitro);
|
|
1111
|
+
nitro.storage = await createStorage(nitro);
|
|
1112
|
+
nitro.hooks.hook("close", async () => {
|
|
1113
|
+
await nitro.storage.dispose();
|
|
1114
|
+
});
|
|
1115
|
+
if (nitro.options.debug) {
|
|
1116
|
+
createDebugger(nitro.hooks, { tag: "nitro" });
|
|
1117
|
+
}
|
|
1118
|
+
if (nitro.options.logLevel !== void 0) {
|
|
1119
|
+
nitro.logger.level = nitro.options.logLevel;
|
|
1120
|
+
}
|
|
1121
|
+
nitro.hooks.addHooks(nitro.options.hooks);
|
|
1122
|
+
addNitroTasksVirtualFile(nitro);
|
|
1123
|
+
await installModules(nitro);
|
|
1124
|
+
if (nitro.options.imports) {
|
|
1125
|
+
nitro.unimport = createUnimport(nitro.options.imports);
|
|
1126
|
+
await nitro.unimport.init();
|
|
1127
|
+
nitro.options.virtual["#imports"] = () => nitro.unimport?.toExports() || "";
|
|
1128
|
+
nitro.options.virtual["#nitro"] = 'export * from "#imports"';
|
|
1129
|
+
}
|
|
1130
|
+
await scanHandlers(nitro);
|
|
1131
|
+
nitro.routing.sync();
|
|
1132
|
+
return nitro;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const allowedExtensions = /* @__PURE__ */ new Set(["", ".json"]);
|
|
1136
|
+
const linkParents$1 = /* @__PURE__ */ new Map();
|
|
1137
|
+
const HTML_ENTITIES = {
|
|
1138
|
+
"<": "<",
|
|
1139
|
+
">": ">",
|
|
1140
|
+
"&": "&",
|
|
1141
|
+
"'": "'",
|
|
1142
|
+
""": '"'
|
|
1143
|
+
};
|
|
1144
|
+
function escapeHtml(text) {
|
|
1145
|
+
return text.replace(
|
|
1146
|
+
/&(lt|gt|amp|apos|quot);/g,
|
|
1147
|
+
(ch) => HTML_ENTITIES[ch] || ch
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
async function extractLinks(html, from, res, crawlLinks) {
|
|
1151
|
+
const links = [];
|
|
1152
|
+
const _links = [];
|
|
1153
|
+
if (crawlLinks) {
|
|
1154
|
+
await z(P(html), (node) => {
|
|
1155
|
+
if (!node.attributes?.href) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
const link = escapeHtml(node.attributes.href);
|
|
1159
|
+
if (!decodeURIComponent(link).startsWith("#") && allowedExtensions.has(getExtension(link))) {
|
|
1160
|
+
_links.push(link);
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
const header = res.headers.get("x-nitro-prerender") || "";
|
|
1165
|
+
_links.push(...header.split(",").map((i) => decodeURIComponent(i.trim())));
|
|
1166
|
+
for (const link of _links.filter(Boolean)) {
|
|
1167
|
+
const _link = parseURL(link);
|
|
1168
|
+
if (_link.protocol || _link.host) {
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
if (!_link.pathname.startsWith("/")) {
|
|
1172
|
+
const fromURL = new URL(from, "http://localhost");
|
|
1173
|
+
_link.pathname = new URL(_link.pathname, fromURL).pathname;
|
|
1174
|
+
}
|
|
1175
|
+
links.push(_link.pathname + _link.search);
|
|
1176
|
+
}
|
|
1177
|
+
for (const link of links) {
|
|
1178
|
+
const _parents = linkParents$1.get(link);
|
|
1179
|
+
if (_parents) {
|
|
1180
|
+
_parents.add(from);
|
|
1181
|
+
} else {
|
|
1182
|
+
linkParents$1.set(link, /* @__PURE__ */ new Set([from]));
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return links;
|
|
1186
|
+
}
|
|
1187
|
+
const EXT_REGEX = /\.[\da-z]+$/;
|
|
1188
|
+
function getExtension(link) {
|
|
1189
|
+
const pathname = parseURL(link).pathname;
|
|
1190
|
+
return (pathname.match(EXT_REGEX) || [])[0] || "";
|
|
1191
|
+
}
|
|
1192
|
+
function formatPrerenderRoute(route) {
|
|
1193
|
+
let str = ` \u251C\u2500 ${route.route} (${route.generateTimeMS}ms)`;
|
|
1194
|
+
if (route.error) {
|
|
1195
|
+
const parents = linkParents$1.get(route.route);
|
|
1196
|
+
const errorColor = colors[route.error.status === 404 ? "yellow" : "red"];
|
|
1197
|
+
const errorLead = parents?.size ? "\u251C\u2500\u2500" : "\u2514\u2500\u2500";
|
|
1198
|
+
str += `
|
|
1199
|
+
\u2502 ${errorLead} ${errorColor(route.error.message)}`;
|
|
1200
|
+
if (parents?.size) {
|
|
1201
|
+
str += `
|
|
1202
|
+
${[...parents.values()].map((link) => ` \u2502 \u2514\u2500\u2500 Linked from ${link}`).join("\n")}`;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (route.skip) {
|
|
1206
|
+
str += colors.gray(" (skipped)");
|
|
1207
|
+
}
|
|
1208
|
+
return colors.gray(str);
|
|
1209
|
+
}
|
|
1210
|
+
function matchesIgnorePattern(path, pattern) {
|
|
1211
|
+
if (typeof pattern === "string") {
|
|
1212
|
+
return path.startsWith(pattern);
|
|
1213
|
+
}
|
|
1214
|
+
if (typeof pattern === "function") {
|
|
1215
|
+
return pattern(path) === true;
|
|
1216
|
+
}
|
|
1217
|
+
if (pattern instanceof RegExp) {
|
|
1218
|
+
return pattern.test(path);
|
|
1219
|
+
}
|
|
1220
|
+
return false;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
1224
|
+
const linkParents = /* @__PURE__ */ new Map();
|
|
1225
|
+
async function prerender(nitro) {
|
|
1226
|
+
if (nitro.options.noPublicDir) {
|
|
1227
|
+
nitro.logger.warn(
|
|
1228
|
+
"Skipping prerender since `noPublicDir` option is enabled."
|
|
1229
|
+
);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
if (nitro.options.builder === "vite") {
|
|
1233
|
+
nitro.logger.warn(
|
|
1234
|
+
"Skipping prerender since not supported with vite builder yet..."
|
|
1235
|
+
);
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
const routes = new Set(nitro.options.prerender.routes);
|
|
1239
|
+
const prerenderRulePaths = Object.entries(nitro.options.routeRules).filter(([path2, options]) => options.prerender && !path2.includes("*")).map((e) => e[0]);
|
|
1240
|
+
for (const route of prerenderRulePaths) {
|
|
1241
|
+
routes.add(route);
|
|
1242
|
+
}
|
|
1243
|
+
await nitro.hooks.callHook("prerender:routes", routes);
|
|
1244
|
+
if (routes.size === 0) {
|
|
1245
|
+
if (nitro.options.prerender.crawlLinks) {
|
|
1246
|
+
routes.add("/");
|
|
1247
|
+
} else {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
nitro.logger.info("Initializing prerenderer");
|
|
1252
|
+
nitro._prerenderedRoutes = [];
|
|
1253
|
+
nitro._prerenderMeta = nitro._prerenderMeta || {};
|
|
1254
|
+
const prerendererConfig = {
|
|
1255
|
+
...nitro.options._config,
|
|
1256
|
+
static: false,
|
|
1257
|
+
rootDir: nitro.options.rootDir,
|
|
1258
|
+
logLevel: 0,
|
|
1259
|
+
preset: "nitro-prerender"
|
|
1260
|
+
};
|
|
1261
|
+
await nitro.hooks.callHook("prerender:config", prerendererConfig);
|
|
1262
|
+
const nitroRenderer = await createNitro(prerendererConfig);
|
|
1263
|
+
const prerenderStartTime = Date.now();
|
|
1264
|
+
await nitro.hooks.callHook("prerender:init", nitroRenderer);
|
|
1265
|
+
let path = relative(nitro.options.output.dir, nitro.options.output.publicDir);
|
|
1266
|
+
if (!path.startsWith(".")) {
|
|
1267
|
+
path = `./${path}`;
|
|
1268
|
+
}
|
|
1269
|
+
nitroRenderer.options.commands.preview = `npx serve ${path}`;
|
|
1270
|
+
nitroRenderer.options.output.dir = nitro.options.output.dir;
|
|
1271
|
+
await build$1(nitroRenderer);
|
|
1272
|
+
const serverFilename = typeof nitroRenderer.options.rollupConfig?.output?.entryFileNames === "string" ? nitroRenderer.options.rollupConfig.output.entryFileNames : "index.mjs";
|
|
1273
|
+
const serverEntrypoint = resolve(
|
|
1274
|
+
nitroRenderer.options.output.serverDir,
|
|
1275
|
+
serverFilename
|
|
1276
|
+
);
|
|
1277
|
+
const { closePrerenderer, appFetch } = await import(pathToFileURL(serverEntrypoint).href);
|
|
1278
|
+
const routeRules = createRouter();
|
|
1279
|
+
for (const [route, rules] of Object.entries(nitro.options.routeRules)) {
|
|
1280
|
+
addRoute(routeRules, void 0, route, rules);
|
|
1281
|
+
}
|
|
1282
|
+
const _getRouteRules = (path2) => defu(
|
|
1283
|
+
{},
|
|
1284
|
+
...findAllRoutes(routeRules, void 0, path2).map((r) => r.data).reverse()
|
|
1285
|
+
);
|
|
1286
|
+
const generatedRoutes = /* @__PURE__ */ new Set();
|
|
1287
|
+
const failedRoutes = /* @__PURE__ */ new Set();
|
|
1288
|
+
const skippedRoutes = /* @__PURE__ */ new Set();
|
|
1289
|
+
const displayedLengthWarns = /* @__PURE__ */ new Set();
|
|
1290
|
+
const publicAssetBases = nitro.options.publicAssets.filter(
|
|
1291
|
+
(a) => !!a.baseURL && a.baseURL !== "/" && !a.fallthrough
|
|
1292
|
+
).map((a) => withTrailingSlash(a.baseURL));
|
|
1293
|
+
const scannedPublicAssets = nitro.options.prerender.ignoreUnprefixedPublicAssets ? new Set(await scanUnprefixedPublicAssets(nitro)) : /* @__PURE__ */ new Set();
|
|
1294
|
+
const canPrerender = (route = "/") => {
|
|
1295
|
+
if (generatedRoutes.has(route) || skippedRoutes.has(route)) {
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
for (const pattern of nitro.options.prerender.ignore) {
|
|
1299
|
+
if (matchesIgnorePattern(route, pattern)) {
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
if (publicAssetBases.some((base) => route.startsWith(base))) {
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
if (scannedPublicAssets.has(route)) {
|
|
1307
|
+
return false;
|
|
1308
|
+
}
|
|
1309
|
+
if (_getRouteRules(route).prerender === false) {
|
|
1310
|
+
return false;
|
|
1311
|
+
}
|
|
1312
|
+
return true;
|
|
1313
|
+
};
|
|
1314
|
+
const canWriteToDisk = (route) => {
|
|
1315
|
+
if (route.route.includes("?")) {
|
|
1316
|
+
return false;
|
|
1317
|
+
}
|
|
1318
|
+
const FS_MAX_SEGMENT = 255;
|
|
1319
|
+
const FS_MAX_PATH = 1024;
|
|
1320
|
+
const FS_MAX_PATH_PUBLIC_HTML = FS_MAX_PATH - (nitro.options.output.publicDir.length + 10);
|
|
1321
|
+
if ((route.route.length >= FS_MAX_PATH_PUBLIC_HTML || route.route.split("/").some((s) => s.length > FS_MAX_SEGMENT)) && !displayedLengthWarns.has(route)) {
|
|
1322
|
+
displayedLengthWarns.add(route);
|
|
1323
|
+
const _route = route.route.slice(0, 60) + "...";
|
|
1324
|
+
if (route.route.length >= FS_MAX_PATH_PUBLIC_HTML) {
|
|
1325
|
+
nitro.logger.warn(
|
|
1326
|
+
`Prerendering long route "${_route}" (${route.route.length}) can cause filesystem issues since it exceeds ${FS_MAX_PATH_PUBLIC_HTML}-character limit when writing to \`${nitro.options.output.publicDir}\`.`
|
|
1327
|
+
);
|
|
1328
|
+
} else {
|
|
1329
|
+
nitro.logger.warn(
|
|
1330
|
+
`Skipping prerender of the route "${_route}" since it exceeds the ${FS_MAX_SEGMENT}-character limit in one of the path segments and can cause filesystem issues.`
|
|
1331
|
+
);
|
|
1332
|
+
return false;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return true;
|
|
1336
|
+
};
|
|
1337
|
+
const generateRoute = async (route) => {
|
|
1338
|
+
const start = Date.now();
|
|
1339
|
+
route = decodeURI(route);
|
|
1340
|
+
if (!canPrerender(route)) {
|
|
1341
|
+
skippedRoutes.add(route);
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
generatedRoutes.add(route);
|
|
1345
|
+
const _route = { route };
|
|
1346
|
+
const encodedRoute = encodeURI(route);
|
|
1347
|
+
const res = await appFetch(withBase(encodedRoute, nitro.options.baseURL), {
|
|
1348
|
+
headers: [["x-nitro-prerender", encodedRoute]]
|
|
1349
|
+
// TODO
|
|
1350
|
+
// retry: nitro.options.prerender.retry,
|
|
1351
|
+
// retryDelay: nitro.options.prerender.retryDelay,
|
|
1352
|
+
});
|
|
1353
|
+
let dataBuff = Buffer.from(await res.arrayBuffer());
|
|
1354
|
+
Object.defineProperty(_route, "contents", {
|
|
1355
|
+
get: () => {
|
|
1356
|
+
return dataBuff ? dataBuff.toString("utf8") : void 0;
|
|
1357
|
+
},
|
|
1358
|
+
set(value) {
|
|
1359
|
+
if (dataBuff) {
|
|
1360
|
+
dataBuff = Buffer.from(value);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
Object.defineProperty(_route, "data", {
|
|
1365
|
+
get: () => {
|
|
1366
|
+
return dataBuff ? dataBuff.buffer : void 0;
|
|
1367
|
+
},
|
|
1368
|
+
set(value) {
|
|
1369
|
+
if (dataBuff) {
|
|
1370
|
+
dataBuff = Buffer.from(value);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
const redirectCodes = [301, 302, 303, 304, 307, 308];
|
|
1375
|
+
if (![200, ...redirectCodes].includes(res.status)) {
|
|
1376
|
+
_route.error = new Error(`[${res.status}] ${res.statusText}`);
|
|
1377
|
+
_route.error.status = res.status;
|
|
1378
|
+
_route.error.statusText = res.statusText;
|
|
1379
|
+
}
|
|
1380
|
+
_route.generateTimeMS = Date.now() - start;
|
|
1381
|
+
const contentType = res.headers.get("content-type") || "";
|
|
1382
|
+
const isImplicitHTML = !route.endsWith(".html") && contentType.includes("html") && !JsonSigRx.test(dataBuff.subarray(0, 32).toString("utf8"));
|
|
1383
|
+
const routeWithIndex = route.endsWith("/") ? route + "index" : route;
|
|
1384
|
+
const htmlPath = route.endsWith("/") || nitro.options.prerender.autoSubfolderIndex ? joinURL(route, "index.html") : route + ".html";
|
|
1385
|
+
_route.fileName = withoutBase(
|
|
1386
|
+
isImplicitHTML ? htmlPath : routeWithIndex,
|
|
1387
|
+
nitro.options.baseURL
|
|
1388
|
+
);
|
|
1389
|
+
const inferredContentType = mime.getType(_route.fileName) || "text/plain";
|
|
1390
|
+
_route.contentType = contentType || inferredContentType;
|
|
1391
|
+
await nitro.hooks.callHook("prerender:generate", _route, nitro);
|
|
1392
|
+
if (_route.contentType !== inferredContentType) {
|
|
1393
|
+
nitro._prerenderMeta[_route.fileName] ||= {};
|
|
1394
|
+
nitro._prerenderMeta[_route.fileName].contentType = _route.contentType;
|
|
1395
|
+
}
|
|
1396
|
+
if (_route.error) {
|
|
1397
|
+
failedRoutes.add(_route);
|
|
1398
|
+
}
|
|
1399
|
+
if (_route.skip || _route.error) {
|
|
1400
|
+
await nitro.hooks.callHook("prerender:route", _route);
|
|
1401
|
+
nitro.logger.log(formatPrerenderRoute(_route));
|
|
1402
|
+
dataBuff = void 0;
|
|
1403
|
+
return _route;
|
|
1404
|
+
}
|
|
1405
|
+
if (canWriteToDisk(_route)) {
|
|
1406
|
+
const filePath = join(nitro.options.output.publicDir, _route.fileName);
|
|
1407
|
+
await writeFile(filePath, dataBuff);
|
|
1408
|
+
nitro._prerenderedRoutes.push(_route);
|
|
1409
|
+
} else {
|
|
1410
|
+
_route.skip = true;
|
|
1411
|
+
}
|
|
1412
|
+
if (!_route.error && (isImplicitHTML || route.endsWith(".html"))) {
|
|
1413
|
+
const extractedLinks = await extractLinks(
|
|
1414
|
+
dataBuff.toString("utf8"),
|
|
1415
|
+
route,
|
|
1416
|
+
res,
|
|
1417
|
+
nitro.options.prerender.crawlLinks
|
|
1418
|
+
);
|
|
1419
|
+
for (const _link of extractedLinks) {
|
|
1420
|
+
if (canPrerender(_link)) {
|
|
1421
|
+
routes.add(_link);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
await nitro.hooks.callHook("prerender:route", _route);
|
|
1426
|
+
nitro.logger.log(formatPrerenderRoute(_route));
|
|
1427
|
+
dataBuff = void 0;
|
|
1428
|
+
return _route;
|
|
1429
|
+
};
|
|
1430
|
+
nitro.logger.info(
|
|
1431
|
+
nitro.options.prerender.crawlLinks ? `Prerendering ${routes.size} initial routes with crawler` : `Prerendering ${routes.size} routes`
|
|
1432
|
+
);
|
|
1433
|
+
await runParallel(routes, generateRoute, {
|
|
1434
|
+
concurrency: nitro.options.prerender.concurrency,
|
|
1435
|
+
interval: nitro.options.prerender.interval
|
|
1436
|
+
});
|
|
1437
|
+
await closePrerenderer();
|
|
1438
|
+
await nitro.hooks.callHook("prerender:done", {
|
|
1439
|
+
prerenderedRoutes: nitro._prerenderedRoutes,
|
|
1440
|
+
failedRoutes: [...failedRoutes]
|
|
1441
|
+
});
|
|
1442
|
+
if (nitro.options.prerender.failOnError && failedRoutes.size > 0) {
|
|
1443
|
+
nitro.logger.log("\nErrors prerendering:");
|
|
1444
|
+
for (const route of failedRoutes) {
|
|
1445
|
+
const parents = linkParents.get(route.route);
|
|
1446
|
+
parents?.size ? `
|
|
1447
|
+
${[...parents.values()].map((link) => colors.gray(` \u2502 \u2514\u2500\u2500 Linked from ${link}`)).join("\n")}` : "";
|
|
1448
|
+
nitro.logger.log(formatPrerenderRoute(route));
|
|
1449
|
+
}
|
|
1450
|
+
nitro.logger.log("");
|
|
1451
|
+
throw new Error("Exiting due to prerender errors.");
|
|
1452
|
+
}
|
|
1453
|
+
const prerenderTimeInMs = Date.now() - prerenderStartTime;
|
|
1454
|
+
nitro.logger.info(
|
|
1455
|
+
`Prerendered ${nitro._prerenderedRoutes.length} routes in ${prerenderTimeInMs / 1e3} seconds`
|
|
1456
|
+
);
|
|
1457
|
+
if (nitro.options.compressPublicAssets) {
|
|
1458
|
+
await compressPublicAssets(nitro);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
function createHTTPProxy(defaults = {}) {
|
|
1463
|
+
const proxy = createProxyServer(defaults);
|
|
1464
|
+
proxy.on("proxyReq", (proxyReq, req) => {
|
|
1465
|
+
if (!proxyReq.hasHeader("x-forwarded-for")) {
|
|
1466
|
+
const address = req.socket.remoteAddress;
|
|
1467
|
+
if (address) {
|
|
1468
|
+
proxyReq.appendHeader("x-forwarded-for", address);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (!proxyReq.hasHeader("x-forwarded-port")) {
|
|
1472
|
+
const localPort = req?.socket?.localPort;
|
|
1473
|
+
if (localPort) {
|
|
1474
|
+
proxyReq.setHeader("x-forwarded-port", req.socket.localPort);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
if (!proxyReq.hasHeader("x-forwarded-Proto")) {
|
|
1478
|
+
const encrypted = req?.connection?.encrypted;
|
|
1479
|
+
proxyReq.setHeader("x-forwarded-proto", encrypted ? "https" : "http");
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
return {
|
|
1483
|
+
proxy,
|
|
1484
|
+
async handleEvent(event, opts) {
|
|
1485
|
+
try {
|
|
1486
|
+
return await fromNodeHandler(
|
|
1487
|
+
(req, res) => proxy.web(req, res, opts)
|
|
1488
|
+
)(event);
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
event.res.headers.set("refresh", "3");
|
|
1491
|
+
throw new HTTPError({
|
|
1492
|
+
status: 503,
|
|
1493
|
+
message: "Dev server is unavailable.",
|
|
1494
|
+
cause: error
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
function fetchAddress(addr, input, inputInit) {
|
|
1501
|
+
let url;
|
|
1502
|
+
let init;
|
|
1503
|
+
if (input instanceof Request) {
|
|
1504
|
+
url = new URL(input.url);
|
|
1505
|
+
init = {
|
|
1506
|
+
method: input.method,
|
|
1507
|
+
headers: input.headers,
|
|
1508
|
+
body: input.body,
|
|
1509
|
+
...inputInit
|
|
1510
|
+
};
|
|
1511
|
+
} else {
|
|
1512
|
+
url = new URL(input);
|
|
1513
|
+
init = inputInit;
|
|
1514
|
+
}
|
|
1515
|
+
init = {
|
|
1516
|
+
duplex: "half",
|
|
1517
|
+
redirect: "manual",
|
|
1518
|
+
...init
|
|
1519
|
+
};
|
|
1520
|
+
if (addr.socketPath) {
|
|
1521
|
+
url.protocol = "http:";
|
|
1522
|
+
return fetch(url, {
|
|
1523
|
+
...init,
|
|
1524
|
+
...fetchSocketOptions(addr.socketPath)
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
const origin = `http://${addr.host}${addr.port ? `:${addr.port}` : ""}`;
|
|
1528
|
+
const outURL = new URL(url.pathname + url.search, origin);
|
|
1529
|
+
return fetch(outURL, init);
|
|
1530
|
+
}
|
|
1531
|
+
function fetchSocketOptions(socketPath) {
|
|
1532
|
+
if ("Bun" in globalThis) {
|
|
1533
|
+
return { unix: socketPath };
|
|
1534
|
+
}
|
|
1535
|
+
if ("Deno" in globalThis) {
|
|
1536
|
+
return {
|
|
1537
|
+
// @ts-ignore
|
|
1538
|
+
client: Deno.createHttpClient({
|
|
1539
|
+
// @ts-ignore Missing types?
|
|
1540
|
+
transport: "unix",
|
|
1541
|
+
path: socketPath
|
|
1542
|
+
})
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
return {
|
|
1546
|
+
dispatcher: new Agent({ connect: { socketPath } })
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
class NodeDevWorker {
|
|
1551
|
+
closed = false;
|
|
1552
|
+
#name;
|
|
1553
|
+
#entry;
|
|
1554
|
+
#data;
|
|
1555
|
+
#hooks;
|
|
1556
|
+
#worker;
|
|
1557
|
+
#address;
|
|
1558
|
+
#proxy;
|
|
1559
|
+
#messageListeners;
|
|
1560
|
+
constructor(opts) {
|
|
1561
|
+
this.#name = opts.name;
|
|
1562
|
+
this.#entry = opts.entry;
|
|
1563
|
+
this.#data = opts.data;
|
|
1564
|
+
this.#hooks = opts.hooks;
|
|
1565
|
+
this.#proxy = createHTTPProxy();
|
|
1566
|
+
this.#messageListeners = /* @__PURE__ */ new Set();
|
|
1567
|
+
this.#initWorker();
|
|
1568
|
+
}
|
|
1569
|
+
get ready() {
|
|
1570
|
+
return Boolean(
|
|
1571
|
+
!this.closed && this.#address && this.#proxy && this.#worker
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
// #region Public methods
|
|
1575
|
+
async fetch(input, init) {
|
|
1576
|
+
for (let i = 0; i < 5 && !(this.#address && this.#proxy); i++) {
|
|
1577
|
+
await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
|
|
1578
|
+
}
|
|
1579
|
+
if (!(this.#address && this.#proxy)) {
|
|
1580
|
+
return new Response("Dev worker is unavailable", { status: 503 });
|
|
1581
|
+
}
|
|
1582
|
+
return fetchAddress(this.#address, input, init);
|
|
1583
|
+
}
|
|
1584
|
+
upgrade(req, socket, head) {
|
|
1585
|
+
if (!this.ready) {
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
return this.#proxy.proxy.ws(
|
|
1589
|
+
req,
|
|
1590
|
+
socket,
|
|
1591
|
+
{ target: this.#address, xfwd: true },
|
|
1592
|
+
head
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
sendMessage(message) {
|
|
1596
|
+
if (!this.#worker) {
|
|
1597
|
+
throw new Error(
|
|
1598
|
+
"Dev worker should be initialized before sending messages."
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
this.#worker.postMessage(message);
|
|
1602
|
+
}
|
|
1603
|
+
onMessage(listener) {
|
|
1604
|
+
this.#messageListeners.add(listener);
|
|
1605
|
+
}
|
|
1606
|
+
offMessage(listener) {
|
|
1607
|
+
this.#messageListeners.delete(listener);
|
|
1608
|
+
}
|
|
1609
|
+
async close(cause) {
|
|
1610
|
+
if (this.closed) {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
this.closed = true;
|
|
1614
|
+
this.#hooks.onClose?.(this, cause);
|
|
1615
|
+
this.#hooks = {};
|
|
1616
|
+
const onError = (error) => consola.error(error);
|
|
1617
|
+
await this.#closeWorker().catch(onError);
|
|
1618
|
+
await this.#closeProxy().catch(onError);
|
|
1619
|
+
await this.#closeSocket().catch(onError);
|
|
1620
|
+
}
|
|
1621
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
1622
|
+
const status = this.closed ? "closed" : this.ready ? "ready" : "pending";
|
|
1623
|
+
return `NodeDevWorker#${this.#name}(${status})`;
|
|
1624
|
+
}
|
|
1625
|
+
// #endregion
|
|
1626
|
+
// #region Private methods
|
|
1627
|
+
#initWorker() {
|
|
1628
|
+
if (!existsSync(this.#entry)) {
|
|
1629
|
+
this.close(`worker entry not found in "${this.#entry}".`);
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const worker = new Worker(this.#entry, {
|
|
1633
|
+
env: {
|
|
1634
|
+
...process.env
|
|
1635
|
+
},
|
|
1636
|
+
workerData: {
|
|
1637
|
+
name: this.#name,
|
|
1638
|
+
...this.#data
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
worker.once("exit", (code) => {
|
|
1642
|
+
worker._exitCode = code;
|
|
1643
|
+
this.close(`worker exited with code ${code}`);
|
|
1644
|
+
});
|
|
1645
|
+
worker.once("error", (error) => {
|
|
1646
|
+
consola.error(`Worker error:`, error);
|
|
1647
|
+
this.close(error);
|
|
1648
|
+
});
|
|
1649
|
+
worker.on("message", (message) => {
|
|
1650
|
+
if (message?.address) {
|
|
1651
|
+
this.#address = message.address;
|
|
1652
|
+
this.#hooks.onReady?.(this, this.#address);
|
|
1653
|
+
}
|
|
1654
|
+
for (const listener of this.#messageListeners) {
|
|
1655
|
+
listener(message);
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
this.#worker = worker;
|
|
1659
|
+
}
|
|
1660
|
+
async #closeProxy() {
|
|
1661
|
+
this.#proxy?.proxy?.close(() => {
|
|
1662
|
+
});
|
|
1663
|
+
this.#proxy = void 0;
|
|
1664
|
+
}
|
|
1665
|
+
async #closeSocket() {
|
|
1666
|
+
const socketPath = this.#address?.socketPath;
|
|
1667
|
+
if (socketPath && socketPath[0] !== "\0" && !socketPath.startsWith(String.raw`\\.\pipe`)) {
|
|
1668
|
+
await rm(socketPath).catch(() => {
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
this.#address = void 0;
|
|
1672
|
+
}
|
|
1673
|
+
async #closeWorker() {
|
|
1674
|
+
if (!this.#worker) {
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
this.#worker.postMessage({ event: "shutdown" });
|
|
1678
|
+
if (!this.#worker._exitCode && !isTest && !isCI) {
|
|
1679
|
+
await new Promise((resolve) => {
|
|
1680
|
+
const gracefulShutdownTimeoutMs = Number.parseInt(process.env.NITRO_SHUTDOWN_TIMEOUT || "", 10) || 5e3;
|
|
1681
|
+
const timeout = setTimeout(() => {
|
|
1682
|
+
if (process.env.DEBUG) {
|
|
1683
|
+
consola.warn(`force closing dev worker...`);
|
|
1684
|
+
}
|
|
1685
|
+
}, gracefulShutdownTimeoutMs);
|
|
1686
|
+
this.#worker?.on("message", (message) => {
|
|
1687
|
+
if (message.event === "exit") {
|
|
1688
|
+
clearTimeout(timeout);
|
|
1689
|
+
resolve();
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
this.#worker.removeAllListeners();
|
|
1695
|
+
await this.#worker.terminate().catch((error) => {
|
|
1696
|
+
consola.error(error);
|
|
1697
|
+
});
|
|
1698
|
+
this.#worker = void 0;
|
|
1699
|
+
}
|
|
1700
|
+
// #endregion
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
function createVFSHandler(nitro) {
|
|
1704
|
+
return defineHandler(async (event) => {
|
|
1705
|
+
const { socket } = event.runtime?.node?.req || {};
|
|
1706
|
+
const isUnixSocket = (
|
|
1707
|
+
// No network addresses
|
|
1708
|
+
!socket?.remoteAddress && !socket?.localAddress && // Empty address object
|
|
1709
|
+
Object.keys(socket?.address?.() || {}).length === 0 && // Socket is readable/writable but has no port info
|
|
1710
|
+
socket?.readable && socket?.writable && !socket?.remotePort
|
|
1711
|
+
);
|
|
1712
|
+
const ip = getRequestIP(event, { xForwardedFor: isUnixSocket });
|
|
1713
|
+
const isLocalRequest = ip && /^::1$|^127\.\d+\.\d+\.\d+$/.test(ip);
|
|
1714
|
+
if (!isLocalRequest) {
|
|
1715
|
+
throw new HTTPError({
|
|
1716
|
+
statusText: `Forbidden IP: "${ip || "?"}"`,
|
|
1717
|
+
status: 403
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
const vfsEntries = {
|
|
1721
|
+
...nitro.vfs,
|
|
1722
|
+
...nitro.options.virtual
|
|
1723
|
+
};
|
|
1724
|
+
const url = event.context.params?._ || "";
|
|
1725
|
+
const isJson = url.endsWith(".json") || event.req.headers.get("accept")?.includes("application/json");
|
|
1726
|
+
const id = decodeURIComponent(url.replace(/^(\.json)?\/?/, "") || "");
|
|
1727
|
+
if (id && !(id in vfsEntries)) {
|
|
1728
|
+
throw new HTTPError({ message: "File not found", status: 404 });
|
|
1729
|
+
}
|
|
1730
|
+
let content = id ? vfsEntries[id] : void 0;
|
|
1731
|
+
if (typeof content === "function") {
|
|
1732
|
+
content = await content();
|
|
1733
|
+
}
|
|
1734
|
+
if (isJson) {
|
|
1735
|
+
return {
|
|
1736
|
+
rootDir: nitro.options.rootDir,
|
|
1737
|
+
entries: Object.keys(vfsEntries).map((id2) => ({
|
|
1738
|
+
id: id2,
|
|
1739
|
+
path: "/_vfs.json/" + encodeURIComponent(id2)
|
|
1740
|
+
})),
|
|
1741
|
+
current: id ? {
|
|
1742
|
+
id,
|
|
1743
|
+
content
|
|
1744
|
+
} : null
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
const directories = { [nitro.options.rootDir]: {} };
|
|
1748
|
+
const fpaths = Object.keys(vfsEntries);
|
|
1749
|
+
for (const item of fpaths) {
|
|
1750
|
+
const segments = item.replace(nitro.options.rootDir, "").split("/").filter(Boolean);
|
|
1751
|
+
let currentDir = item.startsWith(nitro.options.rootDir) ? directories[nitro.options.rootDir] : directories;
|
|
1752
|
+
for (const segment of segments) {
|
|
1753
|
+
if (!currentDir[segment]) {
|
|
1754
|
+
currentDir[segment] = {};
|
|
1755
|
+
}
|
|
1756
|
+
currentDir = currentDir[segment];
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
const generateHTML = (directory, path = []) => Object.entries(directory).map(([fname, value = {}]) => {
|
|
1760
|
+
const subpath = [...path, fname];
|
|
1761
|
+
const key = subpath.join("/");
|
|
1762
|
+
const encodedUrl = encodeURIComponent(key);
|
|
1763
|
+
const linkClass = url === `/${encodedUrl}` ? "bg-gray-700 text-white" : "hover:bg-gray-800 text-gray-200";
|
|
1764
|
+
return Object.keys(value).length === 0 ? `
|
|
1765
|
+
<li class="flex flex-nowrap">
|
|
1766
|
+
<a href="/_vfs/${encodedUrl}" class="w-full text-sm px-2 py-1 border-b border-gray-10 ${linkClass}">
|
|
1767
|
+
${fname}
|
|
1768
|
+
</a>
|
|
1769
|
+
</li>
|
|
1770
|
+
` : `
|
|
1771
|
+
<li>
|
|
1772
|
+
<details ${url.startsWith(`/${encodedUrl}`) ? "open" : ""}>
|
|
1773
|
+
<summary class="w-full text-sm px-2 py-1 border-b border-gray-10 hover:bg-gray-800 text-gray-200">
|
|
1774
|
+
${fname}
|
|
1775
|
+
</summary>
|
|
1776
|
+
<ul class="ml-4">
|
|
1777
|
+
${generateHTML(value, subpath)}
|
|
1778
|
+
</ul>
|
|
1779
|
+
</details>
|
|
1780
|
+
</li>
|
|
1781
|
+
`;
|
|
1782
|
+
}).join("");
|
|
1783
|
+
const rootDirectory = directories[nitro.options.rootDir];
|
|
1784
|
+
delete directories[nitro.options.rootDir];
|
|
1785
|
+
const items = generateHTML(rootDirectory, [nitro.options.rootDir]) + generateHTML(directories);
|
|
1786
|
+
const files = `
|
|
1787
|
+
<div class="h-full overflow-auto border-r border-gray:10">
|
|
1788
|
+
<p class="text-white text-bold text-center py-1 opacity-50">Virtual Files</p>
|
|
1789
|
+
<ul class="flex flex-col">${items}</ul>
|
|
1790
|
+
</div>
|
|
1791
|
+
`;
|
|
1792
|
+
const file = id ? editorTemplate({
|
|
1793
|
+
readOnly: true,
|
|
1794
|
+
language: id.endsWith("html") ? "html" : "javascript",
|
|
1795
|
+
theme: "vs-dark",
|
|
1796
|
+
value: content,
|
|
1797
|
+
wordWrap: "wordWrapColumn",
|
|
1798
|
+
wordWrapColumn: 80
|
|
1799
|
+
}) : `
|
|
1800
|
+
<div class="w-full h-full flex opacity-50">
|
|
1801
|
+
<h1 class="text-white m-auto">Select a virtual file to inspect</h1>
|
|
1802
|
+
</div>
|
|
1803
|
+
`;
|
|
1804
|
+
event.res.headers.set("Content-Type", "text/html; charset=utf-8");
|
|
1805
|
+
return (
|
|
1806
|
+
/* html */
|
|
1807
|
+
`
|
|
1808
|
+
<!doctype html>
|
|
1809
|
+
<html>
|
|
1810
|
+
<head>
|
|
1811
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@unocss/reset/tailwind.min.css" />
|
|
1812
|
+
<link rel="stylesheet" data-name="vs/editor/editor.main" href="${vsUrl}/editor/editor.main.min.css">
|
|
1813
|
+
<script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"><\/script>
|
|
1814
|
+
<style>
|
|
1815
|
+
html {
|
|
1816
|
+
background: #1E1E1E;
|
|
1817
|
+
color: white;
|
|
1818
|
+
}
|
|
1819
|
+
[un-cloak] {
|
|
1820
|
+
display: none;
|
|
1821
|
+
}
|
|
1822
|
+
</style>
|
|
1823
|
+
</head>
|
|
1824
|
+
<body class="bg-[#1E1E1E]">
|
|
1825
|
+
<div un-cloak class="h-screen grid grid-cols-[300px_1fr]">
|
|
1826
|
+
${files}
|
|
1827
|
+
${file}
|
|
1828
|
+
</div>
|
|
1829
|
+
</body>
|
|
1830
|
+
</html>`
|
|
1831
|
+
);
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
const monacoVersion = "0.30.0";
|
|
1835
|
+
const monacoUrl = `https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/${monacoVersion}/min`;
|
|
1836
|
+
const vsUrl = `${monacoUrl}/vs`;
|
|
1837
|
+
const editorTemplate = (options) => `
|
|
1838
|
+
<div id="editor" class="min-h-screen w-full h-full"></div>
|
|
1839
|
+
<script src="${vsUrl}/loader.min.js"><\/script>
|
|
1840
|
+
<script>
|
|
1841
|
+
require.config({ paths: { vs: '${vsUrl}' } })
|
|
1842
|
+
|
|
1843
|
+
const proxy = URL.createObjectURL(new Blob([\`
|
|
1844
|
+
self.MonacoEnvironment = { baseUrl: '${monacoUrl}' }
|
|
1845
|
+
importScripts('${vsUrl}/base/worker/workerMain.min.js')
|
|
1846
|
+
\`], { type: 'text/javascript' }))
|
|
1847
|
+
window.MonacoEnvironment = { getWorkerUrl: () => proxy }
|
|
1848
|
+
|
|
1849
|
+
setTimeout(() => {
|
|
1850
|
+
require(['vs/editor/editor.main'], function () {
|
|
1851
|
+
monaco.editor.create(document.getElementById('editor'), ${JSON.stringify(
|
|
1852
|
+
options
|
|
1853
|
+
)})
|
|
1854
|
+
})
|
|
1855
|
+
}, 0);
|
|
1856
|
+
<\/script>
|
|
1857
|
+
`;
|
|
1858
|
+
|
|
1859
|
+
function defineNitroErrorHandler(handler) {
|
|
1860
|
+
return handler;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const devErrorHandler = defineNitroErrorHandler(
|
|
1864
|
+
async function defaultNitroErrorHandler(error, event) {
|
|
1865
|
+
const res = await defaultHandler(error, event);
|
|
1866
|
+
return new FastResponse(
|
|
1867
|
+
typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2),
|
|
1868
|
+
res
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
);
|
|
1872
|
+
async function defaultHandler(error, event, opts) {
|
|
1873
|
+
const isSensitive = error.unhandled;
|
|
1874
|
+
const status = error.status || 500;
|
|
1875
|
+
const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true });
|
|
1876
|
+
if (status === 404) {
|
|
1877
|
+
const baseURL = import.meta.baseURL || "/";
|
|
1878
|
+
if (/^\/[^/]/.test(baseURL) && !url.pathname.startsWith(baseURL)) {
|
|
1879
|
+
const redirectTo = `${baseURL}${url.pathname.slice(1)}${url.search}`;
|
|
1880
|
+
return {
|
|
1881
|
+
status: 302,
|
|
1882
|
+
statusText: "Found",
|
|
1883
|
+
headers: { location: redirectTo },
|
|
1884
|
+
body: `Redirecting...`
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
await loadStackTrace(error).catch(consola.error);
|
|
1889
|
+
const youch = new Youch();
|
|
1890
|
+
if (isSensitive && !opts?.silent) {
|
|
1891
|
+
const tags = [error.unhandled && "[unhandled]"].filter(Boolean).join(" ");
|
|
1892
|
+
const ansiError = await (await youch.toANSI(error)).replaceAll(process.cwd(), ".");
|
|
1893
|
+
consola.error(
|
|
1894
|
+
`[request error] ${tags} [${event.req.method}] ${url}
|
|
1895
|
+
|
|
1896
|
+
`,
|
|
1897
|
+
ansiError
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
const useJSON = opts?.json || !event.req.headers.get("accept")?.includes("text/html");
|
|
1901
|
+
const headers = {
|
|
1902
|
+
"content-type": useJSON ? "application/json" : "text/html",
|
|
1903
|
+
// Prevent browser from guessing the MIME types of resources.
|
|
1904
|
+
"x-content-type-options": "nosniff",
|
|
1905
|
+
// Prevent error page from being embedded in an iframe
|
|
1906
|
+
"x-frame-options": "DENY",
|
|
1907
|
+
// Prevent browsers from sending the Referer header
|
|
1908
|
+
"referrer-policy": "no-referrer",
|
|
1909
|
+
// Disable the execution of any js
|
|
1910
|
+
"content-security-policy": "script-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self';"
|
|
1911
|
+
};
|
|
1912
|
+
if (status === 404 || !event.res.headers.has("cache-control")) {
|
|
1913
|
+
headers["cache-control"] = "no-cache";
|
|
1914
|
+
}
|
|
1915
|
+
const body = useJSON ? {
|
|
1916
|
+
error: true,
|
|
1917
|
+
url,
|
|
1918
|
+
status,
|
|
1919
|
+
statusText: error.statusText,
|
|
1920
|
+
message: error.message,
|
|
1921
|
+
data: error.data,
|
|
1922
|
+
stack: error.stack?.split("\n").map((line) => line.trim())
|
|
1923
|
+
} : await youch.toHTML(error, {
|
|
1924
|
+
request: {
|
|
1925
|
+
url: url.href,
|
|
1926
|
+
method: event.req.method,
|
|
1927
|
+
headers: Object.fromEntries(event.req.headers.entries())
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
return {
|
|
1931
|
+
status,
|
|
1932
|
+
statusText: error.statusText,
|
|
1933
|
+
headers,
|
|
1934
|
+
body
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
async function loadStackTrace(error) {
|
|
1938
|
+
if (!(error instanceof Error)) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
const parsed = await new ErrorParser().defineSourceLoader(sourceLoader).parse(error);
|
|
1942
|
+
const stack = error.message + "\n" + parsed.frames.map((frame) => fmtFrame(frame)).join("\n");
|
|
1943
|
+
Object.defineProperty(error, "stack", { value: stack });
|
|
1944
|
+
if (error.cause) {
|
|
1945
|
+
await loadStackTrace(error.cause).catch(consola.error);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
async function sourceLoader(frame) {
|
|
1949
|
+
if (!frame.fileName || frame.fileType !== "fs" || frame.type === "native") {
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
if (frame.type === "app") {
|
|
1953
|
+
const rawSourceMap = await readFile(`${frame.fileName}.map`, "utf8").catch(() => {
|
|
1954
|
+
});
|
|
1955
|
+
if (rawSourceMap) {
|
|
1956
|
+
const consumer = await new SourceMapConsumer(rawSourceMap);
|
|
1957
|
+
const originalPosition = consumer.originalPositionFor({ line: frame.lineNumber, column: frame.columnNumber });
|
|
1958
|
+
if (originalPosition.source && originalPosition.line) {
|
|
1959
|
+
frame.fileName = resolve$1(dirname(frame.fileName), originalPosition.source);
|
|
1960
|
+
frame.lineNumber = originalPosition.line;
|
|
1961
|
+
frame.columnNumber = originalPosition.column || 0;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
const contents = await readFile(frame.fileName, "utf8").catch(() => {
|
|
1966
|
+
});
|
|
1967
|
+
return contents ? { contents } : void 0;
|
|
1968
|
+
}
|
|
1969
|
+
function fmtFrame(frame) {
|
|
1970
|
+
if (frame.type === "native") {
|
|
1971
|
+
return frame.raw;
|
|
1972
|
+
}
|
|
1973
|
+
const src = `${frame.fileName || ""}:${frame.lineNumber}:${frame.columnNumber})`;
|
|
1974
|
+
return frame.functionName ? `at ${frame.functionName} (${src}` : `at ${src}`;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
class NitroDevApp {
|
|
1978
|
+
nitro;
|
|
1979
|
+
fetch;
|
|
1980
|
+
constructor(nitro, catchAllHandler) {
|
|
1981
|
+
this.nitro = nitro;
|
|
1982
|
+
const app = this.#createApp(catchAllHandler);
|
|
1983
|
+
this.fetch = app.fetch.bind(app);
|
|
1984
|
+
}
|
|
1985
|
+
#createApp(catchAllHandler) {
|
|
1986
|
+
const app = new H3({
|
|
1987
|
+
debug: true,
|
|
1988
|
+
onError: async (error, event) => {
|
|
1989
|
+
const errorHandler = this.nitro.options.devErrorHandler || devErrorHandler;
|
|
1990
|
+
await loadStackTrace(error).catch(() => {
|
|
1991
|
+
});
|
|
1992
|
+
return errorHandler(error, event, {
|
|
1993
|
+
defaultHandler: defaultHandler
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
for (const h of this.nitro.options.devHandlers) {
|
|
1998
|
+
const handler = toEventHandler(h.handler);
|
|
1999
|
+
if (!handler) {
|
|
2000
|
+
this.nitro.logger.warn("Invalid dev handler:", h);
|
|
2001
|
+
continue;
|
|
2002
|
+
}
|
|
2003
|
+
if (h.middleware || !h.route) {
|
|
2004
|
+
if (h.route) {
|
|
2005
|
+
app.use(h.route, handler, { method: h.method });
|
|
2006
|
+
} else {
|
|
2007
|
+
app.use(handler, { method: h.method });
|
|
2008
|
+
}
|
|
2009
|
+
} else {
|
|
2010
|
+
app.on(h.method || "", h.route, handler, { meta: h.meta });
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
app.get("/_vfs/**", createVFSHandler(this.nitro));
|
|
2014
|
+
for (const asset of this.nitro.options.publicAssets) {
|
|
2015
|
+
const assetRoute = joinURL(
|
|
2016
|
+
this.nitro.options.runtimeConfig.app.baseURL,
|
|
2017
|
+
asset.baseURL || "/",
|
|
2018
|
+
"**"
|
|
2019
|
+
);
|
|
2020
|
+
let handler = fromNodeHandler(
|
|
2021
|
+
// @ts-expect-error (HTTP2 types)
|
|
2022
|
+
serveStatic(asset.dir, { dotfiles: "allow" })
|
|
2023
|
+
);
|
|
2024
|
+
if (asset.baseURL?.length || 0 > 1) {
|
|
2025
|
+
handler = withBase$1(asset.baseURL, handler);
|
|
2026
|
+
}
|
|
2027
|
+
app.use(assetRoute, handler);
|
|
2028
|
+
}
|
|
2029
|
+
const routes = Object.keys(this.nitro.options.devProxy).sort().reverse();
|
|
2030
|
+
for (const route of routes) {
|
|
2031
|
+
let opts = this.nitro.options.devProxy[route];
|
|
2032
|
+
if (typeof opts === "string") {
|
|
2033
|
+
opts = { target: opts };
|
|
2034
|
+
}
|
|
2035
|
+
const proxy = createHTTPProxy(opts);
|
|
2036
|
+
app.all(route, proxy.handleEvent);
|
|
2037
|
+
}
|
|
2038
|
+
if (catchAllHandler) {
|
|
2039
|
+
app.all("/**", catchAllHandler);
|
|
2040
|
+
}
|
|
2041
|
+
return app;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
function createDevServer(nitro) {
|
|
2046
|
+
return new NitroDevServer(nitro);
|
|
2047
|
+
}
|
|
2048
|
+
class NitroDevServer extends NitroDevApp {
|
|
2049
|
+
#entry;
|
|
2050
|
+
#workerData = {};
|
|
2051
|
+
#listeners = [];
|
|
2052
|
+
#watcher;
|
|
2053
|
+
#workers = [];
|
|
2054
|
+
#workerIdCtr = 0;
|
|
2055
|
+
#workerError;
|
|
2056
|
+
#building = true;
|
|
2057
|
+
// Assume initial build will start soon
|
|
2058
|
+
#buildError;
|
|
2059
|
+
#messageListeners = /* @__PURE__ */ new Set();
|
|
2060
|
+
constructor(nitro) {
|
|
2061
|
+
super(nitro, async (event) => {
|
|
2062
|
+
const worker = await this.#getWorker();
|
|
2063
|
+
if (!worker) {
|
|
2064
|
+
return this.#generateError();
|
|
2065
|
+
}
|
|
2066
|
+
return worker.fetch(event.req);
|
|
2067
|
+
});
|
|
2068
|
+
for (const key of Object.getOwnPropertyNames(NitroDevServer.prototype)) {
|
|
2069
|
+
const value = this[key];
|
|
2070
|
+
if (typeof value === "function" && key !== "constructor") {
|
|
2071
|
+
this[key] = value.bind(this);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
this.#entry = resolve(
|
|
2075
|
+
nitro.options.output.dir,
|
|
2076
|
+
nitro.options.output.serverDir,
|
|
2077
|
+
"index.mjs"
|
|
2078
|
+
);
|
|
2079
|
+
nitro.hooks.hook("close", () => this.close());
|
|
2080
|
+
nitro.hooks.hook("dev:start", () => {
|
|
2081
|
+
this.#building = true;
|
|
2082
|
+
this.#buildError = void 0;
|
|
2083
|
+
});
|
|
2084
|
+
nitro.hooks.hook("dev:reload", (payload) => {
|
|
2085
|
+
this.#buildError = void 0;
|
|
2086
|
+
this.#building = false;
|
|
2087
|
+
if (payload?.entry) {
|
|
2088
|
+
this.#entry = payload.entry;
|
|
2089
|
+
}
|
|
2090
|
+
if (payload?.workerData) {
|
|
2091
|
+
this.#workerData = payload.workerData;
|
|
2092
|
+
}
|
|
2093
|
+
this.reload();
|
|
2094
|
+
});
|
|
2095
|
+
nitro.hooks.hook("dev:error", (cause) => {
|
|
2096
|
+
this.#buildError = cause;
|
|
2097
|
+
this.#building = false;
|
|
2098
|
+
for (const worker of this.#workers) {
|
|
2099
|
+
worker.close();
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
if (nitro.options.devServer.watch.length > 0) {
|
|
2103
|
+
const debouncedReload = debounce(() => this.reload());
|
|
2104
|
+
this.#watcher = watch(
|
|
2105
|
+
nitro.options.devServer.watch,
|
|
2106
|
+
nitro.options.watchOptions
|
|
2107
|
+
);
|
|
2108
|
+
this.#watcher.on("add", debouncedReload).on("change", debouncedReload);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
// #region Public Methods
|
|
2112
|
+
async upgrade(req, socket, head) {
|
|
2113
|
+
const worker = await this.#getWorker();
|
|
2114
|
+
if (!worker) {
|
|
2115
|
+
throw new HTTPError({
|
|
2116
|
+
status: 503,
|
|
2117
|
+
statusText: "No worker available."
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
return worker.upgrade(req, socket, head);
|
|
2121
|
+
}
|
|
2122
|
+
listen(opts) {
|
|
2123
|
+
const server = serve({
|
|
2124
|
+
...opts,
|
|
2125
|
+
fetch: this.fetch
|
|
2126
|
+
});
|
|
2127
|
+
this.#listeners.push(server);
|
|
2128
|
+
if (server.node?.server) {
|
|
2129
|
+
server.node.server.on(
|
|
2130
|
+
"upgrade",
|
|
2131
|
+
(req, sock, head) => this.upgrade(req, sock, head)
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
return server;
|
|
2135
|
+
}
|
|
2136
|
+
async close() {
|
|
2137
|
+
await Promise.all(
|
|
2138
|
+
[
|
|
2139
|
+
Promise.all(this.#listeners.map((l) => l.close())).then(() => {
|
|
2140
|
+
this.#listeners = [];
|
|
2141
|
+
}),
|
|
2142
|
+
Promise.all(this.#workers.map((w) => w.close())).then(() => {
|
|
2143
|
+
this.#workers = [];
|
|
2144
|
+
}),
|
|
2145
|
+
Promise.resolve(this.#watcher?.close()).then(() => {
|
|
2146
|
+
this.#watcher = void 0;
|
|
2147
|
+
})
|
|
2148
|
+
].map(
|
|
2149
|
+
(p) => p.catch((error) => {
|
|
2150
|
+
consola.error(error);
|
|
2151
|
+
})
|
|
2152
|
+
)
|
|
2153
|
+
);
|
|
2154
|
+
}
|
|
2155
|
+
reload() {
|
|
2156
|
+
for (const worker2 of this.#workers) {
|
|
2157
|
+
worker2.close();
|
|
2158
|
+
}
|
|
2159
|
+
const worker = new NodeDevWorker({
|
|
2160
|
+
name: `Nitro_${this.#workerIdCtr++}`,
|
|
2161
|
+
entry: this.#entry,
|
|
2162
|
+
data: {
|
|
2163
|
+
...this.#workerData,
|
|
2164
|
+
globals: {
|
|
2165
|
+
__NITRO_RUNTIME_CONFIG__: this.nitro.options.runtimeConfig,
|
|
2166
|
+
...this.#workerData.globals
|
|
2167
|
+
}
|
|
2168
|
+
},
|
|
2169
|
+
hooks: {
|
|
2170
|
+
onClose: (worker2, cause) => {
|
|
2171
|
+
this.#workerError = cause;
|
|
2172
|
+
const index = this.#workers.indexOf(worker2);
|
|
2173
|
+
if (index !== -1) {
|
|
2174
|
+
this.#workers.splice(index, 1);
|
|
2175
|
+
}
|
|
2176
|
+
},
|
|
2177
|
+
onReady: (worker2, addr) => {
|
|
2178
|
+
this.#writeBuildInfo(worker2, addr);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
if (!worker.closed) {
|
|
2183
|
+
for (const listener of this.#messageListeners) {
|
|
2184
|
+
worker.onMessage(listener);
|
|
2185
|
+
}
|
|
2186
|
+
this.#workers.unshift(worker);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
sendMessage(message) {
|
|
2190
|
+
for (const worker of this.#workers) {
|
|
2191
|
+
if (!worker.closed) {
|
|
2192
|
+
worker.sendMessage(message);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
onMessage(listener) {
|
|
2197
|
+
this.#messageListeners.add(listener);
|
|
2198
|
+
for (const worker of this.#workers) {
|
|
2199
|
+
worker.onMessage(listener);
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
offMessage(listener) {
|
|
2203
|
+
this.#messageListeners.delete(listener);
|
|
2204
|
+
for (const worker of this.#workers) {
|
|
2205
|
+
worker.offMessage(listener);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
// #endregion
|
|
2209
|
+
// #region Private Methods
|
|
2210
|
+
#writeBuildInfo(_worker, addr) {
|
|
2211
|
+
const buildInfoPath = resolve(this.nitro.options.buildDir, "nitro.json");
|
|
2212
|
+
const buildInfo = {
|
|
2213
|
+
date: (/* @__PURE__ */ new Date()).toJSON(),
|
|
2214
|
+
preset: this.nitro.options.preset,
|
|
2215
|
+
framework: this.nitro.options.framework,
|
|
2216
|
+
versions: {
|
|
2217
|
+
nitro: version
|
|
2218
|
+
},
|
|
2219
|
+
dev: {
|
|
2220
|
+
pid: process.pid,
|
|
2221
|
+
workerAddress: addr
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
writeFile$1(buildInfoPath, JSON.stringify(buildInfo, null, 2)).catch(
|
|
2225
|
+
(error) => {
|
|
2226
|
+
consola.error(error);
|
|
2227
|
+
}
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
async #getWorker() {
|
|
2231
|
+
let retry = 0;
|
|
2232
|
+
const maxRetries = isTest || isCI ? 100 : 10;
|
|
2233
|
+
while (this.#building || ++retry < maxRetries) {
|
|
2234
|
+
if ((this.#workers.length === 0 || this.#buildError) && !this.#building) {
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
const activeWorker = this.#workers.find((w) => w.ready);
|
|
2238
|
+
if (activeWorker) {
|
|
2239
|
+
return activeWorker;
|
|
2240
|
+
}
|
|
2241
|
+
await new Promise((resolve2) => setTimeout(resolve2, 600));
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
#generateError() {
|
|
2245
|
+
const error = this.#buildError || this.#workerError;
|
|
2246
|
+
if (error) {
|
|
2247
|
+
try {
|
|
2248
|
+
error.unhandled = false;
|
|
2249
|
+
let id = error.id || error.path;
|
|
2250
|
+
if (id) {
|
|
2251
|
+
const cause = error.errors?.[0];
|
|
2252
|
+
const loc = error.location || error.loc || cause?.location || cause?.loc;
|
|
2253
|
+
if (loc) {
|
|
2254
|
+
id += `:${loc.line}:${loc.column}`;
|
|
2255
|
+
}
|
|
2256
|
+
error.stack = (error.stack || "").replace(
|
|
2257
|
+
/(^\s*at\s+.+)/m,
|
|
2258
|
+
` at ${id}
|
|
2259
|
+
$1`
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
} catch {
|
|
2263
|
+
}
|
|
2264
|
+
return new HTTPError(error);
|
|
2265
|
+
}
|
|
2266
|
+
return new Response(
|
|
2267
|
+
JSON.stringify(
|
|
2268
|
+
{
|
|
2269
|
+
error: "Dev server is unavailable.",
|
|
2270
|
+
hint: "Please reload the page and check the console for errors if the issue persists."
|
|
2271
|
+
},
|
|
2272
|
+
null,
|
|
2273
|
+
2
|
|
2274
|
+
),
|
|
2275
|
+
{
|
|
2276
|
+
status: 503,
|
|
2277
|
+
statusText: "Dev server is unavailable",
|
|
2278
|
+
headers: {
|
|
2279
|
+
"Content-Type": "application/json",
|
|
2280
|
+
"Cache-Control": "no-store",
|
|
2281
|
+
Refresh: "3"
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
);
|
|
2285
|
+
}
|
|
2286
|
+
// #endregion
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
const getViteRollupConfig = (ctx) => {
|
|
2290
|
+
const nitro = ctx.nitro;
|
|
2291
|
+
const base = baseBuildConfig(nitro);
|
|
2292
|
+
const chunkNamePrefixes = [
|
|
2293
|
+
[nitro.options.buildDir, "build"],
|
|
2294
|
+
[base.buildServerDir, "app"],
|
|
2295
|
+
[runtimeDir, "nitro"],
|
|
2296
|
+
[base.presetsDir, "nitro"],
|
|
2297
|
+
["\0nitro-wasm:", "wasm"],
|
|
2298
|
+
["\0", "virtual"]
|
|
2299
|
+
];
|
|
2300
|
+
function getChunkGroup(id) {
|
|
2301
|
+
if (id.startsWith(runtimeDir) || id.startsWith(base.presetsDir)) {
|
|
2302
|
+
return "nitro";
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
let config = {
|
|
2306
|
+
input: nitro.options.entry,
|
|
2307
|
+
external: [...base.env.external],
|
|
2308
|
+
plugins: [
|
|
2309
|
+
ctx.pluginConfig.experimental?.virtualBundle && virtualBundlePlugin(ctx._serviceBundles),
|
|
2310
|
+
...baseBuildPlugins(nitro, base),
|
|
2311
|
+
alias({ entries: base.aliases }),
|
|
2312
|
+
replace({
|
|
2313
|
+
delimiters: base.replaceDelimiters,
|
|
2314
|
+
preventAssignment: true,
|
|
2315
|
+
values: base.replacements
|
|
2316
|
+
}),
|
|
2317
|
+
inject(base.env.inject)
|
|
2318
|
+
].filter(Boolean),
|
|
2319
|
+
treeshake: {
|
|
2320
|
+
moduleSideEffects(id) {
|
|
2321
|
+
const normalizedId = normalize(id);
|
|
2322
|
+
const idWithoutNodeModules = normalizedId.split("node_modules/").pop();
|
|
2323
|
+
if (!idWithoutNodeModules) {
|
|
2324
|
+
return false;
|
|
2325
|
+
}
|
|
2326
|
+
if (normalizedId.startsWith(runtimeDir) || idWithoutNodeModules.startsWith(runtimeDir)) {
|
|
2327
|
+
return true;
|
|
2328
|
+
}
|
|
2329
|
+
return nitro.options.moduleSideEffects.some(
|
|
2330
|
+
(m) => normalizedId.startsWith(m) || idWithoutNodeModules.startsWith(m)
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
output: {
|
|
2335
|
+
dir: nitro.options.output.serverDir,
|
|
2336
|
+
entryFileNames: "index.mjs",
|
|
2337
|
+
chunkFileNames(chunk) {
|
|
2338
|
+
const id = normalize(chunk.moduleIds.at(-1) || "");
|
|
2339
|
+
for (const [dir, name] of chunkNamePrefixes) {
|
|
2340
|
+
if (id.startsWith(dir)) {
|
|
2341
|
+
return `chunks/${name}/[name].mjs`;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
const routeHandler = nitro.options.handlers.find(
|
|
2345
|
+
(h) => id.startsWith(h.handler)
|
|
2346
|
+
) || nitro.scannedHandlers.find((h) => id.startsWith(h.handler));
|
|
2347
|
+
if (routeHandler?.route) {
|
|
2348
|
+
const path = routeHandler.route.replace(/:([^/]+)/g, "_$1").replace(/\/[^/]+$/g, "") || "/";
|
|
2349
|
+
return `chunks/routes/${path}/[name].mjs`.replace(/\/+/g, "/");
|
|
2350
|
+
}
|
|
2351
|
+
const taskHandler = Object.entries(nitro.options.tasks).find(
|
|
2352
|
+
([_, task]) => task.handler === id
|
|
2353
|
+
);
|
|
2354
|
+
if (taskHandler) {
|
|
2355
|
+
return `chunks/tasks/[name].mjs`;
|
|
2356
|
+
}
|
|
2357
|
+
return `chunks/_/[name].mjs`;
|
|
2358
|
+
},
|
|
2359
|
+
manualChunks(id) {
|
|
2360
|
+
return getChunkGroup(id);
|
|
2361
|
+
},
|
|
2362
|
+
inlineDynamicImports: nitro.options.inlineDynamicImports,
|
|
2363
|
+
format: "esm",
|
|
2364
|
+
exports: "auto",
|
|
2365
|
+
intro: "",
|
|
2366
|
+
outro: "",
|
|
2367
|
+
generatedCode: {
|
|
2368
|
+
constBindings: true
|
|
2369
|
+
},
|
|
2370
|
+
sanitizeFileName: sanitizeFilePath,
|
|
2371
|
+
sourcemapExcludeSources: true,
|
|
2372
|
+
sourcemapIgnoreList(relativePath) {
|
|
2373
|
+
return relativePath.includes("node_modules");
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
config = defu(nitro.options.rollupConfig, config);
|
|
2378
|
+
if (config.output.inlineDynamicImports) {
|
|
2379
|
+
delete config.output.manualChunks;
|
|
2380
|
+
}
|
|
2381
|
+
return { config, base };
|
|
2382
|
+
};
|
|
2383
|
+
function virtualBundlePlugin(bundles) {
|
|
2384
|
+
let _modules = null;
|
|
2385
|
+
const getModules = () => {
|
|
2386
|
+
if (_modules) {
|
|
2387
|
+
return _modules;
|
|
2388
|
+
}
|
|
2389
|
+
_modules = /* @__PURE__ */ new Map();
|
|
2390
|
+
for (const bundle of Object.values(bundles)) {
|
|
2391
|
+
for (const [fileName, content] of Object.entries(bundle)) {
|
|
2392
|
+
if (content.type === "chunk") {
|
|
2393
|
+
const virtualModule = {
|
|
2394
|
+
code: content.code,
|
|
2395
|
+
map: null
|
|
2396
|
+
};
|
|
2397
|
+
const maybeMap = bundle[`${fileName}.map`];
|
|
2398
|
+
if (maybeMap && maybeMap.type === "asset") {
|
|
2399
|
+
virtualModule.map = maybeMap.source;
|
|
2400
|
+
}
|
|
2401
|
+
_modules.set(fileName, virtualModule);
|
|
2402
|
+
_modules.set(resolve(fileName), virtualModule);
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
return _modules;
|
|
2407
|
+
};
|
|
2408
|
+
return {
|
|
2409
|
+
name: "virtual-bundle",
|
|
2410
|
+
resolveId(id, importer) {
|
|
2411
|
+
const modules = getModules();
|
|
2412
|
+
if (modules.has(id)) {
|
|
2413
|
+
return resolve(id);
|
|
2414
|
+
}
|
|
2415
|
+
if (importer) {
|
|
2416
|
+
const resolved = resolve(dirname$1(importer), id);
|
|
2417
|
+
if (modules.has(resolved)) {
|
|
2418
|
+
return resolved;
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
return null;
|
|
2422
|
+
},
|
|
2423
|
+
load(id) {
|
|
2424
|
+
const modules = getModules();
|
|
2425
|
+
const m = modules.get(id);
|
|
2426
|
+
if (!m) {
|
|
2427
|
+
return null;
|
|
2428
|
+
}
|
|
2429
|
+
return m;
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
const BuilderNames = {
|
|
2435
|
+
nitro: colors.magenta("Nitro"),
|
|
2436
|
+
client: colors.green("Client"),
|
|
2437
|
+
ssr: colors.blue("SSR")
|
|
2438
|
+
};
|
|
2439
|
+
async function buildEnvironments(ctx, builder) {
|
|
2440
|
+
const nitro = ctx.nitro;
|
|
2441
|
+
for (const [envName, env] of Object.entries(builder.environments)) {
|
|
2442
|
+
const fmtName = BuilderNames[envName] || (envName.length <= 3 ? envName.toUpperCase() : envName[0].toUpperCase() + envName.slice(1));
|
|
2443
|
+
if (envName === "nitro" || !env.config.build.rollupOptions.input || env.isBuilt) {
|
|
2444
|
+
if (!["nitro", "ssr", "client"].includes(envName)) {
|
|
2445
|
+
nitro.logger.info(
|
|
2446
|
+
env.isBuilt ? `Skipping ${fmtName} (already built)` : `Skipping ${fmtName} (no input defined)`
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
continue;
|
|
2450
|
+
}
|
|
2451
|
+
if (!isTest && !isCI) console.log();
|
|
2452
|
+
nitro.logger.start(`Building [${fmtName}]`);
|
|
2453
|
+
await builder.build(env);
|
|
2454
|
+
}
|
|
2455
|
+
const nitroOptions = ctx.nitro.options;
|
|
2456
|
+
const clientInput = builder.environments.client?.config?.build?.rollupOptions?.input;
|
|
2457
|
+
if (nitroOptions.renderer?.template && nitroOptions.renderer?.template === clientInput) {
|
|
2458
|
+
const outputPath = resolve(
|
|
2459
|
+
nitroOptions.output.publicDir,
|
|
2460
|
+
basename(clientInput)
|
|
2461
|
+
);
|
|
2462
|
+
if (existsSync(outputPath)) {
|
|
2463
|
+
const html = await readFile(outputPath, "utf8").then(
|
|
2464
|
+
(r) => r.replace(
|
|
2465
|
+
"<!--ssr-outlet-->",
|
|
2466
|
+
`{{{ fetch($REQUEST, { viteEnv: "ssr" }) }}}`
|
|
2467
|
+
)
|
|
2468
|
+
);
|
|
2469
|
+
await rm(outputPath);
|
|
2470
|
+
const tmp = resolve(nitroOptions.buildDir, "vite/index.html");
|
|
2471
|
+
await mkdir(dirname$1(tmp), { recursive: true });
|
|
2472
|
+
await writeFile$1(tmp, html, "utf8");
|
|
2473
|
+
nitroOptions.renderer.template = tmp;
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
await builder.writeAssetsManifest?.();
|
|
2477
|
+
if (!isTest && !isCI) console.log();
|
|
2478
|
+
const buildInfo = [
|
|
2479
|
+
["preset", nitro.options.preset],
|
|
2480
|
+
["compatibility", formatCompatibilityDate(nitro.options.compatibilityDate)]
|
|
2481
|
+
].filter((e) => e[1]);
|
|
2482
|
+
nitro.logger.start(
|
|
2483
|
+
`Building [${BuilderNames.nitro}] ${colors.dim(`(${buildInfo.map(([k, v]) => `${k}: \`${v}\``).join(", ")})`)}`
|
|
2484
|
+
);
|
|
2485
|
+
await copyPublicAssets(nitro);
|
|
2486
|
+
await builder.build(builder.environments.nitro);
|
|
2487
|
+
await nitro.close();
|
|
2488
|
+
await nitro.hooks.callHook("compiled", nitro);
|
|
2489
|
+
await writeBuildInfo(nitro);
|
|
2490
|
+
const rOutput = relative(process.cwd(), nitro.options.output.dir);
|
|
2491
|
+
const rewriteRelativePaths = (input) => {
|
|
2492
|
+
return input.replace(/([\s:])\.\/(\S*)/g, `$1${rOutput}/$2`);
|
|
2493
|
+
};
|
|
2494
|
+
if (!isTest && !isCI) console.log();
|
|
2495
|
+
if (nitro.options.commands.preview) {
|
|
2496
|
+
nitro.logger.success(
|
|
2497
|
+
`You can preview this build using \`${rewriteRelativePaths(
|
|
2498
|
+
nitro.options.commands.preview
|
|
2499
|
+
)}\``
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
if (nitro.options.commands.deploy) {
|
|
2503
|
+
nitro.logger.success(
|
|
2504
|
+
`You can deploy this build using \`${rewriteRelativePaths(
|
|
2505
|
+
nitro.options.commands.deploy
|
|
2506
|
+
)}\``
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
function prodSetup(ctx) {
|
|
2511
|
+
const services = ctx.pluginConfig.services || {};
|
|
2512
|
+
const serviceNames = Object.keys(services);
|
|
2513
|
+
const serviceEntries = serviceNames.map((name) => {
|
|
2514
|
+
let entry;
|
|
2515
|
+
if (ctx.pluginConfig.experimental?.virtualBundle) {
|
|
2516
|
+
entry = ctx._entryPoints[name];
|
|
2517
|
+
} else {
|
|
2518
|
+
entry = resolve(
|
|
2519
|
+
ctx.nitro.options.buildDir,
|
|
2520
|
+
"vite/services",
|
|
2521
|
+
name,
|
|
2522
|
+
ctx._entryPoints[name]
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
return [name, entry];
|
|
2526
|
+
});
|
|
2527
|
+
return (
|
|
2528
|
+
/* js */
|
|
2529
|
+
`
|
|
2530
|
+
import { setupVite } from "${resolve(runtimeDir, "internal/vite/prod-setup.mjs")}";
|
|
2531
|
+
|
|
2532
|
+
const manifest = ${JSON.stringify(ctx._manifest || {})};
|
|
2533
|
+
|
|
2534
|
+
function lazyService(loader) {
|
|
2535
|
+
let promise, mod
|
|
2536
|
+
return {
|
|
2537
|
+
fetch(req) {
|
|
2538
|
+
if (mod) { return mod.fetch(req) }
|
|
2539
|
+
if (!promise) {
|
|
2540
|
+
promise = loader().then(_mod => (mod = _mod.default || _mod))
|
|
2541
|
+
}
|
|
2542
|
+
return promise.then(mod => mod.fetch(req))
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
const services = {
|
|
2548
|
+
${serviceEntries.map(
|
|
2549
|
+
([name, entry]) => (
|
|
2550
|
+
/* js */
|
|
2551
|
+
`[${JSON.stringify(name)}]: lazyService(() => import(${JSON.stringify(entry)}))`
|
|
2552
|
+
)
|
|
2553
|
+
).join(",\n")}
|
|
2554
|
+
};
|
|
2555
|
+
|
|
2556
|
+
setupVite({ manifest, services });
|
|
2557
|
+
`
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
function createFetchableDevEnvironment(name, config, devServer, entry) {
|
|
2562
|
+
const transport = createTransport(name, devServer);
|
|
2563
|
+
const context = { hot: true, transport };
|
|
2564
|
+
return new FetchableDevEnvironment(name, config, context, devServer, entry);
|
|
2565
|
+
}
|
|
2566
|
+
class FetchableDevEnvironment extends DevEnvironment {
|
|
2567
|
+
devServer;
|
|
2568
|
+
constructor(name, config, context, devServer, entry) {
|
|
2569
|
+
super(name, config, context);
|
|
2570
|
+
this.devServer = devServer;
|
|
2571
|
+
this.devServer.sendMessage({
|
|
2572
|
+
type: "custom",
|
|
2573
|
+
event: "nitro:vite-env",
|
|
2574
|
+
data: { name, entry }
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
async dispatchFetch(request) {
|
|
2578
|
+
return this.devServer.fetch(request);
|
|
2579
|
+
}
|
|
2580
|
+
async init(...args) {
|
|
2581
|
+
await this.devServer.init?.();
|
|
2582
|
+
return super.init(...args);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
function createTransport(name, hooks) {
|
|
2586
|
+
const listeners = /* @__PURE__ */ new WeakMap();
|
|
2587
|
+
return {
|
|
2588
|
+
send: (data) => hooks.sendMessage({ ...data, viteEnv: name }),
|
|
2589
|
+
on: (event, handler) => {
|
|
2590
|
+
if (event === "connection") return;
|
|
2591
|
+
const listener = (value) => {
|
|
2592
|
+
if (value?.type === "custom" && value.event === event && value.viteEnv === name) {
|
|
2593
|
+
handler(value.data, {
|
|
2594
|
+
send: (payload) => hooks.sendMessage({ ...payload, viteEnv: name })
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
};
|
|
2598
|
+
listeners.set(handler, listener);
|
|
2599
|
+
hooks.onMessage(listener);
|
|
2600
|
+
},
|
|
2601
|
+
off: (event, handler) => {
|
|
2602
|
+
if (event === "connection") return;
|
|
2603
|
+
const listener = listeners.get(handler);
|
|
2604
|
+
if (listener) {
|
|
2605
|
+
hooks.offMessage(listener);
|
|
2606
|
+
listeners.delete(handler);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
async function configureViteDevServer(ctx, server) {
|
|
2612
|
+
const nitro = ctx.nitro;
|
|
2613
|
+
const nitroEnv = server.environments.nitro;
|
|
2614
|
+
const nitroConfigFile = nitro.options._c12.configFile;
|
|
2615
|
+
if (nitroConfigFile) {
|
|
2616
|
+
server.config.configFileDependencies.push(nitroConfigFile);
|
|
2617
|
+
}
|
|
2618
|
+
const reload = debounce(async () => {
|
|
2619
|
+
await scanHandlers(nitro);
|
|
2620
|
+
nitro.routing.sync();
|
|
2621
|
+
nitroEnv.moduleGraph.invalidateAll();
|
|
2622
|
+
nitroEnv.hot.send({ type: "full-reload" });
|
|
2623
|
+
});
|
|
2624
|
+
const scanDirs = nitro.options.scanDirs.flatMap((dir) => [
|
|
2625
|
+
join(dir, nitro.options.apiDir || "api"),
|
|
2626
|
+
join(dir, nitro.options.routesDir || "routes"),
|
|
2627
|
+
join(dir, "middleware"),
|
|
2628
|
+
join(dir, "plugins"),
|
|
2629
|
+
join(dir, "modules")
|
|
2630
|
+
]);
|
|
2631
|
+
const watchReloadEvents = /* @__PURE__ */ new Set(["add", "addDir", "unlink", "unlinkDir"]);
|
|
2632
|
+
const scanDirsWatcher = watch(scanDirs, {
|
|
2633
|
+
ignoreInitial: true
|
|
2634
|
+
}).on("all", (event, path, stat) => {
|
|
2635
|
+
if (watchReloadEvents.has(event)) {
|
|
2636
|
+
reload();
|
|
2637
|
+
}
|
|
2638
|
+
});
|
|
2639
|
+
const srcDirWatcher = watch$1(
|
|
2640
|
+
nitro.options.srcDir,
|
|
2641
|
+
{ persistent: false },
|
|
2642
|
+
(_event, filename) => {
|
|
2643
|
+
if (filename && /^server\.[mc]?[jt]sx?$/.test(filename)) {
|
|
2644
|
+
reload();
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
);
|
|
2648
|
+
nitro.hooks.hook("close", () => {
|
|
2649
|
+
scanDirsWatcher.close();
|
|
2650
|
+
srcDirWatcher.close();
|
|
2651
|
+
});
|
|
2652
|
+
const hostIPC = {
|
|
2653
|
+
async transformHTML(html) {
|
|
2654
|
+
return server.transformIndexHtml("/", html).then(
|
|
2655
|
+
(r) => r.replace(
|
|
2656
|
+
"<!--ssr-outlet-->",
|
|
2657
|
+
`{{{ fetch($REQUEST, { viteEnv: "ssr" }) }}}`
|
|
2658
|
+
)
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2662
|
+
nitroEnv.devServer.onMessage(async (payload) => {
|
|
2663
|
+
if (payload.type === "custom" && payload.event === "nitro:vite-invoke") {
|
|
2664
|
+
const methodName = payload.data.name;
|
|
2665
|
+
const res = await hostIPC[methodName](payload.data.data).then((data) => ({ data })).catch((error) => ({ error }));
|
|
2666
|
+
nitroEnv.devServer.sendMessage({
|
|
2667
|
+
type: "custom",
|
|
2668
|
+
event: "nitro:vite-invoke-response",
|
|
2669
|
+
data: { id: payload.data.id, data: res }
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2672
|
+
});
|
|
2673
|
+
const nitroDevMiddleware = async (nodeReq, nodeRes, next) => {
|
|
2674
|
+
if (/^\/@(?:vite|fs|id)\//.test(nodeReq.url) || nodeReq._nitroHandled) {
|
|
2675
|
+
return next();
|
|
2676
|
+
}
|
|
2677
|
+
nodeReq._nitroHandled = true;
|
|
2678
|
+
const req = new NodeRequest({ req: nodeReq, res: nodeRes });
|
|
2679
|
+
const devAppRes = await ctx.devApp.fetch(req);
|
|
2680
|
+
if (nodeRes.writableEnded || nodeRes.headersSent) {
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
if (devAppRes.status !== 404) {
|
|
2684
|
+
return await sendNodeResponse(nodeRes, devAppRes);
|
|
2685
|
+
}
|
|
2686
|
+
const envRes = await nitroEnv.dispatchFetch(req);
|
|
2687
|
+
if (nodeRes.writableEnded || nodeRes.headersSent) {
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
if (envRes.status !== 404) {
|
|
2691
|
+
return await sendNodeResponse(nodeRes, envRes);
|
|
2692
|
+
}
|
|
2693
|
+
return next();
|
|
2694
|
+
};
|
|
2695
|
+
server.middlewares.use(function nitroDevMiddlewarePre(req, res, next) {
|
|
2696
|
+
const fetchDest = req.headers["sec-fetch-dest"];
|
|
2697
|
+
if (fetchDest) {
|
|
2698
|
+
res.setHeader("vary", "sec-fetch-dest");
|
|
2699
|
+
}
|
|
2700
|
+
const ext = (req.url || "").match(/\.([a-z0-9]+)(?:[?#]|$)/i)?.[1] || "";
|
|
2701
|
+
if (!ext && (!fetchDest || /^(document|iframe|frame|empty)$/.test(fetchDest))) {
|
|
2702
|
+
nitroDevMiddleware(req, res, next);
|
|
2703
|
+
} else {
|
|
2704
|
+
next();
|
|
2705
|
+
}
|
|
2706
|
+
});
|
|
2707
|
+
return () => {
|
|
2708
|
+
server.middlewares.use(nitroDevMiddleware);
|
|
2709
|
+
};
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
function createDevWorker(ctx) {
|
|
2713
|
+
return new NodeDevWorker({
|
|
2714
|
+
name: "nitro-vite",
|
|
2715
|
+
entry: resolve$1(runtimeDir, "internal/vite/dev-worker.mjs"),
|
|
2716
|
+
hooks: {},
|
|
2717
|
+
data: {
|
|
2718
|
+
server: true,
|
|
2719
|
+
globals: {
|
|
2720
|
+
__NITRO_RUNTIME_CONFIG__: ctx.nitro.options.runtimeConfig
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2725
|
+
function createNitroEnvironment(ctx) {
|
|
2726
|
+
return {
|
|
2727
|
+
consumer: "server",
|
|
2728
|
+
build: {
|
|
2729
|
+
rollupOptions: ctx.rollupConfig.config,
|
|
2730
|
+
minify: ctx.nitro.options.minify,
|
|
2731
|
+
emptyOutDir: false,
|
|
2732
|
+
commonjsOptions: {
|
|
2733
|
+
strictRequires: "auto",
|
|
2734
|
+
// TODO: set to true (default) in v3
|
|
2735
|
+
esmExternals: (id) => !id.startsWith("unenv/"),
|
|
2736
|
+
requireReturnsDefault: "auto",
|
|
2737
|
+
...ctx.nitro.options.commonJS
|
|
2738
|
+
}
|
|
2739
|
+
},
|
|
2740
|
+
resolve: {
|
|
2741
|
+
noExternal: ctx.nitro.options.dev ? (
|
|
2742
|
+
// Workaround for dev: external dependencies are not resolvable with respect to nodeModulePaths
|
|
2743
|
+
new RegExp(runtimeDependencies.join("|"))
|
|
2744
|
+
) : void 0,
|
|
2745
|
+
conditions: ctx.nitro.options.exportConditions,
|
|
2746
|
+
externalConditions: ctx.nitro.options.exportConditions
|
|
2747
|
+
},
|
|
2748
|
+
dev: {
|
|
2749
|
+
createEnvironment: (envName, envConfig) => createFetchableDevEnvironment(
|
|
2750
|
+
envName,
|
|
2751
|
+
envConfig,
|
|
2752
|
+
ctx.devWorker,
|
|
2753
|
+
resolve$1(runtimeDir, "internal/vite/dev-entry.mjs")
|
|
2754
|
+
)
|
|
2755
|
+
}
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
function createServiceEnvironment(ctx, name, serviceConfig) {
|
|
2759
|
+
return {
|
|
2760
|
+
consumer: "server",
|
|
2761
|
+
build: {
|
|
2762
|
+
rollupOptions: { input: serviceConfig.entry },
|
|
2763
|
+
minify: ctx.nitro.options.minify,
|
|
2764
|
+
outDir: join$1(ctx.nitro.options.buildDir, "vite", "services", name),
|
|
2765
|
+
emptyOutDir: true
|
|
2766
|
+
},
|
|
2767
|
+
resolve: {
|
|
2768
|
+
conditions: ctx.nitro.options.exportConditions,
|
|
2769
|
+
externalConditions: ctx.nitro.options.exportConditions
|
|
2770
|
+
},
|
|
2771
|
+
dev: {
|
|
2772
|
+
createEnvironment: (envName, envConfig) => createFetchableDevEnvironment(
|
|
2773
|
+
envName,
|
|
2774
|
+
envConfig,
|
|
2775
|
+
ctx.devWorker,
|
|
2776
|
+
tryResolve(serviceConfig.entry)
|
|
2777
|
+
)
|
|
2778
|
+
}
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
function createServiceEnvironments(ctx) {
|
|
2782
|
+
return Object.fromEntries(
|
|
2783
|
+
Object.entries(ctx.pluginConfig.services || {}).map(([name, config]) => [
|
|
2784
|
+
name,
|
|
2785
|
+
createServiceEnvironment(ctx, name, config)
|
|
2786
|
+
])
|
|
2787
|
+
);
|
|
2788
|
+
}
|
|
2789
|
+
function tryResolve(id) {
|
|
2790
|
+
if (/^[~#/\0]/.test(id) || isAbsolute(id)) {
|
|
2791
|
+
return id;
|
|
2792
|
+
}
|
|
2793
|
+
const resolved = resolveModulePath(id, {
|
|
2794
|
+
suffixes: ["", "/index"],
|
|
2795
|
+
extensions: ["", ".ts", ".mjs", ".cjs", ".js", ".mts", ".cts"],
|
|
2796
|
+
try: true
|
|
2797
|
+
});
|
|
2798
|
+
return resolved || id;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
function nitroPreviewPlugin(ctx) {
|
|
2802
|
+
return {
|
|
2803
|
+
name: "nitro:preview",
|
|
2804
|
+
apply: (_config, configEnv) => !!configEnv.isPreview,
|
|
2805
|
+
config(config) {
|
|
2806
|
+
return {
|
|
2807
|
+
preview: {
|
|
2808
|
+
port: config.preview?.port || 3e3
|
|
2809
|
+
}
|
|
2810
|
+
};
|
|
2811
|
+
},
|
|
2812
|
+
async configurePreviewServer(server) {
|
|
2813
|
+
const buildInfoPath = resolve(
|
|
2814
|
+
server.config.root,
|
|
2815
|
+
"node_modules/.nitro/last-build",
|
|
2816
|
+
"nitro.json"
|
|
2817
|
+
);
|
|
2818
|
+
if (!existsSync(buildInfoPath)) {
|
|
2819
|
+
console.warn(
|
|
2820
|
+
`[nitro] No build found. Please build your project before previewing.`
|
|
2821
|
+
);
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
const realBuildDir = await readlink("node_modules/.nitro/last-build");
|
|
2825
|
+
const buildInfo = JSON.parse(
|
|
2826
|
+
await readFile(buildInfoPath, "utf8")
|
|
2827
|
+
);
|
|
2828
|
+
const info = [
|
|
2829
|
+
["Build Directory:", prettyPath(realBuildDir)],
|
|
2830
|
+
["Date:", buildInfo.date && new Date(buildInfo.date).toLocaleString()],
|
|
2831
|
+
["Nitro Version:", buildInfo.versions.nitro],
|
|
2832
|
+
["Nitro Preset:", buildInfo.preset],
|
|
2833
|
+
buildInfo.framework?.name !== "nitro" && [
|
|
2834
|
+
"Framework:",
|
|
2835
|
+
buildInfo.framework?.name + (buildInfo.framework?.version ? ` (v${buildInfo.framework.version})` : "")
|
|
2836
|
+
]
|
|
2837
|
+
].filter((i) => i && i[1]);
|
|
2838
|
+
consola.box({
|
|
2839
|
+
title: " [Build Info] ",
|
|
2840
|
+
message: info.map((i) => `- ${i[0]} ${i[1]}`).join("\n")
|
|
2841
|
+
});
|
|
2842
|
+
if (!buildInfo.commands?.preview) {
|
|
2843
|
+
consola.warn("[nitro] No preview command found for this preset..");
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
const randomPort = await getRandomPort();
|
|
2847
|
+
consola.info(`Spawning preview server...`);
|
|
2848
|
+
const [command, ...args] = buildInfo.commands.preview.split(" ");
|
|
2849
|
+
let child;
|
|
2850
|
+
consola.info(buildInfo.commands?.preview);
|
|
2851
|
+
child = spawn(command, args, {
|
|
2852
|
+
stdio: "inherit",
|
|
2853
|
+
cwd: realBuildDir,
|
|
2854
|
+
env: {
|
|
2855
|
+
...process.env,
|
|
2856
|
+
PORT: String(randomPort)
|
|
2857
|
+
}
|
|
2858
|
+
});
|
|
2859
|
+
process.on("exit", () => {
|
|
2860
|
+
child?.kill();
|
|
2861
|
+
child = void 0;
|
|
2862
|
+
});
|
|
2863
|
+
child.on("exit", (code) => {
|
|
2864
|
+
if (code && code !== 0) {
|
|
2865
|
+
consola.error(`[nitro] Preview server exited with code ${code}`);
|
|
2866
|
+
}
|
|
2867
|
+
});
|
|
2868
|
+
const proxy = createProxyServer({
|
|
2869
|
+
target: `http://localhost:${randomPort}`
|
|
2870
|
+
});
|
|
2871
|
+
server.middlewares.use((req, res, next) => {
|
|
2872
|
+
if (child && !child.killed) {
|
|
2873
|
+
proxy.web(req, res).catch(next);
|
|
2874
|
+
} else {
|
|
2875
|
+
res.end(`Nitro preview server is not running.`);
|
|
2876
|
+
}
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
const DEFAULT_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"];
|
|
2883
|
+
const debug = process.env.NITRO_DEBUG ? (...args) => console.log("[nitro]", ...args) : () => {
|
|
2884
|
+
};
|
|
2885
|
+
function nitro(pluginConfig = {}) {
|
|
2886
|
+
const ctx = createContext(pluginConfig);
|
|
2887
|
+
return [
|
|
2888
|
+
nitroInit(ctx),
|
|
2889
|
+
nitroEnv(ctx),
|
|
2890
|
+
nitroMain(ctx),
|
|
2891
|
+
nitroPrepare(ctx),
|
|
2892
|
+
nitroService(ctx),
|
|
2893
|
+
nitroPreviewPlugin(),
|
|
2894
|
+
pluginConfig.experimental?.assetsImport !== false && assetsPlugin({
|
|
2895
|
+
experimental: {
|
|
2896
|
+
// See https://github.com/hi-ogawa/vite-plugins/pull/1289
|
|
2897
|
+
clientBuildFallback: false
|
|
2898
|
+
}
|
|
2899
|
+
})
|
|
2900
|
+
];
|
|
2901
|
+
}
|
|
2902
|
+
function nitroInit(ctx) {
|
|
2903
|
+
return {
|
|
2904
|
+
name: "nitro:init",
|
|
2905
|
+
sharedDuringBuild: true,
|
|
2906
|
+
apply: (_config, configEnv) => !configEnv.isPreview,
|
|
2907
|
+
async config(config, configEnv) {
|
|
2908
|
+
if (!ctx._initialized) {
|
|
2909
|
+
debug("[init] Initializing nitro");
|
|
2910
|
+
ctx._initialized = true;
|
|
2911
|
+
await setupNitroContext(ctx, configEnv, config);
|
|
2912
|
+
}
|
|
2913
|
+
},
|
|
2914
|
+
applyToEnvironment(env) {
|
|
2915
|
+
if (env.name === "nitro" && ctx.nitro?.options.dev) {
|
|
2916
|
+
debug("[init] Adding rollup plugins for dev");
|
|
2917
|
+
return [...ctx.rollupConfig?.config.plugins || []];
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
function nitroEnv(ctx) {
|
|
2923
|
+
return {
|
|
2924
|
+
name: "nitro:env",
|
|
2925
|
+
sharedDuringBuild: true,
|
|
2926
|
+
apply: (_config, configEnv) => !configEnv.isPreview,
|
|
2927
|
+
async config(userConfig, _configEnv) {
|
|
2928
|
+
debug("[env] Extending config (environments)");
|
|
2929
|
+
const environments = {
|
|
2930
|
+
...createServiceEnvironments(ctx),
|
|
2931
|
+
nitro: createNitroEnvironment(ctx)
|
|
2932
|
+
};
|
|
2933
|
+
environments.client = {
|
|
2934
|
+
consumer: userConfig.environments?.client?.consumer ?? "client",
|
|
2935
|
+
build: {
|
|
2936
|
+
rollupOptions: {
|
|
2937
|
+
input: userConfig.environments?.client?.build?.rollupOptions?.input ?? useNitro(ctx).options.renderer?.template
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
debug("[env] Environments:", Object.keys(environments).join(", "));
|
|
2942
|
+
return {
|
|
2943
|
+
environments
|
|
2944
|
+
};
|
|
2945
|
+
},
|
|
2946
|
+
configEnvironment(name, config) {
|
|
2947
|
+
if (config.consumer === "client") {
|
|
2948
|
+
debug(
|
|
2949
|
+
"[env] Configuring client environment",
|
|
2950
|
+
name === "client" ? "" : ` (${name})`
|
|
2951
|
+
);
|
|
2952
|
+
config.build.emptyOutDir = false;
|
|
2953
|
+
config.build.outDir = useNitro(ctx).options.output.publicDir;
|
|
2954
|
+
} else {
|
|
2955
|
+
if (ctx.pluginConfig.experimental?.virtualBundle && name in (ctx.pluginConfig.services || {})) {
|
|
2956
|
+
debug("[env] Configuring service environment for virtual:", name);
|
|
2957
|
+
config.build ??= {};
|
|
2958
|
+
config.build.write = config.build.write ?? false;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
};
|
|
2963
|
+
}
|
|
2964
|
+
function nitroMain(ctx) {
|
|
2965
|
+
return {
|
|
2966
|
+
name: "nitro:main",
|
|
2967
|
+
sharedDuringBuild: true,
|
|
2968
|
+
apply: (_config, configEnv) => !configEnv.isPreview,
|
|
2969
|
+
async config(userConfig, _configEnv) {
|
|
2970
|
+
debug("[main] Extending config (appType, resolve, server)");
|
|
2971
|
+
if (!ctx.rollupConfig) {
|
|
2972
|
+
throw new Error("Nitro rollup config is not initialized yet.");
|
|
2973
|
+
}
|
|
2974
|
+
return {
|
|
2975
|
+
appType: userConfig.appType || "custom",
|
|
2976
|
+
resolve: {
|
|
2977
|
+
// TODO: environment specific aliases not working
|
|
2978
|
+
// https://github.com/vitejs/vite/pull/17583 (seems not effective)
|
|
2979
|
+
alias: ctx.rollupConfig.base.aliases
|
|
2980
|
+
},
|
|
2981
|
+
builder: {
|
|
2982
|
+
sharedConfigBuild: true
|
|
2983
|
+
},
|
|
2984
|
+
server: {
|
|
2985
|
+
port: Number.parseInt(process.env.PORT || "") || userConfig.server?.port || useNitro(ctx).options.devServer?.port || 3e3
|
|
2986
|
+
}
|
|
2987
|
+
};
|
|
2988
|
+
},
|
|
2989
|
+
configResolved(config) {
|
|
2990
|
+
if (config.command === "build") {
|
|
2991
|
+
debug("[main] Inferring caching routes");
|
|
2992
|
+
for (const env of Object.values(config.environments)) {
|
|
2993
|
+
if (env.consumer === "client") {
|
|
2994
|
+
const rule = ctx.nitro.options.routeRules[`/${env.build.assetsDir}/**`] ??= {};
|
|
2995
|
+
if (!rule.headers?.["cache-control"]) {
|
|
2996
|
+
rule.headers = {
|
|
2997
|
+
...rule.headers,
|
|
2998
|
+
"cache-control": `public, max-age=31536000, immutable`
|
|
2999
|
+
};
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
debug("[main] Syncing nitro routes");
|
|
3005
|
+
ctx.nitro.routing.sync();
|
|
3006
|
+
},
|
|
3007
|
+
buildApp: {
|
|
3008
|
+
order: "post",
|
|
3009
|
+
handler(builder) {
|
|
3010
|
+
debug("[main] Building environments");
|
|
3011
|
+
return buildEnvironments(ctx, builder);
|
|
3012
|
+
}
|
|
3013
|
+
},
|
|
3014
|
+
generateBundle: {
|
|
3015
|
+
handler(_options, bundle) {
|
|
3016
|
+
const environment = this.environment;
|
|
3017
|
+
debug(
|
|
3018
|
+
"[main] Generating manifest and entry points for environment:",
|
|
3019
|
+
environment.name
|
|
3020
|
+
);
|
|
3021
|
+
const { root } = environment.config;
|
|
3022
|
+
const services = ctx.pluginConfig.services || {};
|
|
3023
|
+
const serviceNames = Object.keys(services);
|
|
3024
|
+
const isRegisteredService = serviceNames.includes(environment.name);
|
|
3025
|
+
let entryFile;
|
|
3026
|
+
for (const [_name, file] of Object.entries(bundle)) {
|
|
3027
|
+
if (file.type === "chunk") {
|
|
3028
|
+
if (isRegisteredService && file.isEntry) {
|
|
3029
|
+
if (entryFile === void 0) {
|
|
3030
|
+
entryFile = file.fileName;
|
|
3031
|
+
} else {
|
|
3032
|
+
this.warn(
|
|
3033
|
+
`Multiple entry points found for service "${environment.name}"`
|
|
3034
|
+
);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
const filteredModuleIds = file.moduleIds.filter(
|
|
3038
|
+
(id) => id.startsWith(root)
|
|
3039
|
+
);
|
|
3040
|
+
for (const id of filteredModuleIds) {
|
|
3041
|
+
const originalFile = relative(root, id);
|
|
3042
|
+
ctx._manifest[originalFile] = { file: file.fileName };
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
if (isRegisteredService) {
|
|
3047
|
+
if (entryFile === void 0) {
|
|
3048
|
+
this.error(
|
|
3049
|
+
`No entry point found for service "${this.environment.name}".`
|
|
3050
|
+
);
|
|
3051
|
+
}
|
|
3052
|
+
ctx._entryPoints[this.environment.name] = entryFile;
|
|
3053
|
+
ctx._serviceBundles[this.environment.name] = bundle;
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
},
|
|
3057
|
+
configureServer: (server) => {
|
|
3058
|
+
debug("[main] Configuring dev server");
|
|
3059
|
+
return configureViteDevServer(ctx, server);
|
|
3060
|
+
}
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3063
|
+
function nitroPrepare(ctx) {
|
|
3064
|
+
return {
|
|
3065
|
+
name: "nitro:prepare",
|
|
3066
|
+
sharedDuringBuild: true,
|
|
3067
|
+
applyToEnvironment: (env) => env.name === "nitro",
|
|
3068
|
+
buildApp: {
|
|
3069
|
+
// Clean the output directory before any environment is built
|
|
3070
|
+
order: "pre",
|
|
3071
|
+
async handler() {
|
|
3072
|
+
debug("[prepare] Preparing output directory");
|
|
3073
|
+
const nitro2 = ctx.nitro;
|
|
3074
|
+
await prepare(nitro2);
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
function nitroService(ctx) {
|
|
3080
|
+
return {
|
|
3081
|
+
name: "nitro:service",
|
|
3082
|
+
enforce: "pre",
|
|
3083
|
+
sharedDuringBuild: true,
|
|
3084
|
+
applyToEnvironment: (env) => env.name === "nitro",
|
|
3085
|
+
resolveId: {
|
|
3086
|
+
async handler(id, importer, options) {
|
|
3087
|
+
if (id === "#nitro-vite-setup") {
|
|
3088
|
+
return { id, moduleSideEffects: true };
|
|
3089
|
+
}
|
|
3090
|
+
if (id === "#nitro-vite-services") {
|
|
3091
|
+
return id;
|
|
3092
|
+
}
|
|
3093
|
+
if (runtimeDependencies.some(
|
|
3094
|
+
(dep) => id === dep || id.startsWith(`${dep}/`)
|
|
3095
|
+
)) {
|
|
3096
|
+
const resolved = await this.resolve(id, importer, {
|
|
3097
|
+
...options,
|
|
3098
|
+
skipSelf: true
|
|
3099
|
+
});
|
|
3100
|
+
return resolved || resolveModulePath(id, {
|
|
3101
|
+
from: ctx.nitro.options.nodeModulesDirs,
|
|
3102
|
+
conditions: ctx.nitro.options.exportConditions,
|
|
3103
|
+
try: true
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
if (importer?.startsWith("\0virtual:#nitro-internal-virtual")) {
|
|
3107
|
+
const internalRes = await this.resolve(id, import.meta.url, {
|
|
3108
|
+
...options,
|
|
3109
|
+
custom: { ...options.custom, skipNoExternals: true }
|
|
3110
|
+
});
|
|
3111
|
+
if (internalRes) {
|
|
3112
|
+
return internalRes;
|
|
3113
|
+
}
|
|
3114
|
+
const resolvedFromRoot = await this.resolve(
|
|
3115
|
+
id,
|
|
3116
|
+
ctx.nitro.options.rootDir,
|
|
3117
|
+
{ ...options, custom: { ...options.custom, skipNoExternals: true } }
|
|
3118
|
+
);
|
|
3119
|
+
if (resolvedFromRoot) {
|
|
3120
|
+
return resolvedFromRoot;
|
|
3121
|
+
}
|
|
3122
|
+
const ids = [id];
|
|
3123
|
+
if (!/^[./@#]/.test(id)) {
|
|
3124
|
+
ids.push(`./${id}`);
|
|
3125
|
+
}
|
|
3126
|
+
for (const _id of ids) {
|
|
3127
|
+
const resolved = resolveModulePath(_id, {
|
|
3128
|
+
from: process.cwd(),
|
|
3129
|
+
extensions: DEFAULT_EXTENSIONS,
|
|
3130
|
+
suffixes: ["", "/index"],
|
|
3131
|
+
try: true
|
|
3132
|
+
});
|
|
3133
|
+
if (resolved) {
|
|
3134
|
+
return resolved;
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
},
|
|
3140
|
+
load: {
|
|
3141
|
+
async handler(id) {
|
|
3142
|
+
if (id === "#nitro-vite-setup") {
|
|
3143
|
+
return prodSetup(ctx);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
};
|
|
3148
|
+
}
|
|
3149
|
+
function createContext(pluginConfig) {
|
|
3150
|
+
return {
|
|
3151
|
+
pluginConfig,
|
|
3152
|
+
_entryPoints: {},
|
|
3153
|
+
_manifest: {},
|
|
3154
|
+
_serviceBundles: {}
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
function useNitro(ctx) {
|
|
3158
|
+
if (!ctx.nitro) {
|
|
3159
|
+
throw new Error("Nitro instance is not initialized yet.");
|
|
3160
|
+
}
|
|
3161
|
+
return ctx.nitro;
|
|
3162
|
+
}
|
|
3163
|
+
async function setupNitroContext(ctx, configEnv, userConfig) {
|
|
3164
|
+
ctx.nitro = ctx.pluginConfig._nitro || await createNitro({
|
|
3165
|
+
dev: configEnv.mode === "development",
|
|
3166
|
+
rootDir: userConfig.root,
|
|
3167
|
+
...defu(ctx.pluginConfig.config, userConfig.nitro)
|
|
3168
|
+
});
|
|
3169
|
+
if (!ctx.pluginConfig.services?.ssr) {
|
|
3170
|
+
ctx.pluginConfig.services ??= {};
|
|
3171
|
+
if (userConfig.environments?.ssr === void 0) {
|
|
3172
|
+
const ssrEntry = resolveModulePath("./entry-server", {
|
|
3173
|
+
from: ["", "app", "src"].flatMap(
|
|
3174
|
+
(d) => ctx.nitro.options.scanDirs.map((s) => join(s, d) + "/")
|
|
3175
|
+
),
|
|
3176
|
+
extensions: DEFAULT_EXTENSIONS,
|
|
3177
|
+
try: true
|
|
3178
|
+
});
|
|
3179
|
+
if (ssrEntry) {
|
|
3180
|
+
ctx.pluginConfig.services.ssr = { entry: ssrEntry };
|
|
3181
|
+
ctx.nitro.logger.info(
|
|
3182
|
+
`Using \`${prettyPath(ssrEntry)}\` as vite ssr entry.`
|
|
3183
|
+
);
|
|
3184
|
+
}
|
|
3185
|
+
} else {
|
|
3186
|
+
let ssrEntry = getEntry(
|
|
3187
|
+
userConfig.environments.ssr.build?.rollupOptions?.input
|
|
3188
|
+
);
|
|
3189
|
+
if (typeof ssrEntry === "string") {
|
|
3190
|
+
ssrEntry = resolveModulePath(ssrEntry, {
|
|
3191
|
+
from: ctx.nitro.options.scanDirs,
|
|
3192
|
+
extensions: DEFAULT_EXTENSIONS,
|
|
3193
|
+
suffixes: ["", "/index"],
|
|
3194
|
+
try: true
|
|
3195
|
+
}) || ssrEntry;
|
|
3196
|
+
ctx.pluginConfig.services.ssr = { entry: ssrEntry };
|
|
3197
|
+
} else {
|
|
3198
|
+
throw new TypeError(`Invalid input type for SSR entry point.`);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
if (!ctx.nitro.options.renderer?.entry && !ctx.nitro.options.renderer?.template && ctx.pluginConfig.services.ssr?.entry) {
|
|
3203
|
+
ctx.nitro.options.renderer ??= {};
|
|
3204
|
+
ctx.nitro.options.renderer.entry = resolve(
|
|
3205
|
+
runtimeDir,
|
|
3206
|
+
"internal/vite/ssr-renderer"
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
const publicDistDir = ctx._publicDistDir = userConfig.build?.outDir || resolve(ctx.nitro.options.buildDir, "vite/public");
|
|
3210
|
+
ctx.nitro.options.publicAssets.push({
|
|
3211
|
+
dir: publicDistDir,
|
|
3212
|
+
maxAge: 0,
|
|
3213
|
+
baseURL: "/",
|
|
3214
|
+
fallthrough: true
|
|
3215
|
+
});
|
|
3216
|
+
if (!ctx.nitro.options.dev) {
|
|
3217
|
+
ctx.nitro.options.unenv.push({
|
|
3218
|
+
meta: { name: "nitro-vite" },
|
|
3219
|
+
polyfill: ["#nitro-vite-setup"]
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
await ctx.nitro.hooks.callHook("build:before", ctx.nitro);
|
|
3223
|
+
ctx.rollupConfig = await getViteRollupConfig(ctx);
|
|
3224
|
+
await ctx.nitro.hooks.callHook(
|
|
3225
|
+
"rollup:before",
|
|
3226
|
+
ctx.nitro,
|
|
3227
|
+
ctx.rollupConfig.config
|
|
3228
|
+
);
|
|
3229
|
+
if (ctx.nitro.options.dev && !ctx.devWorker) {
|
|
3230
|
+
ctx.devWorker = createDevWorker(ctx);
|
|
3231
|
+
}
|
|
3232
|
+
if (ctx.nitro.options.dev && !ctx.devApp) {
|
|
3233
|
+
ctx.devApp = new NitroDevApp(ctx.nitro);
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
function getEntry(input) {
|
|
3237
|
+
if (typeof input === "string") {
|
|
3238
|
+
return input;
|
|
3239
|
+
} else if (Array.isArray(input) && input.length > 0) {
|
|
3240
|
+
return input[0];
|
|
3241
|
+
} else if (input && "index" in input) {
|
|
3242
|
+
return input.index;
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
async function viteBuild(nitro$1) {
|
|
3247
|
+
if (nitro$1.options.dev) {
|
|
3248
|
+
throw new Error(
|
|
3249
|
+
"Nitro vite builder is not supported in development mode. Please use `vite dev` instead."
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
const { createBuilder } = await import('vite');
|
|
3253
|
+
const builder = await createBuilder({
|
|
3254
|
+
base: nitro$1.options.rootDir,
|
|
3255
|
+
plugins: [await nitro({ _nitro: nitro$1 })],
|
|
3256
|
+
logLevel: isTest ? "warn" : void 0
|
|
3257
|
+
});
|
|
3258
|
+
await builder.buildApp();
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
const build = {
|
|
3262
|
+
__proto__: null,
|
|
3263
|
+
viteBuild: viteBuild
|
|
3264
|
+
};
|
|
3265
|
+
|
|
3266
|
+
export { NitroDevServer as N, createDevServer as a, listTasks as b, createNitro as c, build as d, loadOptions as l, nitro as n, prerender as p, runTask as r };
|