@depup/nuxt__kit 4.4.2-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/changes.json +10 -0
- package/dist/index.d.mts +584 -0
- package/dist/index.mjs +1981 -0
- package/package.json +84 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1981 @@
|
|
|
1
|
+
import { performance } from "node:perf_hooks";
|
|
2
|
+
import { createDefu, defu } from "defu";
|
|
3
|
+
import { applyDefaults } from "untyped";
|
|
4
|
+
import { consola } from "consola";
|
|
5
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
|
+
import { getContext } from "unctx";
|
|
7
|
+
import satisfies from "semver/functions/satisfies.js";
|
|
8
|
+
import { readPackageJSON, resolvePackageJSON } from "pkg-types";
|
|
9
|
+
import { existsSync, lstatSync, promises, readFileSync } from "node:fs";
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
|
+
import { basename, dirname, isAbsolute, join, normalize, parse, relative, resolve } from "pathe";
|
|
12
|
+
import { createJiti } from "jiti";
|
|
13
|
+
import { interopDefault, lookupNodeModuleSubpath, parseNodeModulePath, resolveModuleExportNames } from "mlly";
|
|
14
|
+
import { resolveModulePath, resolveModuleURL } from "exsolve";
|
|
15
|
+
import { isRelative, withTrailingSlash, withoutTrailingSlash } from "ufo";
|
|
16
|
+
import { read, update } from "rc9";
|
|
17
|
+
import semver, { gte } from "semver";
|
|
18
|
+
import { captureStackTrace } from "errx";
|
|
19
|
+
import process from "node:process";
|
|
20
|
+
import { glob } from "tinyglobby";
|
|
21
|
+
import { resolveAlias as resolveAlias$1, reverseResolveAlias } from "pathe/utils";
|
|
22
|
+
import ignore from "ignore";
|
|
23
|
+
import { loadConfig } from "c12";
|
|
24
|
+
import destr from "destr";
|
|
25
|
+
import { kebabCase, pascalCase, snakeCase } from "scule";
|
|
26
|
+
import { klona } from "klona";
|
|
27
|
+
import { hash } from "ohash";
|
|
28
|
+
import { isAbsolute as isAbsolute$1 } from "node:path";
|
|
29
|
+
//#region src/logger.ts
|
|
30
|
+
const logger = consola;
|
|
31
|
+
function useLogger(tag, options = {}) {
|
|
32
|
+
return tag ? logger.create(options).withTag(tag) : logger;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/context.ts
|
|
36
|
+
/**
|
|
37
|
+
* Direct access to the Nuxt global context - see https://github.com/unjs/unctx.
|
|
38
|
+
* @deprecated Use `getNuxtCtx` instead
|
|
39
|
+
*/
|
|
40
|
+
const nuxtCtx = getContext("nuxt");
|
|
41
|
+
/** async local storage for the name of the current nuxt instance */
|
|
42
|
+
const asyncNuxtStorage = getContext("asyncNuxtStorage", {
|
|
43
|
+
asyncContext: true,
|
|
44
|
+
AsyncLocalStorage
|
|
45
|
+
});
|
|
46
|
+
/** Direct access to the Nuxt context with asyncLocalStorage - see https://github.com/unjs/unctx. */
|
|
47
|
+
const getNuxtCtx = () => asyncNuxtStorage.tryUse();
|
|
48
|
+
/**
|
|
49
|
+
* Get access to Nuxt instance.
|
|
50
|
+
*
|
|
51
|
+
* Throws an error if Nuxt instance is unavailable.
|
|
52
|
+
* @example
|
|
53
|
+
* ```js
|
|
54
|
+
* const nuxt = useNuxt()
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function useNuxt() {
|
|
58
|
+
const instance = asyncNuxtStorage.tryUse() || nuxtCtx.tryUse();
|
|
59
|
+
if (!instance) throw new Error("Nuxt instance is unavailable!");
|
|
60
|
+
return instance;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get access to Nuxt instance.
|
|
64
|
+
*
|
|
65
|
+
* Returns null if Nuxt instance is unavailable.
|
|
66
|
+
* @example
|
|
67
|
+
* ```js
|
|
68
|
+
* const nuxt = tryUseNuxt()
|
|
69
|
+
* if (nuxt) {
|
|
70
|
+
* // Do something
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function tryUseNuxt() {
|
|
75
|
+
return asyncNuxtStorage.tryUse() || nuxtCtx.tryUse();
|
|
76
|
+
}
|
|
77
|
+
function runWithNuxtContext(nuxt, fn) {
|
|
78
|
+
return asyncNuxtStorage.call(nuxt, fn);
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/compatibility.ts
|
|
82
|
+
const SEMANTIC_VERSION_RE = /-\d+\.[0-9a-f]+/;
|
|
83
|
+
function normalizeSemanticVersion(version) {
|
|
84
|
+
return version.replace(SEMANTIC_VERSION_RE, "");
|
|
85
|
+
}
|
|
86
|
+
const builderMap = {
|
|
87
|
+
"@nuxt/rspack-builder": "rspack",
|
|
88
|
+
"@nuxt/vite-builder": "vite",
|
|
89
|
+
"@nuxt/webpack-builder": "webpack"
|
|
90
|
+
};
|
|
91
|
+
function checkNuxtVersion(version, nuxt = useNuxt()) {
|
|
92
|
+
return satisfies(normalizeSemanticVersion(getNuxtVersion(nuxt)), version, { includePrerelease: true });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check version constraints and return incompatibility issues as an array
|
|
96
|
+
*/
|
|
97
|
+
async function checkNuxtCompatibility(constraints, nuxt = useNuxt()) {
|
|
98
|
+
const issues = [];
|
|
99
|
+
if (constraints.nuxt) {
|
|
100
|
+
const nuxtVersion = getNuxtVersion(nuxt);
|
|
101
|
+
if (!checkNuxtVersion(constraints.nuxt, nuxt)) issues.push({
|
|
102
|
+
name: "nuxt",
|
|
103
|
+
message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\``
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (constraints.builder && typeof nuxt.options.builder === "string") {
|
|
107
|
+
const currentBuilder = builderMap[nuxt.options.builder] || nuxt.options.builder;
|
|
108
|
+
if (currentBuilder in constraints.builder) {
|
|
109
|
+
const constraint = constraints.builder[currentBuilder];
|
|
110
|
+
if (constraint === false) issues.push({
|
|
111
|
+
name: "builder",
|
|
112
|
+
message: `Not compatible with \`${nuxt.options.builder}\`.`
|
|
113
|
+
});
|
|
114
|
+
else for (const parent of [
|
|
115
|
+
nuxt.options.rootDir,
|
|
116
|
+
nuxt.options.workspaceDir,
|
|
117
|
+
import.meta.url
|
|
118
|
+
]) {
|
|
119
|
+
const builderVersion = await readPackageJSON(nuxt.options.builder, { parent }).then((r) => r.version).catch(() => void 0);
|
|
120
|
+
if (builderVersion) {
|
|
121
|
+
if (!satisfies(normalizeSemanticVersion(builderVersion), constraint, { includePrerelease: true })) issues.push({
|
|
122
|
+
name: "builder",
|
|
123
|
+
message: `Not compatible with \`${builderVersion}\` of \`${currentBuilder}\`. This module requires \`${constraint}\`.`
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await nuxt.callHook("kit:compatibility", constraints, issues);
|
|
131
|
+
issues.toString = () => issues.map((issue) => ` - [${issue.name}] ${issue.message}`).join("\n");
|
|
132
|
+
return issues;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check version constraints and throw a detailed error if has any, otherwise returns true
|
|
136
|
+
*/
|
|
137
|
+
async function assertNuxtCompatibility(constraints, nuxt = useNuxt()) {
|
|
138
|
+
const issues = await checkNuxtCompatibility(constraints, nuxt);
|
|
139
|
+
if (issues.length) throw new Error("Nuxt compatibility issues found:\n" + issues.toString());
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Check version constraints and return true if passed, otherwise returns false
|
|
144
|
+
*/
|
|
145
|
+
async function hasNuxtCompatibility(constraints, nuxt = useNuxt()) {
|
|
146
|
+
return !(await checkNuxtCompatibility(constraints, nuxt)).length;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if current Nuxt instance is of specified major version
|
|
150
|
+
*/
|
|
151
|
+
function isNuxtMajorVersion(majorVersion, nuxt = useNuxt()) {
|
|
152
|
+
const version = getNuxtVersion(nuxt);
|
|
153
|
+
return version[0] === majorVersion.toString() && version[1] === ".";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @deprecated Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
|
157
|
+
*/
|
|
158
|
+
function isNuxt2(nuxt = useNuxt()) {
|
|
159
|
+
return isNuxtMajorVersion(2, nuxt);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* @deprecated Use `isNuxtMajorVersion(3, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
|
163
|
+
*/
|
|
164
|
+
function isNuxt3(nuxt = useNuxt()) {
|
|
165
|
+
return isNuxtMajorVersion(3, nuxt);
|
|
166
|
+
}
|
|
167
|
+
const NUXT_VERSION_RE = /^v/g;
|
|
168
|
+
/**
|
|
169
|
+
* Get nuxt version
|
|
170
|
+
*/
|
|
171
|
+
function getNuxtVersion(nuxt = useNuxt()) {
|
|
172
|
+
const rawVersion = nuxt?._version || nuxt?.version || nuxt?.constructor?.version;
|
|
173
|
+
if (typeof rawVersion !== "string") throw new TypeError("Cannot determine nuxt version! Is current instance passed?");
|
|
174
|
+
return rawVersion.replace(NUXT_VERSION_RE, "");
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/module/define.ts
|
|
178
|
+
function defineNuxtModule(definition) {
|
|
179
|
+
if (definition) return _defineNuxtModule(definition);
|
|
180
|
+
return { with: (definition) => _defineNuxtModule(definition) };
|
|
181
|
+
}
|
|
182
|
+
function _defineNuxtModule(definition) {
|
|
183
|
+
if (typeof definition === "function") return _defineNuxtModule({ setup: definition });
|
|
184
|
+
const module = defu(definition, { meta: {} });
|
|
185
|
+
module.meta.configKey ||= module.meta.name;
|
|
186
|
+
async function getOptions(inlineOptions, nuxt = useNuxt()) {
|
|
187
|
+
const nuxtConfigOptionsKey = module.meta.configKey || module.meta.name;
|
|
188
|
+
let options = defu(inlineOptions, nuxtConfigOptionsKey && nuxtConfigOptionsKey in nuxt.options ? nuxt.options[nuxtConfigOptionsKey] : {}, module.defaults instanceof Function ? await module.defaults(nuxt) : module.defaults ?? {});
|
|
189
|
+
if (module.schema) options = await applyDefaults(module.schema, options);
|
|
190
|
+
return Promise.resolve(options);
|
|
191
|
+
}
|
|
192
|
+
function getModuleDependencies(nuxt = useNuxt()) {
|
|
193
|
+
if (typeof module.moduleDependencies === "function") return module.moduleDependencies(nuxt);
|
|
194
|
+
return module.moduleDependencies;
|
|
195
|
+
}
|
|
196
|
+
async function normalizedModule(inlineOptions, nuxt = tryUseNuxt()) {
|
|
197
|
+
if (!nuxt) throw new TypeError(`Cannot use ${module.meta.name || "module"} outside of Nuxt context`);
|
|
198
|
+
const uniqueKey = module.meta.name || module.meta.configKey;
|
|
199
|
+
if (uniqueKey) {
|
|
200
|
+
nuxt.options._requiredModules ||= {};
|
|
201
|
+
if (nuxt.options._requiredModules[uniqueKey]) return false;
|
|
202
|
+
nuxt.options._requiredModules[uniqueKey] = true;
|
|
203
|
+
}
|
|
204
|
+
if (module.meta.compatibility) {
|
|
205
|
+
const issues = await checkNuxtCompatibility(module.meta.compatibility, nuxt);
|
|
206
|
+
if (issues.length) {
|
|
207
|
+
const errorMessage = `Module \`${module.meta.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`;
|
|
208
|
+
if (nuxt.options.experimental.enforceModuleCompatibility) {
|
|
209
|
+
const error = new Error(errorMessage);
|
|
210
|
+
error.name = "ModuleCompatibilityError";
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
logger.warn(errorMessage);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const _options = await getOptions(inlineOptions, nuxt);
|
|
218
|
+
if (module.hooks) nuxt.hooks.addHooks(module.hooks);
|
|
219
|
+
const moduleName = uniqueKey || module.meta.name || "<no name>";
|
|
220
|
+
nuxt._perf?.startPhase(`module:${moduleName}`);
|
|
221
|
+
const start = performance.now();
|
|
222
|
+
let res = {};
|
|
223
|
+
try {
|
|
224
|
+
res = await module.setup?.call(null, _options, nuxt) ?? {};
|
|
225
|
+
} finally {
|
|
226
|
+
nuxt._perf?.endPhase(`module:${moduleName}`);
|
|
227
|
+
}
|
|
228
|
+
const perf = performance.now() - start;
|
|
229
|
+
const setupTime = Math.round(perf * 100) / 100;
|
|
230
|
+
if (setupTime > 5e3 && uniqueKey !== "@nuxt/telemetry") logger.warn(`Slow module \`${moduleName}\` took \`${setupTime}ms\` to setup.`);
|
|
231
|
+
else if (nuxt.options.debug && nuxt.options.debug.modules) logger.info(`Module \`${moduleName}\` took \`${setupTime}ms\` to setup.`);
|
|
232
|
+
if (res === false) return false;
|
|
233
|
+
return defu(res, { timings: { setup: setupTime } });
|
|
234
|
+
}
|
|
235
|
+
normalizedModule.getMeta = () => Promise.resolve(module.meta);
|
|
236
|
+
normalizedModule.getOptions = getOptions;
|
|
237
|
+
normalizedModule.getModuleDependencies = getModuleDependencies;
|
|
238
|
+
normalizedModule.onInstall = module.onInstall;
|
|
239
|
+
normalizedModule.onUpgrade = module.onUpgrade;
|
|
240
|
+
return normalizedModule;
|
|
241
|
+
}
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/internal/trace.ts
|
|
244
|
+
const distURL = import.meta.url.replace(/\/dist\/.*$/, "/");
|
|
245
|
+
function getUserCaller() {
|
|
246
|
+
if (!import.meta.dev) return null;
|
|
247
|
+
const { source, line, column } = captureStackTrace().find((entry) => !entry.source.startsWith(distURL)) ?? {};
|
|
248
|
+
if (!source) return null;
|
|
249
|
+
return {
|
|
250
|
+
source: source.replace(/^file:\/\//, ""),
|
|
251
|
+
line,
|
|
252
|
+
column
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
256
|
+
function warn(warning) {
|
|
257
|
+
if (!warnings.has(warning)) {
|
|
258
|
+
console.warn(warning);
|
|
259
|
+
warnings.add(warning);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/layers.ts
|
|
264
|
+
const layerMap = /* @__PURE__ */ new WeakMap();
|
|
265
|
+
/**
|
|
266
|
+
* Get the resolved directory paths for all layers in a Nuxt application.
|
|
267
|
+
*
|
|
268
|
+
* Returns an array of LayerDirectories objects, ordered by layer priority:
|
|
269
|
+
* - The first layer is the user/project layer (highest priority)
|
|
270
|
+
* - Earlier layers override later layers in the array
|
|
271
|
+
* - Base layers appear last in the array (lowest priority)
|
|
272
|
+
*
|
|
273
|
+
* @param nuxt - The Nuxt instance to get layers from. Defaults to the current Nuxt context.
|
|
274
|
+
* @returns Array of LayerDirectories objects, ordered by priority (user layer first)
|
|
275
|
+
*/
|
|
276
|
+
function getLayerDirectories(nuxt = useNuxt()) {
|
|
277
|
+
return nuxt.options._layers.map((layer) => {
|
|
278
|
+
if (layerMap.has(layer)) return layerMap.get(layer);
|
|
279
|
+
const config = withTrailingSlash$2(layer.config.rootDir) === withTrailingSlash$2(nuxt.options.rootDir) ? nuxt.options : layer.config;
|
|
280
|
+
const src = withTrailingSlash$2(config.srcDir || layer.cwd);
|
|
281
|
+
const root = withTrailingSlash$2(config.rootDir || layer.cwd);
|
|
282
|
+
const directories = {
|
|
283
|
+
root,
|
|
284
|
+
shared: withTrailingSlash$2(resolve(root, resolveAlias(config.dir?.shared || "shared", nuxt.options.alias))),
|
|
285
|
+
server: withTrailingSlash$2(resolve(src, resolveAlias(config.serverDir || "server", nuxt.options.alias))),
|
|
286
|
+
modules: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.modules || "modules", nuxt.options.alias))),
|
|
287
|
+
public: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.public || "public", nuxt.options.alias))),
|
|
288
|
+
app: src,
|
|
289
|
+
appLayouts: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.layouts || "layouts", nuxt.options.alias))),
|
|
290
|
+
appMiddleware: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.middleware || "middleware", nuxt.options.alias))),
|
|
291
|
+
appPages: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.pages || "pages", nuxt.options.alias))),
|
|
292
|
+
appPlugins: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.plugins || "plugins", nuxt.options.alias)))
|
|
293
|
+
};
|
|
294
|
+
layerMap.set(layer, directories);
|
|
295
|
+
return directories;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function withTrailingSlash$2(dir) {
|
|
299
|
+
return dir.replace(/[^/]$/, "$&/");
|
|
300
|
+
}
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region src/ignore.ts
|
|
303
|
+
function createIsIgnored(nuxt = tryUseNuxt()) {
|
|
304
|
+
return (pathname, stats) => isIgnored(pathname, stats, nuxt);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Return a filter function to filter an array of paths
|
|
308
|
+
*/
|
|
309
|
+
function isIgnored(pathname, _stats, nuxt = tryUseNuxt()) {
|
|
310
|
+
if (!nuxt) return false;
|
|
311
|
+
if (!nuxt._ignore) {
|
|
312
|
+
nuxt._ignore = ignore(nuxt.options.ignoreOptions);
|
|
313
|
+
nuxt._ignore.add(resolveIgnorePatterns());
|
|
314
|
+
}
|
|
315
|
+
const relativePath = relative(getLayerDirectories(nuxt).map((dirs) => dirs.root).sort((a, b) => b.length - a.length).find((cwd) => pathname.startsWith(cwd)) ?? nuxt.options.rootDir, pathname);
|
|
316
|
+
if (relativePath[0] === "." && relativePath[1] === ".") return false;
|
|
317
|
+
return !!(relativePath && nuxt._ignore.ignores(relativePath));
|
|
318
|
+
}
|
|
319
|
+
const NEGATION_RE = /^(!?)(.*)$/;
|
|
320
|
+
function resolveIgnorePatterns(relativePath) {
|
|
321
|
+
const nuxt = tryUseNuxt();
|
|
322
|
+
if (!nuxt) return [];
|
|
323
|
+
const ignorePatterns = nuxt.options.ignore.flatMap((s) => resolveGroupSyntax(s));
|
|
324
|
+
const nuxtignoreFile = join(nuxt.options.rootDir, ".nuxtignore");
|
|
325
|
+
if (existsSync(nuxtignoreFile)) {
|
|
326
|
+
const contents = readFileSync(nuxtignoreFile, "utf-8");
|
|
327
|
+
ignorePatterns.push(...contents.trim().split(/\r?\n/));
|
|
328
|
+
}
|
|
329
|
+
if (relativePath) return ignorePatterns.map((p) => {
|
|
330
|
+
const [_, negation = "", pattern] = p.match(NEGATION_RE) || [];
|
|
331
|
+
if (pattern && pattern[0] === "*") return p;
|
|
332
|
+
return negation + relative(relativePath, resolve(nuxt.options.rootDir, pattern || p));
|
|
333
|
+
});
|
|
334
|
+
return ignorePatterns;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* This function turns string containing groups '**\/*.{spec,test}.{js,ts}' into an array of strings.
|
|
338
|
+
* For example will '**\/*.{spec,test}.{js,ts}' be resolved to:
|
|
339
|
+
* ['**\/*.spec.js', '**\/*.spec.ts', '**\/*.test.js', '**\/*.test.ts']
|
|
340
|
+
* @param group string containing the group syntax
|
|
341
|
+
* @returns {string[]} array of strings without the group syntax
|
|
342
|
+
*/
|
|
343
|
+
function resolveGroupSyntax(group) {
|
|
344
|
+
let groups = [group];
|
|
345
|
+
while (groups.some((group) => group.includes("{"))) groups = groups.flatMap((group) => {
|
|
346
|
+
const [head, ...tail] = group.split("{");
|
|
347
|
+
if (tail.length) {
|
|
348
|
+
const [body = "", ...rest] = tail.join("{").split("}");
|
|
349
|
+
return body.split(",").map((part) => `${head}${part}${rest.join("")}`);
|
|
350
|
+
}
|
|
351
|
+
return group;
|
|
352
|
+
});
|
|
353
|
+
return groups;
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/utils.ts
|
|
357
|
+
/** @since 3.9.0 */
|
|
358
|
+
function toArray(value) {
|
|
359
|
+
return Array.isArray(value) ? value : [value];
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Filter out items from an array in place. This function mutates the array.
|
|
363
|
+
* `predicate` get through the array from the end to the start for performance.
|
|
364
|
+
*
|
|
365
|
+
* This function should be faster than `Array.prototype.filter` on large arrays.
|
|
366
|
+
*/
|
|
367
|
+
function filterInPlace(array, predicate) {
|
|
368
|
+
for (let i = array.length; i--;) if (!predicate(array[i], i, array)) array.splice(i, 1);
|
|
369
|
+
return array;
|
|
370
|
+
}
|
|
371
|
+
const MODE_RE = /\.(server|client)(\.\w+)*$/;
|
|
372
|
+
const distDirURL = new URL(".", import.meta.url);
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/resolve.ts
|
|
375
|
+
/**
|
|
376
|
+
* Resolve the full path to a file or a directory (based on the provided type), respecting Nuxt alias and extensions options.
|
|
377
|
+
*
|
|
378
|
+
* If a path cannot be resolved, normalized input will be returned unless the `fallbackToOriginal` option is set to `true`,
|
|
379
|
+
* in which case the original input path will be returned.
|
|
380
|
+
*/
|
|
381
|
+
async function resolvePath(path, opts = {}) {
|
|
382
|
+
const { type = "file" } = opts;
|
|
383
|
+
const res = await _resolvePathGranularly(path, {
|
|
384
|
+
...opts,
|
|
385
|
+
type
|
|
386
|
+
});
|
|
387
|
+
if (res.type === type) return res.path;
|
|
388
|
+
return opts.fallbackToOriginal ? path : res.path;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Try to resolve first existing file in paths
|
|
392
|
+
*/
|
|
393
|
+
async function findPath(paths, opts, pathType = "file") {
|
|
394
|
+
for (const path of toArray(paths)) {
|
|
395
|
+
const res = await _resolvePathGranularly(path, {
|
|
396
|
+
...opts,
|
|
397
|
+
type: opts?.type || pathType
|
|
398
|
+
});
|
|
399
|
+
if (!res.type || pathType && res.type !== pathType) continue;
|
|
400
|
+
if (res.virtual || await existsSensitive(res.path)) return res.path;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Resolve path aliases respecting Nuxt alias options
|
|
406
|
+
*/
|
|
407
|
+
function resolveAlias(path, alias) {
|
|
408
|
+
alias ||= tryUseNuxt()?.options.alias || {};
|
|
409
|
+
return resolveAlias$1(path, alias);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Create a relative resolver
|
|
413
|
+
*/
|
|
414
|
+
function createResolver(base) {
|
|
415
|
+
if (!base) throw new Error("`base` argument is missing for createResolver(base)!");
|
|
416
|
+
base = base.toString();
|
|
417
|
+
if (base.startsWith("file://")) base = dirname(fileURLToPath(base));
|
|
418
|
+
return {
|
|
419
|
+
resolve: (...path) => resolve(base, ...path),
|
|
420
|
+
resolvePath: (path, opts) => resolvePath(path, {
|
|
421
|
+
cwd: base,
|
|
422
|
+
...opts
|
|
423
|
+
})
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
async function resolveNuxtModule(base, paths) {
|
|
427
|
+
const resolved = [];
|
|
428
|
+
const resolver = createResolver(base);
|
|
429
|
+
for (const path of paths) {
|
|
430
|
+
if (path.startsWith(base)) {
|
|
431
|
+
resolved.push(path.split("/index.ts")[0]);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
const resolvedPath = await resolver.resolvePath(path);
|
|
435
|
+
const dir = parseNodeModulePath(resolvedPath).dir;
|
|
436
|
+
if (dir) {
|
|
437
|
+
resolved.push(dir);
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
const index = resolvedPath.lastIndexOf(path);
|
|
441
|
+
resolved.push(index === -1 ? dirname(resolvedPath) : resolvedPath.slice(0, index + path.length));
|
|
442
|
+
}
|
|
443
|
+
return resolved;
|
|
444
|
+
}
|
|
445
|
+
async function _resolvePathType(path, opts = {}, skipFs = false) {
|
|
446
|
+
if (opts?.virtual && existsInVFS(path)) return {
|
|
447
|
+
path,
|
|
448
|
+
type: "file",
|
|
449
|
+
virtual: true
|
|
450
|
+
};
|
|
451
|
+
if (skipFs) return;
|
|
452
|
+
const fd = await promises.open(path, "r").catch(() => null);
|
|
453
|
+
try {
|
|
454
|
+
const stats = await fd?.stat();
|
|
455
|
+
if (stats) return {
|
|
456
|
+
path,
|
|
457
|
+
type: stats.isFile() ? "file" : "dir",
|
|
458
|
+
virtual: false
|
|
459
|
+
};
|
|
460
|
+
} finally {
|
|
461
|
+
fd?.close();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function normalizeExtension(ext) {
|
|
465
|
+
return ext.startsWith(".") ? ext : `.${ext}`;
|
|
466
|
+
}
|
|
467
|
+
async function _resolvePathGranularly(path, opts = { type: "file" }) {
|
|
468
|
+
const _path = path;
|
|
469
|
+
path = normalize(path);
|
|
470
|
+
if (isAbsolute(path)) {
|
|
471
|
+
const res = await _resolvePathType(path, opts);
|
|
472
|
+
if (res && res.type === opts.type) return res;
|
|
473
|
+
}
|
|
474
|
+
const nuxt = tryUseNuxt();
|
|
475
|
+
const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd());
|
|
476
|
+
const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : [
|
|
477
|
+
".ts",
|
|
478
|
+
".mjs",
|
|
479
|
+
".cjs",
|
|
480
|
+
".json"
|
|
481
|
+
]);
|
|
482
|
+
const modulesDir = nuxt ? nuxt.options.modulesDir : [];
|
|
483
|
+
path = resolveAlias$1(path, opts.alias ?? nuxt?.options.alias ?? {});
|
|
484
|
+
if (!isAbsolute(path)) path = resolve(cwd, path);
|
|
485
|
+
const res = await _resolvePathType(path, opts);
|
|
486
|
+
if (res && res.type === opts.type) return res;
|
|
487
|
+
if (opts.type === "file") {
|
|
488
|
+
for (const ext of extensions) {
|
|
489
|
+
const normalizedExt = normalizeExtension(ext);
|
|
490
|
+
const extPath = await _resolvePathType(path + normalizedExt, opts);
|
|
491
|
+
if (extPath && extPath.type === "file") return extPath;
|
|
492
|
+
const indexPath = await _resolvePathType(join(path, "index" + normalizedExt), opts, res?.type !== "dir");
|
|
493
|
+
if (indexPath && indexPath.type === "file") return indexPath;
|
|
494
|
+
}
|
|
495
|
+
const resolvedModulePath = resolveModulePath(_path, {
|
|
496
|
+
try: true,
|
|
497
|
+
suffixes: ["", "index"],
|
|
498
|
+
from: [cwd, ...modulesDir].map((d) => directoryToURL(d))
|
|
499
|
+
});
|
|
500
|
+
if (resolvedModulePath) return {
|
|
501
|
+
path: resolvedModulePath,
|
|
502
|
+
type: "file",
|
|
503
|
+
virtual: false
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
return { path };
|
|
507
|
+
}
|
|
508
|
+
async function existsSensitive(path) {
|
|
509
|
+
return new Set(await promises.readdir(dirname(path)).catch(() => [])).has(basename(path));
|
|
510
|
+
}
|
|
511
|
+
function existsInVFS(path, nuxt = tryUseNuxt()) {
|
|
512
|
+
if (!nuxt) return false;
|
|
513
|
+
if (path in nuxt.vfs) return true;
|
|
514
|
+
return (nuxt.apps.default?.templates ?? nuxt.options.build.templates).some((template) => template.dst === path);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Resolve absolute file paths in the provided directory with respect to `.nuxtignore` and return them sorted.
|
|
518
|
+
* @param path path to the directory to resolve files in
|
|
519
|
+
* @param pattern glob pattern or an array of glob patterns to match files
|
|
520
|
+
* @param opts options for globbing
|
|
521
|
+
* @param opts.followSymbolicLinks whether to follow symbolic links, default is `true`
|
|
522
|
+
* @param opts.ignore additional glob patterns to ignore
|
|
523
|
+
* @returns sorted array of absolute file paths
|
|
524
|
+
*/
|
|
525
|
+
async function resolveFiles(path, pattern, opts = {}) {
|
|
526
|
+
const files = [];
|
|
527
|
+
for (const p of await glob(pattern, {
|
|
528
|
+
cwd: path,
|
|
529
|
+
followSymbolicLinks: opts.followSymbolicLinks ?? true,
|
|
530
|
+
absolute: true,
|
|
531
|
+
ignore: opts.ignore
|
|
532
|
+
})) if (!isIgnored(p)) files.push(p);
|
|
533
|
+
return files.sort();
|
|
534
|
+
}
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region src/internal/esm.ts
|
|
537
|
+
function directoryToURL(dir) {
|
|
538
|
+
return pathToFileURL(dir + "/");
|
|
539
|
+
}
|
|
540
|
+
function tryResolveModule(id, url = import.meta.url) {
|
|
541
|
+
return Promise.resolve(resolveModulePath(id, {
|
|
542
|
+
from: url,
|
|
543
|
+
suffixes: ["", "index"],
|
|
544
|
+
try: true
|
|
545
|
+
}));
|
|
546
|
+
}
|
|
547
|
+
function resolveModule(id, options) {
|
|
548
|
+
return resolveModulePath(id, {
|
|
549
|
+
from: options?.url ?? options?.paths ?? [import.meta.url],
|
|
550
|
+
extensions: options?.extensions ?? [
|
|
551
|
+
".js",
|
|
552
|
+
".mjs",
|
|
553
|
+
".cjs",
|
|
554
|
+
".ts",
|
|
555
|
+
".mts",
|
|
556
|
+
".cts"
|
|
557
|
+
]
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
async function importModule(id, opts) {
|
|
561
|
+
return await import(pathToFileURL(resolveModule(id, opts)).href).then((r) => opts?.interopDefault !== false ? interopDefault(r) : r);
|
|
562
|
+
}
|
|
563
|
+
function tryImportModule(id, opts) {
|
|
564
|
+
try {
|
|
565
|
+
return importModule(id, opts).catch(() => void 0);
|
|
566
|
+
} catch {}
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* @deprecated Please use `importModule` instead.
|
|
570
|
+
*/
|
|
571
|
+
function requireModule(id, opts) {
|
|
572
|
+
const caller = getUserCaller();
|
|
573
|
+
warn(`[@nuxt/kit] \`requireModule\` is deprecated${caller ? ` (used at \`${resolveAlias(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Please use \`importModule\` instead.`);
|
|
574
|
+
const resolvedPath = resolveModule(id, opts);
|
|
575
|
+
return createJiti(import.meta.url, { interopDefault: opts?.interopDefault !== false })(pathToFileURL(resolvedPath).href);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* @deprecated Please use `tryImportModule` instead.
|
|
579
|
+
*/
|
|
580
|
+
function tryRequireModule(id, opts) {
|
|
581
|
+
try {
|
|
582
|
+
return requireModule(id, opts);
|
|
583
|
+
} catch {}
|
|
584
|
+
}
|
|
585
|
+
//#endregion
|
|
586
|
+
//#region src/module/install.ts
|
|
587
|
+
const NODE_MODULES_RE = /[/\\]node_modules[/\\]/;
|
|
588
|
+
const ignoredConfigKeys = new Set([
|
|
589
|
+
"components",
|
|
590
|
+
"imports",
|
|
591
|
+
"pages",
|
|
592
|
+
"devtools",
|
|
593
|
+
"telemetry"
|
|
594
|
+
]);
|
|
595
|
+
/**
|
|
596
|
+
* Installs a set of modules on a Nuxt instance.
|
|
597
|
+
* @internal
|
|
598
|
+
*/
|
|
599
|
+
async function installModules(modulesToInstall, resolvedModulePaths, nuxt = useNuxt()) {
|
|
600
|
+
const localLayerModuleDirs = [];
|
|
601
|
+
for (const l of nuxt.options._layers) {
|
|
602
|
+
const srcDir = l.config.srcDir || l.cwd;
|
|
603
|
+
if (!NODE_MODULES_RE.test(srcDir)) localLayerModuleDirs.push(resolve(srcDir, l.config?.dir?.modules || "modules").replace(/\/?$/, "/"));
|
|
604
|
+
}
|
|
605
|
+
nuxt._moduleOptionsFunctions ||= /* @__PURE__ */ new Map();
|
|
606
|
+
const resolvedModules = [];
|
|
607
|
+
const modulesByMetaName = /* @__PURE__ */ new Map();
|
|
608
|
+
const inlineConfigKeys = new Set(await Promise.all([...modulesToInstall].map(async ([mod]) => {
|
|
609
|
+
if (typeof mod === "string") return;
|
|
610
|
+
const meta = await Promise.resolve(mod.getMeta?.());
|
|
611
|
+
if (meta?.name) modulesByMetaName.set(meta.name, mod);
|
|
612
|
+
if (meta?.configKey) {
|
|
613
|
+
if (meta.configKey !== meta.name) modulesByMetaName.set(meta.configKey, mod);
|
|
614
|
+
return meta.configKey;
|
|
615
|
+
}
|
|
616
|
+
})));
|
|
617
|
+
let error;
|
|
618
|
+
const dependencyMap = /* @__PURE__ */ new Map();
|
|
619
|
+
for (const [key, options] of modulesToInstall) {
|
|
620
|
+
const res = await loadNuxtModuleInstance(key, nuxt).catch((err) => {
|
|
621
|
+
if (dependencyMap.has(key) && typeof key === "string") err.cause = `Could not resolve \`${key}\` (specified as a dependency of ${dependencyMap.get(key)}).`;
|
|
622
|
+
throw err;
|
|
623
|
+
});
|
|
624
|
+
const dependencyMeta = await res.nuxtModule.getModuleDependencies?.(nuxt) || {};
|
|
625
|
+
for (const [name, value] of Object.entries(dependencyMeta)) {
|
|
626
|
+
if (!value.overrides && !value.defaults && !value.version && value.optional) continue;
|
|
627
|
+
const resolvedModule = modulesByMetaName.has(name) ? resolveModuleWithOptions(modulesByMetaName.get(name), nuxt) : resolveModuleWithOptions(name, nuxt);
|
|
628
|
+
const moduleToAttribute = typeof key === "string" ? `\`${key}\`` : "a module in `nuxt.options`";
|
|
629
|
+
if (!resolvedModule?.module) {
|
|
630
|
+
const message = `Could not resolve \`${name}\` (specified as a dependency of ${moduleToAttribute}).`;
|
|
631
|
+
error = new TypeError(message);
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (value.version) {
|
|
635
|
+
const pkg = await readPackageJSON(name, { from: [res.resolvedModulePath, ...nuxt.options.modulesDir].filter(Boolean) }).catch(() => null);
|
|
636
|
+
if (pkg?.version && !semver.satisfies(pkg.version, value.version, { includePrerelease: true })) {
|
|
637
|
+
const message = `Module \`${name}\` version (\`${pkg.version}\`) does not satisfy \`${value.version}\` (requested by ${moduleToAttribute}).`;
|
|
638
|
+
error = new TypeError(message);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (value.overrides || value.defaults) {
|
|
642
|
+
const currentFns = nuxt._moduleOptionsFunctions.get(resolvedModule.module) || [];
|
|
643
|
+
nuxt._moduleOptionsFunctions.set(resolvedModule.module, [...currentFns, () => ({
|
|
644
|
+
defaults: value.defaults,
|
|
645
|
+
overrides: value.overrides
|
|
646
|
+
})]);
|
|
647
|
+
}
|
|
648
|
+
if (value.optional === true) continue;
|
|
649
|
+
nuxt.options.typescript.hoist.push(name);
|
|
650
|
+
if (resolvedModule && !modulesToInstall.has(resolvedModule.module) && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
|
|
651
|
+
if (typeof resolvedModule.module === "string" && inlineConfigKeys.has(resolvedModule.module)) continue;
|
|
652
|
+
modulesToInstall.set(resolvedModule.module, resolvedModule.options);
|
|
653
|
+
dependencyMap.set(resolvedModule.module, moduleToAttribute);
|
|
654
|
+
const path = resolvedModule.resolvedPath || resolvedModule.module;
|
|
655
|
+
if (typeof path === "string") resolvedModulePaths.add(path);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
resolvedModules.push({
|
|
659
|
+
moduleToInstall: key,
|
|
660
|
+
meta: await res.nuxtModule.getMeta?.(),
|
|
661
|
+
nuxtModule: res.nuxtModule,
|
|
662
|
+
buildTimeModuleMeta: res.buildTimeModuleMeta,
|
|
663
|
+
resolvedModulePath: res.resolvedModulePath,
|
|
664
|
+
inlineOptions: options
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
if (error) throw error;
|
|
668
|
+
for (const { nuxtModule, meta = {}, moduleToInstall, buildTimeModuleMeta, resolvedModulePath, inlineOptions } of resolvedModules) {
|
|
669
|
+
const configKey = meta.configKey;
|
|
670
|
+
const optionsFns = new Set([
|
|
671
|
+
...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [],
|
|
672
|
+
...meta?.name ? nuxt._moduleOptionsFunctions.get(meta.name) || [] : [],
|
|
673
|
+
...configKey ? nuxt._moduleOptionsFunctions.get(configKey) || [] : []
|
|
674
|
+
]);
|
|
675
|
+
if (optionsFns.size > 0) {
|
|
676
|
+
const overrides = [];
|
|
677
|
+
const defaults = [];
|
|
678
|
+
for (const fn of optionsFns) {
|
|
679
|
+
const options = fn();
|
|
680
|
+
overrides.push(options.overrides);
|
|
681
|
+
defaults.push(options.defaults);
|
|
682
|
+
}
|
|
683
|
+
if (configKey) nuxt.options[configKey] = defu(...overrides, nuxt.options[configKey], ...defaults);
|
|
684
|
+
}
|
|
685
|
+
const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false;
|
|
686
|
+
if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, inlineOptions, nuxt);
|
|
687
|
+
const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0;
|
|
688
|
+
await callModule(nuxt, nuxtModule, inlineOptions, {
|
|
689
|
+
meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta),
|
|
690
|
+
nameOrPath: path,
|
|
691
|
+
modulePath: resolvedModulePath || path,
|
|
692
|
+
localLayerModuleDirs
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
delete nuxt._moduleOptionsFunctions;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Installs a module on a Nuxt instance.
|
|
699
|
+
* @deprecated Use module dependencies.
|
|
700
|
+
*/
|
|
701
|
+
async function installModule(moduleToInstall, inlineOptions, nuxt = useNuxt()) {
|
|
702
|
+
const { nuxtModule, buildTimeModuleMeta, resolvedModulePath } = await loadNuxtModuleInstance(moduleToInstall, nuxt);
|
|
703
|
+
const localLayerModuleDirs = [];
|
|
704
|
+
for (const dirs of getLayerDirectories(nuxt)) if (!NODE_MODULES_RE.test(dirs.app)) localLayerModuleDirs.push(dirs.modules);
|
|
705
|
+
const meta = await nuxtModule.getMeta?.();
|
|
706
|
+
let mergedOptions = inlineOptions;
|
|
707
|
+
const configKey = meta?.configKey;
|
|
708
|
+
if (configKey && nuxt._moduleOptionsFunctions) {
|
|
709
|
+
const optionsFns = [...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [], ...nuxt._moduleOptionsFunctions.get(configKey) || []];
|
|
710
|
+
if (optionsFns.length > 0) {
|
|
711
|
+
const overrides = [];
|
|
712
|
+
const defaults = [];
|
|
713
|
+
for (const fn of optionsFns) {
|
|
714
|
+
const options = fn();
|
|
715
|
+
overrides.push(options.overrides);
|
|
716
|
+
defaults.push(options.defaults);
|
|
717
|
+
}
|
|
718
|
+
mergedOptions = defu(inlineOptions, ...overrides, nuxt.options[configKey], ...defaults);
|
|
719
|
+
nuxt.options[configKey] = mergedOptions;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false;
|
|
723
|
+
if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, mergedOptions, nuxt);
|
|
724
|
+
const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0;
|
|
725
|
+
await callModule(nuxt, nuxtModule, mergedOptions, {
|
|
726
|
+
meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta),
|
|
727
|
+
nameOrPath: path,
|
|
728
|
+
modulePath: resolvedModulePath || path,
|
|
729
|
+
localLayerModuleDirs
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
function resolveModuleWithOptions(definition, nuxt) {
|
|
733
|
+
const [module, options = {}] = Array.isArray(definition) ? definition : [definition, {}];
|
|
734
|
+
if (!module) return;
|
|
735
|
+
if (typeof module !== "string") return {
|
|
736
|
+
module,
|
|
737
|
+
options
|
|
738
|
+
};
|
|
739
|
+
const modAlias = resolveAlias(module, nuxt.options.alias);
|
|
740
|
+
return {
|
|
741
|
+
module,
|
|
742
|
+
resolvedPath: resolveModulePath(modAlias, {
|
|
743
|
+
try: true,
|
|
744
|
+
from: nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/"))),
|
|
745
|
+
suffixes: [
|
|
746
|
+
"nuxt",
|
|
747
|
+
"nuxt/index",
|
|
748
|
+
"module",
|
|
749
|
+
"module/index",
|
|
750
|
+
"",
|
|
751
|
+
"index"
|
|
752
|
+
],
|
|
753
|
+
extensions: [
|
|
754
|
+
".js",
|
|
755
|
+
".mjs",
|
|
756
|
+
".cjs",
|
|
757
|
+
".ts",
|
|
758
|
+
".mts",
|
|
759
|
+
".cts"
|
|
760
|
+
]
|
|
761
|
+
}) || modAlias,
|
|
762
|
+
options
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
async function loadNuxtModuleInstance(nuxtModule, nuxt = useNuxt()) {
|
|
766
|
+
let buildTimeModuleMeta = {};
|
|
767
|
+
if (typeof nuxtModule === "function") return {
|
|
768
|
+
nuxtModule,
|
|
769
|
+
buildTimeModuleMeta
|
|
770
|
+
};
|
|
771
|
+
if (typeof nuxtModule !== "string") throw new TypeError(`Nuxt module should be a function or a string to import. Received: ${nuxtModule}.`);
|
|
772
|
+
const jiti = createJiti(nuxt.options.rootDir, { alias: nuxt.options.alias });
|
|
773
|
+
nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias);
|
|
774
|
+
if (isRelative(nuxtModule)) nuxtModule = resolve(nuxt.options.rootDir, nuxtModule);
|
|
775
|
+
try {
|
|
776
|
+
const src = resolveModuleURL(nuxtModule, {
|
|
777
|
+
from: nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/"))),
|
|
778
|
+
suffixes: [
|
|
779
|
+
"nuxt",
|
|
780
|
+
"nuxt/index",
|
|
781
|
+
"module",
|
|
782
|
+
"module/index",
|
|
783
|
+
"",
|
|
784
|
+
"index"
|
|
785
|
+
],
|
|
786
|
+
extensions: [
|
|
787
|
+
".js",
|
|
788
|
+
".mjs",
|
|
789
|
+
".cjs",
|
|
790
|
+
".ts",
|
|
791
|
+
".mts",
|
|
792
|
+
".cts"
|
|
793
|
+
]
|
|
794
|
+
});
|
|
795
|
+
const resolvedModulePath = fileURLToPath(src);
|
|
796
|
+
const resolvedNuxtModule = await jiti.import(src, { default: true });
|
|
797
|
+
if (typeof resolvedNuxtModule !== "function") throw new TypeError(`Nuxt module should be a function: ${nuxtModule}.`);
|
|
798
|
+
const moduleMetadataPath = new URL("module.json", src);
|
|
799
|
+
if (existsSync(moduleMetadataPath)) buildTimeModuleMeta = JSON.parse(await promises.readFile(moduleMetadataPath, "utf-8"));
|
|
800
|
+
return {
|
|
801
|
+
nuxtModule: resolvedNuxtModule,
|
|
802
|
+
buildTimeModuleMeta,
|
|
803
|
+
resolvedModulePath
|
|
804
|
+
};
|
|
805
|
+
} catch (error) {
|
|
806
|
+
const code = error.code;
|
|
807
|
+
if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED" || code === "ERR_UNSUPPORTED_DIR_IMPORT" || code === "ENOTDIR") throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`);
|
|
808
|
+
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
809
|
+
const module = MissingModuleMatcher.exec(error.message)?.[1];
|
|
810
|
+
if (module && !module.includes(nuxtModule)) throw new TypeError(`Error while importing module \`${nuxtModule}\`: ${error}`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`);
|
|
814
|
+
}
|
|
815
|
+
function getDirectory(p) {
|
|
816
|
+
try {
|
|
817
|
+
return isAbsolute(p) && lstatSync(p).isFile() ? dirname(p) : p;
|
|
818
|
+
} catch {}
|
|
819
|
+
return p;
|
|
820
|
+
}
|
|
821
|
+
const normalizeModuleTranspilePath = (p) => {
|
|
822
|
+
return getDirectory(p).split("node_modules/").pop();
|
|
823
|
+
};
|
|
824
|
+
const MissingModuleMatcher = /Cannot find module\s+['"]?([^'")\s]+)['"]?/i;
|
|
825
|
+
async function callLifecycleHooks(nuxtModule, meta = {}, inlineOptions, nuxt = useNuxt()) {
|
|
826
|
+
if (!meta.name || !meta.version) return;
|
|
827
|
+
if (!nuxtModule.onInstall && !nuxtModule.onUpgrade) return;
|
|
828
|
+
const previousVersion = read({
|
|
829
|
+
dir: nuxt.options.rootDir,
|
|
830
|
+
name: ".nuxtrc"
|
|
831
|
+
})?.setups?.[meta.name];
|
|
832
|
+
try {
|
|
833
|
+
if (!previousVersion) await nuxtModule.onInstall?.(nuxt);
|
|
834
|
+
else if (semver.gt(meta.version, previousVersion)) await nuxtModule.onUpgrade?.(nuxt, inlineOptions, previousVersion);
|
|
835
|
+
if (previousVersion !== meta.version) update({ setups: { [meta.name]: meta?.version } }, {
|
|
836
|
+
dir: nuxt.options.rootDir,
|
|
837
|
+
name: ".nuxtrc"
|
|
838
|
+
});
|
|
839
|
+
} catch (e) {
|
|
840
|
+
logger.error(`Error while executing ${!previousVersion ? "install" : "upgrade"} hook for module \`${meta.name}\`: ${e}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
async function callModule(nuxt, nuxtModule, moduleOptions = {}, options) {
|
|
844
|
+
const modulePath = options.modulePath;
|
|
845
|
+
const nameOrPath = options.nameOrPath;
|
|
846
|
+
const localLayerModuleDirs = options.localLayerModuleDirs;
|
|
847
|
+
const fn = () => nuxt.options.experimental?.debugModuleMutation && nuxt._asyncLocalStorageModule ? nuxt._asyncLocalStorageModule.run(nuxtModule, () => nuxtModule(moduleOptions, nuxt)) : nuxtModule(moduleOptions, nuxt);
|
|
848
|
+
const res = options.meta.disabled ? false : await fn();
|
|
849
|
+
let entryPath;
|
|
850
|
+
if (typeof modulePath === "string") {
|
|
851
|
+
const parsed = parseNodeModulePath(modulePath);
|
|
852
|
+
if (parsed.name) {
|
|
853
|
+
const subpath = await lookupNodeModuleSubpath(modulePath) || ".";
|
|
854
|
+
entryPath = join(parsed.name, subpath === "./" ? "." : subpath);
|
|
855
|
+
}
|
|
856
|
+
if (res !== false) {
|
|
857
|
+
const moduleRoot = parsed.dir ? parsed.dir + parsed.name : await resolvePackageJSON(modulePath, { try: true }).then((r) => r ? dirname(r) : modulePath);
|
|
858
|
+
nuxt.options.build.transpile.push(normalizeModuleTranspilePath(moduleRoot));
|
|
859
|
+
const directory = moduleRoot.replace(/\/?$/, "/");
|
|
860
|
+
if (moduleRoot !== nameOrPath && !localLayerModuleDirs.some((dir) => directory.startsWith(dir))) nuxt.options.modulesDir.push(join(moduleRoot, "node_modules"));
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (nameOrPath) {
|
|
864
|
+
entryPath ||= resolveAlias(nameOrPath, nuxt.options.alias);
|
|
865
|
+
if (entryPath !== nameOrPath) options.meta.rawPath = nameOrPath;
|
|
866
|
+
}
|
|
867
|
+
nuxt.options._installedModules ||= [];
|
|
868
|
+
nuxt.options._installedModules.push({
|
|
869
|
+
meta: options.meta,
|
|
870
|
+
module: nuxtModule,
|
|
871
|
+
timings: (res || {}).timings,
|
|
872
|
+
entryPath
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
//#endregion
|
|
876
|
+
//#region src/module/compatibility.ts
|
|
877
|
+
function resolveNuxtModuleEntryName(m) {
|
|
878
|
+
if (typeof m === "object" && !Array.isArray(m)) return m.name;
|
|
879
|
+
if (Array.isArray(m)) return resolveNuxtModuleEntryName(m[0]);
|
|
880
|
+
return m || false;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Check if a Nuxt module is installed by name.
|
|
884
|
+
*
|
|
885
|
+
* This will check both the installed modules and the modules to be installed. Note
|
|
886
|
+
* that it cannot detect if a module is _going to be_ installed programmatically by another module.
|
|
887
|
+
*/
|
|
888
|
+
function hasNuxtModule(moduleName, nuxt = useNuxt()) {
|
|
889
|
+
return nuxt.options._installedModules.some(({ meta }) => meta.name === moduleName) || nuxt.options.modules.some((m) => moduleName === resolveNuxtModuleEntryName(m));
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Checks if a Nuxt module is compatible with a given semver version.
|
|
893
|
+
*/
|
|
894
|
+
async function hasNuxtModuleCompatibility(module, semverVersion, nuxt = useNuxt()) {
|
|
895
|
+
const version = await getNuxtModuleVersion(module, nuxt);
|
|
896
|
+
if (!version) return false;
|
|
897
|
+
return satisfies(normalizeSemanticVersion(version), semverVersion, { includePrerelease: true });
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Get the version of a Nuxt module.
|
|
901
|
+
*
|
|
902
|
+
* Scans installed modules for the version, if it's not found it will attempt to load the module instance and get the version from there.
|
|
903
|
+
*/
|
|
904
|
+
async function getNuxtModuleVersion(module, nuxt = useNuxt()) {
|
|
905
|
+
const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
|
|
906
|
+
if (moduleMeta.version) return moduleMeta.version;
|
|
907
|
+
if (!moduleMeta.name) return false;
|
|
908
|
+
for (const m of nuxt.options._installedModules) if (m.meta.name === moduleMeta.name && m.meta.version) return m.meta.version;
|
|
909
|
+
if (hasNuxtModule(moduleMeta.name)) {
|
|
910
|
+
const { nuxtModule, buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleMeta.name, nuxt);
|
|
911
|
+
return buildTimeModuleMeta.version || await nuxtModule.getMeta?.().then((r) => r.version) || false;
|
|
912
|
+
}
|
|
913
|
+
return false;
|
|
914
|
+
}
|
|
915
|
+
//#endregion
|
|
916
|
+
//#region src/loader/config.ts
|
|
917
|
+
const merger = createDefu((obj, key, value) => {
|
|
918
|
+
if (Array.isArray(obj[key]) && Array.isArray(value)) {
|
|
919
|
+
obj[key] = obj[key].concat(value);
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
async function loadNuxtConfig(opts) {
|
|
924
|
+
const localLayers = (await glob("layers/*", {
|
|
925
|
+
onlyDirectories: true,
|
|
926
|
+
cwd: opts.cwd || process.cwd()
|
|
927
|
+
})).map((d) => withTrailingSlash(d)).sort((a, b) => b.localeCompare(a));
|
|
928
|
+
opts.overrides = defu(opts.overrides, { _extends: localLayers });
|
|
929
|
+
const { configFile, layers = [], cwd, config: nuxtConfig, meta } = await withDefineNuxtConfig(() => loadConfig({
|
|
930
|
+
name: "nuxt",
|
|
931
|
+
configFile: "nuxt.config",
|
|
932
|
+
rcFile: ".nuxtrc",
|
|
933
|
+
extend: { extendKey: [
|
|
934
|
+
"theme",
|
|
935
|
+
"_extends",
|
|
936
|
+
"extends"
|
|
937
|
+
] },
|
|
938
|
+
dotenv: true,
|
|
939
|
+
globalRc: true,
|
|
940
|
+
merger,
|
|
941
|
+
...opts
|
|
942
|
+
}));
|
|
943
|
+
nuxtConfig.rootDir ||= cwd;
|
|
944
|
+
nuxtConfig._nuxtConfigFile = configFile;
|
|
945
|
+
nuxtConfig._nuxtConfigFiles = [configFile];
|
|
946
|
+
nuxtConfig._loadOptions = opts;
|
|
947
|
+
nuxtConfig.alias ||= {};
|
|
948
|
+
if (meta?.name) {
|
|
949
|
+
const alias = `#layers/${meta.name}`;
|
|
950
|
+
nuxtConfig.alias[alias] ||= withTrailingSlash(nuxtConfig.rootDir);
|
|
951
|
+
}
|
|
952
|
+
const defaultBuildDir = join(nuxtConfig.rootDir, ".nuxt");
|
|
953
|
+
if (!opts.overrides?._prepare && !nuxtConfig.dev && !nuxtConfig.buildDir && existsSync(defaultBuildDir)) nuxtConfig.buildDir = join(nuxtConfig.rootDir, "node_modules/.cache/nuxt/.nuxt");
|
|
954
|
+
const NuxtConfigSchema = await loadNuxtSchema(nuxtConfig.rootDir || cwd || process.cwd());
|
|
955
|
+
const layerSchemaKeys = [
|
|
956
|
+
"future",
|
|
957
|
+
"srcDir",
|
|
958
|
+
"rootDir",
|
|
959
|
+
"serverDir",
|
|
960
|
+
"dir"
|
|
961
|
+
];
|
|
962
|
+
const layerSchema = Object.create(null);
|
|
963
|
+
for (const key of layerSchemaKeys) if (key in NuxtConfigSchema) layerSchema[key] = NuxtConfigSchema[key];
|
|
964
|
+
const _layers = [];
|
|
965
|
+
const processedLayers = /* @__PURE__ */ new Set();
|
|
966
|
+
const localRelativePaths = new Set(localLayers.map((layer) => withoutTrailingSlash(layer)));
|
|
967
|
+
for (const layer of layers) {
|
|
968
|
+
const resolvedRootDir = layer.config?.rootDir ?? layer.cwd;
|
|
969
|
+
layer.config = {
|
|
970
|
+
...layer.config || {},
|
|
971
|
+
rootDir: resolvedRootDir
|
|
972
|
+
};
|
|
973
|
+
if (processedLayers.has(resolvedRootDir)) continue;
|
|
974
|
+
processedLayers.add(resolvedRootDir);
|
|
975
|
+
layer.config = await applyDefaults(layerSchema, layer.config);
|
|
976
|
+
if (!layer.configFile || layer.configFile.endsWith(".nuxtrc")) continue;
|
|
977
|
+
if (layer.cwd && cwd && localRelativePaths.has(relative(cwd, layer.cwd))) {
|
|
978
|
+
layer.meta ||= {};
|
|
979
|
+
layer.meta.name ||= basename(layer.cwd);
|
|
980
|
+
}
|
|
981
|
+
if (layer.meta?.name) {
|
|
982
|
+
const alias = `#layers/${layer.meta.name}`;
|
|
983
|
+
nuxtConfig.alias[alias] ||= withTrailingSlash(layer.config.rootDir || layer.cwd);
|
|
984
|
+
}
|
|
985
|
+
_layers.push(layer);
|
|
986
|
+
}
|
|
987
|
+
nuxtConfig._layers = _layers;
|
|
988
|
+
if (!_layers.length) _layers.push({
|
|
989
|
+
cwd,
|
|
990
|
+
config: {
|
|
991
|
+
rootDir: cwd,
|
|
992
|
+
srcDir: cwd
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
return await applyDefaults(NuxtConfigSchema, nuxtConfig);
|
|
996
|
+
}
|
|
997
|
+
function loadNuxtSchema(cwd) {
|
|
998
|
+
const url = directoryToURL(cwd);
|
|
999
|
+
const urls = [url];
|
|
1000
|
+
const nuxtPath = resolveModuleURL("nuxt", {
|
|
1001
|
+
try: true,
|
|
1002
|
+
from: url
|
|
1003
|
+
}) ?? resolveModuleURL("nuxt-nightly", {
|
|
1004
|
+
try: true,
|
|
1005
|
+
from: url
|
|
1006
|
+
});
|
|
1007
|
+
if (nuxtPath) urls.unshift(nuxtPath);
|
|
1008
|
+
return import(resolveModuleURL("@nuxt/schema", {
|
|
1009
|
+
try: true,
|
|
1010
|
+
from: urls
|
|
1011
|
+
}) ?? "@nuxt/schema").then((r) => r.NuxtConfigSchema);
|
|
1012
|
+
}
|
|
1013
|
+
async function withDefineNuxtConfig(fn) {
|
|
1014
|
+
const key = "defineNuxtConfig";
|
|
1015
|
+
const globalSelf = globalThis;
|
|
1016
|
+
if (!globalSelf[key]) {
|
|
1017
|
+
globalSelf[key] = (c) => c;
|
|
1018
|
+
globalSelf[key].count = 0;
|
|
1019
|
+
}
|
|
1020
|
+
globalSelf[key].count++;
|
|
1021
|
+
try {
|
|
1022
|
+
return await fn();
|
|
1023
|
+
} finally {
|
|
1024
|
+
globalSelf[key].count--;
|
|
1025
|
+
if (!globalSelf[key].count) delete globalSelf[key];
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
//#endregion
|
|
1029
|
+
//#region src/loader/schema.ts
|
|
1030
|
+
function extendNuxtSchema(def) {
|
|
1031
|
+
useNuxt().hook("schema:extend", (schemas) => {
|
|
1032
|
+
schemas.push(typeof def === "function" ? def() : def);
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
//#endregion
|
|
1036
|
+
//#region src/loader/nuxt.ts
|
|
1037
|
+
async function loadNuxt(opts) {
|
|
1038
|
+
opts.cwd = resolve(opts.cwd || opts.rootDir || ".");
|
|
1039
|
+
opts.overrides ||= opts.config || {};
|
|
1040
|
+
opts.overrides.dev = !!opts.dev;
|
|
1041
|
+
const resolvedPath = ["nuxt-nightly", "nuxt"].reduce((resolvedPath, pkg) => {
|
|
1042
|
+
const path = resolveModulePath(pkg, {
|
|
1043
|
+
try: true,
|
|
1044
|
+
from: [directoryToURL(opts.cwd)]
|
|
1045
|
+
});
|
|
1046
|
+
return path && path.length > resolvedPath.length ? path : resolvedPath;
|
|
1047
|
+
}, "");
|
|
1048
|
+
if (!resolvedPath) throw new Error(`Cannot find any nuxt version from ${opts.cwd}`);
|
|
1049
|
+
const { loadNuxt } = await import(pathToFileURL(resolvedPath).href).then((r) => interopDefault(r));
|
|
1050
|
+
return await loadNuxt(opts);
|
|
1051
|
+
}
|
|
1052
|
+
async function buildNuxt(nuxt) {
|
|
1053
|
+
const rootURL = directoryToURL(nuxt.options.rootDir);
|
|
1054
|
+
const { build } = await tryImportModule("nuxt-nightly", { url: rootURL }) || await importModule("nuxt", { url: rootURL });
|
|
1055
|
+
return runWithNuxtContext(nuxt, () => build(nuxt));
|
|
1056
|
+
}
|
|
1057
|
+
//#endregion
|
|
1058
|
+
//#region src/head.ts
|
|
1059
|
+
function setGlobalHead(head) {
|
|
1060
|
+
const nuxt = useNuxt();
|
|
1061
|
+
nuxt.options.app.head = defu(head, nuxt.options.app.head);
|
|
1062
|
+
}
|
|
1063
|
+
//#endregion
|
|
1064
|
+
//#region src/imports.ts
|
|
1065
|
+
function addImports(imports) {
|
|
1066
|
+
useNuxt().hook("imports:extend", (_imports) => {
|
|
1067
|
+
_imports.push(...toArray(imports));
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
function addImportsDir(dirs, opts = {}) {
|
|
1071
|
+
useNuxt().hook("imports:dirs", (_dirs) => {
|
|
1072
|
+
for (const dir of toArray(dirs)) _dirs[opts.prepend ? "unshift" : "push"](dir);
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
function addImportsSources(presets) {
|
|
1076
|
+
useNuxt().hook("imports:sources", (_presets) => {
|
|
1077
|
+
for (const preset of toArray(presets)) _presets.push(preset);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
//#endregion
|
|
1081
|
+
//#region src/nitro.ts
|
|
1082
|
+
const HANDLER_METHOD_RE = /\.(get|head|patch|post|put|delete|connect|options|trace)(\.\w+)*$/;
|
|
1083
|
+
/**
|
|
1084
|
+
* normalize handler object
|
|
1085
|
+
*
|
|
1086
|
+
*/
|
|
1087
|
+
function normalizeHandlerMethod(handler) {
|
|
1088
|
+
const [, method = void 0] = handler.handler.match(HANDLER_METHOD_RE) || [];
|
|
1089
|
+
return {
|
|
1090
|
+
method: method?.toUpperCase(),
|
|
1091
|
+
...handler,
|
|
1092
|
+
handler: normalize(handler.handler)
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Adds a nitro server handler
|
|
1097
|
+
*
|
|
1098
|
+
*/
|
|
1099
|
+
function addServerHandler(handler) {
|
|
1100
|
+
useNuxt().options.serverHandlers.push(normalizeHandlerMethod(handler));
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Adds a nitro server handler for development-only
|
|
1104
|
+
*
|
|
1105
|
+
*/
|
|
1106
|
+
function addDevServerHandler(handler) {
|
|
1107
|
+
useNuxt().options.devServerHandlers.push(handler);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Adds a Nitro plugin
|
|
1111
|
+
*/
|
|
1112
|
+
function addServerPlugin(plugin) {
|
|
1113
|
+
const nuxt = useNuxt();
|
|
1114
|
+
nuxt.options.nitro.plugins ||= [];
|
|
1115
|
+
nuxt.options.nitro.plugins.push(normalize(plugin));
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Adds routes to be prerendered
|
|
1119
|
+
*/
|
|
1120
|
+
function addPrerenderRoutes(routes) {
|
|
1121
|
+
const nuxt = useNuxt();
|
|
1122
|
+
routes = toArray(routes).filter(Boolean);
|
|
1123
|
+
if (!routes.length) return;
|
|
1124
|
+
nuxt.hook("prerender:routes", (ctx) => {
|
|
1125
|
+
for (const route of routes) ctx.routes.add(route);
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Access to the Nitro instance
|
|
1130
|
+
*
|
|
1131
|
+
* **Note:** You can call `useNitro()` only after `ready` hook.
|
|
1132
|
+
*
|
|
1133
|
+
* **Note:** Changes to the Nitro instance configuration are not applied.
|
|
1134
|
+
* @example
|
|
1135
|
+
*
|
|
1136
|
+
* ```ts
|
|
1137
|
+
* nuxt.hook('ready', () => {
|
|
1138
|
+
* console.log(useNitro())
|
|
1139
|
+
* })
|
|
1140
|
+
* ```
|
|
1141
|
+
*/
|
|
1142
|
+
function useNitro() {
|
|
1143
|
+
const nuxt = useNuxt();
|
|
1144
|
+
if (!nuxt._nitro) throw new Error("Nitro is not initialized yet. You can call `useNitro()` only after `ready` hook.");
|
|
1145
|
+
return nuxt._nitro;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Add server imports to be auto-imported by Nitro
|
|
1149
|
+
*/
|
|
1150
|
+
function addServerImports(imports) {
|
|
1151
|
+
const nuxt = useNuxt();
|
|
1152
|
+
const _imports = toArray(imports);
|
|
1153
|
+
nuxt.hook("nitro:config", (config) => {
|
|
1154
|
+
config.imports ||= {};
|
|
1155
|
+
config.imports.imports ||= [];
|
|
1156
|
+
config.imports.imports.push(..._imports);
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Add directories to be scanned for auto-imports by Nitro
|
|
1161
|
+
*/
|
|
1162
|
+
function addServerImportsDir(dirs, opts = {}) {
|
|
1163
|
+
const nuxt = useNuxt();
|
|
1164
|
+
const _dirs = toArray(dirs);
|
|
1165
|
+
nuxt.hook("nitro:config", (config) => {
|
|
1166
|
+
config.imports ||= {};
|
|
1167
|
+
config.imports.dirs ||= [];
|
|
1168
|
+
config.imports.dirs[opts.prepend ? "unshift" : "push"](..._dirs);
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Add directories to be scanned by Nitro. It will check for subdirectories,
|
|
1173
|
+
* which will be registered just like the `~~/server` folder is.
|
|
1174
|
+
*/
|
|
1175
|
+
function addServerScanDir(dirs, opts = {}) {
|
|
1176
|
+
useNuxt().hook("nitro:config", (config) => {
|
|
1177
|
+
config.scanDirs ||= [];
|
|
1178
|
+
for (const dir of toArray(dirs)) config.scanDirs[opts.prepend ? "unshift" : "push"](dir);
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
//#endregion
|
|
1182
|
+
//#region src/runtime-config.ts
|
|
1183
|
+
/**
|
|
1184
|
+
* Access 'resolved' Nuxt runtime configuration, with values updated from environment.
|
|
1185
|
+
*
|
|
1186
|
+
* This mirrors the runtime behavior of Nitro.
|
|
1187
|
+
*/
|
|
1188
|
+
function useRuntimeConfig() {
|
|
1189
|
+
const nuxt = useNuxt();
|
|
1190
|
+
return applyEnv(klona(nuxt.options.nitro.runtimeConfig), {
|
|
1191
|
+
prefix: "NITRO_",
|
|
1192
|
+
altPrefix: "NUXT_",
|
|
1193
|
+
envExpansion: nuxt.options.nitro.experimental?.envExpansion ?? !!process.env.NITRO_ENV_EXPANSION
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Update Nuxt runtime configuration.
|
|
1198
|
+
*/
|
|
1199
|
+
function updateRuntimeConfig(runtimeConfig) {
|
|
1200
|
+
const nuxt = useNuxt();
|
|
1201
|
+
Object.assign(nuxt.options.nitro.runtimeConfig, defu(runtimeConfig, nuxt.options.nitro.runtimeConfig));
|
|
1202
|
+
try {
|
|
1203
|
+
return useNitro().updateConfig({ runtimeConfig });
|
|
1204
|
+
} catch {}
|
|
1205
|
+
}
|
|
1206
|
+
function getEnv(key, opts, env = process.env) {
|
|
1207
|
+
const envKey = snakeCase(key).toUpperCase();
|
|
1208
|
+
return destr(env[opts.prefix + envKey] ?? env[opts.altPrefix + envKey]);
|
|
1209
|
+
}
|
|
1210
|
+
function _isObject(input) {
|
|
1211
|
+
return typeof input === "object" && !Array.isArray(input);
|
|
1212
|
+
}
|
|
1213
|
+
function applyEnv(obj, opts, parentKey = "") {
|
|
1214
|
+
for (const key in obj) {
|
|
1215
|
+
const subKey = parentKey ? `${parentKey}_${key}` : key;
|
|
1216
|
+
const envValue = getEnv(subKey, opts);
|
|
1217
|
+
if (_isObject(obj[key])) if (_isObject(envValue)) {
|
|
1218
|
+
obj[key] = {
|
|
1219
|
+
...obj[key],
|
|
1220
|
+
...envValue
|
|
1221
|
+
};
|
|
1222
|
+
applyEnv(obj[key], opts, subKey);
|
|
1223
|
+
} else if (envValue === void 0) applyEnv(obj[key], opts, subKey);
|
|
1224
|
+
else obj[key] = envValue ?? obj[key];
|
|
1225
|
+
else obj[key] = envValue ?? obj[key];
|
|
1226
|
+
if (opts.envExpansion && typeof obj[key] === "string") obj[key] = _expandFromEnv(obj[key]);
|
|
1227
|
+
}
|
|
1228
|
+
return obj;
|
|
1229
|
+
}
|
|
1230
|
+
const envExpandRx = /\{\{([^{}]*)\}\}/g;
|
|
1231
|
+
function _expandFromEnv(value, env = process.env) {
|
|
1232
|
+
return value.replace(envExpandRx, (match, key) => {
|
|
1233
|
+
return env[key] || match;
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
//#endregion
|
|
1237
|
+
//#region src/build.ts
|
|
1238
|
+
const extendWebpackCompatibleConfig = (builder) => (fn, options = {}) => {
|
|
1239
|
+
const nuxt = useNuxt();
|
|
1240
|
+
if (options.dev === false && nuxt.options.dev) return;
|
|
1241
|
+
if (options.build === false && nuxt.options.build) return;
|
|
1242
|
+
nuxt.hook(`${builder}:config`, async (configs) => {
|
|
1243
|
+
if (options.server !== false) {
|
|
1244
|
+
const config = configs.find((i) => i.name === "server");
|
|
1245
|
+
if (config) await fn(config);
|
|
1246
|
+
}
|
|
1247
|
+
if (options.client !== false) {
|
|
1248
|
+
const config = configs.find((i) => i.name === "client");
|
|
1249
|
+
if (config) await fn(config);
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
};
|
|
1253
|
+
/**
|
|
1254
|
+
* Extend webpack config
|
|
1255
|
+
*
|
|
1256
|
+
* The fallback function might be called multiple times
|
|
1257
|
+
* when applying to both client and server builds.
|
|
1258
|
+
*/
|
|
1259
|
+
const extendWebpackConfig = extendWebpackCompatibleConfig("webpack");
|
|
1260
|
+
/**
|
|
1261
|
+
* Extend rspack config
|
|
1262
|
+
*
|
|
1263
|
+
* The fallback function might be called multiple times
|
|
1264
|
+
* when applying to both client and server builds.
|
|
1265
|
+
*/
|
|
1266
|
+
const extendRspackConfig = extendWebpackCompatibleConfig("rspack");
|
|
1267
|
+
/**
|
|
1268
|
+
* Extend Vite config
|
|
1269
|
+
*/
|
|
1270
|
+
function extendViteConfig(fn, options = {}) {
|
|
1271
|
+
const nuxt = useNuxt();
|
|
1272
|
+
if (options.dev === false && nuxt.options.dev) return;
|
|
1273
|
+
if (options.build === false && nuxt.options.build) return;
|
|
1274
|
+
if (options.server === false || options.client === false) {
|
|
1275
|
+
const caller = getUserCaller();
|
|
1276
|
+
warn(`[@nuxt/kit] calling \`extendViteConfig\` with only server/client environment is deprecated${caller ? ` (used at \`${resolveAlias(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Nuxt 5+ will use the Vite Environment API which shares a configuration between environments. You can likely use a Vite plugin to achieve the same result.`);
|
|
1277
|
+
}
|
|
1278
|
+
return nuxt.hook("vite:extend", ({ config }) => fn(config));
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Append webpack plugin to the config.
|
|
1282
|
+
*/
|
|
1283
|
+
function addWebpackPlugin(pluginOrGetter, options) {
|
|
1284
|
+
extendWebpackConfig(async (config) => {
|
|
1285
|
+
const method = options?.prepend ? "unshift" : "push";
|
|
1286
|
+
const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter;
|
|
1287
|
+
config.plugins ||= [];
|
|
1288
|
+
config.plugins[method](...toArray(plugin));
|
|
1289
|
+
}, options);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Append rspack plugin to the config.
|
|
1293
|
+
*/
|
|
1294
|
+
function addRspackPlugin(pluginOrGetter, options) {
|
|
1295
|
+
extendRspackConfig(async (config) => {
|
|
1296
|
+
const method = options?.prepend ? "unshift" : "push";
|
|
1297
|
+
const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter;
|
|
1298
|
+
config.plugins ||= [];
|
|
1299
|
+
config.plugins[method](...toArray(plugin));
|
|
1300
|
+
}, options);
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Append Vite plugin to the config.
|
|
1304
|
+
*/
|
|
1305
|
+
function addVitePlugin(pluginOrGetter, options = {}) {
|
|
1306
|
+
const nuxt = useNuxt();
|
|
1307
|
+
if (options.dev === false && nuxt.options.dev) return;
|
|
1308
|
+
if (options.build === false && nuxt.options.build) return;
|
|
1309
|
+
let needsEnvInjection = false;
|
|
1310
|
+
nuxt.hook("vite:extend", async ({ config }) => {
|
|
1311
|
+
config.plugins ||= [];
|
|
1312
|
+
const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter);
|
|
1313
|
+
if (options.server !== false && options.client !== false) {
|
|
1314
|
+
const method = options?.prepend ? "unshift" : "push";
|
|
1315
|
+
config.plugins[method](...plugin);
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (!config.environments?.ssr || !config.environments.client) {
|
|
1319
|
+
needsEnvInjection = true;
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const environmentName = options.server === false ? "client" : "ssr";
|
|
1323
|
+
const pluginName = plugin.map((p) => p.name).join("|");
|
|
1324
|
+
config.plugins.push({
|
|
1325
|
+
name: `${pluginName}:wrapper`,
|
|
1326
|
+
enforce: options?.prepend ? "pre" : "post",
|
|
1327
|
+
applyToEnvironment(environment) {
|
|
1328
|
+
if (environment.name === environmentName) return plugin;
|
|
1329
|
+
}
|
|
1330
|
+
});
|
|
1331
|
+
});
|
|
1332
|
+
nuxt.hook("vite:extendConfig", async (config, env) => {
|
|
1333
|
+
if (!needsEnvInjection) return;
|
|
1334
|
+
const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter);
|
|
1335
|
+
const method = options?.prepend ? "unshift" : "push";
|
|
1336
|
+
if (env.isClient && options.server === false) config.plugins[method](...plugin);
|
|
1337
|
+
if (env.isServer && options.client === false) config.plugins[method](...plugin);
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
function addBuildPlugin(pluginFactory, options) {
|
|
1341
|
+
if (pluginFactory.vite) addVitePlugin(pluginFactory.vite, options);
|
|
1342
|
+
if (pluginFactory.webpack) addWebpackPlugin(pluginFactory.webpack, options);
|
|
1343
|
+
if (pluginFactory.rspack) addRspackPlugin(pluginFactory.rspack, options);
|
|
1344
|
+
}
|
|
1345
|
+
//#endregion
|
|
1346
|
+
//#region src/components.ts
|
|
1347
|
+
/**
|
|
1348
|
+
* Register a directory to be scanned for components and imported only when used.
|
|
1349
|
+
*/
|
|
1350
|
+
function addComponentsDir(dir, opts = {}) {
|
|
1351
|
+
const nuxt = useNuxt();
|
|
1352
|
+
nuxt.options.components ||= [];
|
|
1353
|
+
dir.priority ||= 0;
|
|
1354
|
+
nuxt.hook("components:dirs", (dirs) => {
|
|
1355
|
+
dirs[opts.prepend ? "unshift" : "push"](dir);
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* This utility takes a file path or npm package that is scanned for named exports, which are get added automatically
|
|
1360
|
+
*/
|
|
1361
|
+
function addComponentExports(opts) {
|
|
1362
|
+
const nuxt = useNuxt();
|
|
1363
|
+
const components = [];
|
|
1364
|
+
nuxt.hook("components:dirs", async () => {
|
|
1365
|
+
const names = await resolveModuleExportNames(await resolvePath(opts.filePath), { extensions: nuxt.options.extensions });
|
|
1366
|
+
components.length = 0;
|
|
1367
|
+
for (const name of names) components.push(normalizeComponent({
|
|
1368
|
+
name: pascalCase([opts.prefix || "", name === "default" ? "" : name]),
|
|
1369
|
+
export: name,
|
|
1370
|
+
...opts
|
|
1371
|
+
}));
|
|
1372
|
+
});
|
|
1373
|
+
addComponents(components);
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Register a component by its name and filePath.
|
|
1377
|
+
*/
|
|
1378
|
+
function addComponent(opts) {
|
|
1379
|
+
addComponents([normalizeComponent(opts)]);
|
|
1380
|
+
}
|
|
1381
|
+
function addComponents(addedComponents) {
|
|
1382
|
+
const nuxt = useNuxt();
|
|
1383
|
+
nuxt.options.components ||= [];
|
|
1384
|
+
nuxt.hook("components:extend", (components) => {
|
|
1385
|
+
for (const component of addedComponents) {
|
|
1386
|
+
const existingComponentIndex = components.findIndex((c) => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode);
|
|
1387
|
+
if (existingComponentIndex !== -1) {
|
|
1388
|
+
const existingComponent = components[existingComponentIndex];
|
|
1389
|
+
const existingPriority = existingComponent.priority ?? 0;
|
|
1390
|
+
const newPriority = component.priority ?? 0;
|
|
1391
|
+
if (newPriority < existingPriority) continue;
|
|
1392
|
+
if (newPriority === existingPriority) {
|
|
1393
|
+
const name = existingComponent.pascalName || existingComponent.kebabName;
|
|
1394
|
+
logger.warn(`Overriding ${name} component. You can specify a \`priority\` option when calling \`addComponent\` to avoid this warning.`);
|
|
1395
|
+
}
|
|
1396
|
+
components.splice(existingComponentIndex, 1, component);
|
|
1397
|
+
} else components.push(component);
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
function normalizeComponent(opts) {
|
|
1402
|
+
if (!opts.mode) {
|
|
1403
|
+
const [, mode = "all"] = opts.filePath.match(MODE_RE) || [];
|
|
1404
|
+
opts.mode = mode;
|
|
1405
|
+
}
|
|
1406
|
+
return {
|
|
1407
|
+
export: opts.export || "default",
|
|
1408
|
+
chunkName: "components/" + kebabCase(opts.name),
|
|
1409
|
+
global: opts.global ?? false,
|
|
1410
|
+
kebabName: kebabCase(opts.name || ""),
|
|
1411
|
+
pascalName: pascalCase(opts.name || ""),
|
|
1412
|
+
prefetch: false,
|
|
1413
|
+
preload: false,
|
|
1414
|
+
mode: "all",
|
|
1415
|
+
shortPath: opts.filePath,
|
|
1416
|
+
priority: 0,
|
|
1417
|
+
meta: {},
|
|
1418
|
+
...opts
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
//#endregion
|
|
1422
|
+
//#region src/template.ts
|
|
1423
|
+
/**
|
|
1424
|
+
* Renders given template during build into the virtual file system (and optionally to disk in the project `buildDir`)
|
|
1425
|
+
*/
|
|
1426
|
+
function addTemplate(_template) {
|
|
1427
|
+
const nuxt = useNuxt();
|
|
1428
|
+
const template = normalizeTemplate(_template);
|
|
1429
|
+
filterInPlace(nuxt.options.build.templates, (p) => (p.dst || normalizeTemplate(p).dst) !== template.dst);
|
|
1430
|
+
try {
|
|
1431
|
+
const distDir = distDirURL.toString();
|
|
1432
|
+
const { source } = captureStackTrace().find((e) => e.source && !e.source.startsWith(distDir)) ?? {};
|
|
1433
|
+
if (source) {
|
|
1434
|
+
const path = normalize(fileURLToPath(source));
|
|
1435
|
+
if (existsSync(path)) template._path = path;
|
|
1436
|
+
}
|
|
1437
|
+
} catch {}
|
|
1438
|
+
nuxt.options.build.templates.push(template);
|
|
1439
|
+
return template;
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Adds a virtual file that can be used within the Nuxt Nitro server build.
|
|
1443
|
+
*/
|
|
1444
|
+
function addServerTemplate(template) {
|
|
1445
|
+
const nuxt = useNuxt();
|
|
1446
|
+
nuxt.options.nitro.virtual ||= {};
|
|
1447
|
+
nuxt.options.nitro.virtual[template.filename] = template.getContents;
|
|
1448
|
+
return template;
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Renders given types during build to disk in the project `buildDir`
|
|
1452
|
+
* and register them as types.
|
|
1453
|
+
*
|
|
1454
|
+
* You can pass a second context object to specify in which context the type should be added.
|
|
1455
|
+
*
|
|
1456
|
+
* If no context object is passed, then it will only be added to the nuxt context.
|
|
1457
|
+
*/
|
|
1458
|
+
function addTypeTemplate(_template, context) {
|
|
1459
|
+
const nuxt = useNuxt();
|
|
1460
|
+
const template = addTemplate(_template);
|
|
1461
|
+
if (!template.filename.endsWith(".d.ts")) throw new Error(`Invalid type template. Filename must end with .d.ts : "${template.filename}"`);
|
|
1462
|
+
if (!context || context.nuxt) nuxt.hook("prepare:types", (payload) => {
|
|
1463
|
+
payload.references ||= [];
|
|
1464
|
+
payload.references.push({ path: template.dst });
|
|
1465
|
+
});
|
|
1466
|
+
if (context?.node) nuxt.hook("prepare:types", (payload) => {
|
|
1467
|
+
payload.nodeReferences ||= [];
|
|
1468
|
+
payload.nodeReferences.push({ path: template.dst });
|
|
1469
|
+
});
|
|
1470
|
+
if (context?.shared) nuxt.hook("prepare:types", (payload) => {
|
|
1471
|
+
payload.sharedReferences ||= [];
|
|
1472
|
+
payload.sharedReferences.push({ path: template.dst });
|
|
1473
|
+
});
|
|
1474
|
+
if (!context || context.nuxt || context.shared) nuxt.options.vite.vue = defu(nuxt.options.vite.vue, { script: { globalTypeFiles: [template.dst] } });
|
|
1475
|
+
if (context?.nitro) nuxt.hook("nitro:prepare:types", (payload) => {
|
|
1476
|
+
payload.references ||= [];
|
|
1477
|
+
payload.references.push({ path: template.dst });
|
|
1478
|
+
});
|
|
1479
|
+
return template;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Normalize a nuxt template object
|
|
1483
|
+
*/
|
|
1484
|
+
function normalizeTemplate(template, buildDir) {
|
|
1485
|
+
if (!template) throw new Error("Invalid template: " + JSON.stringify(template));
|
|
1486
|
+
if (typeof template === "string") template = { src: template };
|
|
1487
|
+
else template = { ...template };
|
|
1488
|
+
if (template.src) {
|
|
1489
|
+
if (!existsSync(template.src)) throw new Error("Template not found: " + template.src);
|
|
1490
|
+
if (!template.filename) {
|
|
1491
|
+
const srcPath = parse(template.src);
|
|
1492
|
+
template.filename = template.fileName || `${basename(srcPath.dir)}.${srcPath.name}.${hash(template.src).replace(/-/g, "_")}${srcPath.ext}`;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (!template.src && !template.getContents) throw new Error("Invalid template. Either `getContents` or `src` should be provided: " + JSON.stringify(template));
|
|
1496
|
+
if (!template.filename) throw new Error("Invalid template. `filename` must be provided: " + JSON.stringify(template));
|
|
1497
|
+
if (template.filename.endsWith(".d.ts")) template.write = true;
|
|
1498
|
+
template.dst ||= resolve(buildDir ?? useNuxt().options.buildDir, template.filename);
|
|
1499
|
+
return template;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Trigger rebuilding Nuxt templates
|
|
1503
|
+
*
|
|
1504
|
+
* You can pass a filter within the options to selectively regenerate a subset of templates.
|
|
1505
|
+
*/
|
|
1506
|
+
async function updateTemplates(options) {
|
|
1507
|
+
await tryUseNuxt()?.hooks.callHook("builder:generateApp", options);
|
|
1508
|
+
}
|
|
1509
|
+
function resolveLayerPaths(dirs, projectBuildDir) {
|
|
1510
|
+
const relativeRootDir = relativeWithDot(projectBuildDir, dirs.root);
|
|
1511
|
+
const relativeSrcDir = relativeWithDot(projectBuildDir, dirs.app);
|
|
1512
|
+
const relativeModulesDir = relativeWithDot(projectBuildDir, dirs.modules);
|
|
1513
|
+
const relativeSharedDir = relativeWithDot(projectBuildDir, dirs.shared);
|
|
1514
|
+
return {
|
|
1515
|
+
nuxt: [
|
|
1516
|
+
join(relativeSrcDir, "**/*"),
|
|
1517
|
+
join(relativeModulesDir, `*/runtime/**/*`),
|
|
1518
|
+
join(relativeRootDir, `test/nuxt/**/*`),
|
|
1519
|
+
join(relativeRootDir, `tests/nuxt/**/*`),
|
|
1520
|
+
join(relativeRootDir, `layers/*/app/**/*`),
|
|
1521
|
+
join(relativeRootDir, `layers/*/modules/*/runtime/**/*`)
|
|
1522
|
+
],
|
|
1523
|
+
nitro: [
|
|
1524
|
+
join(relativeModulesDir, `*/runtime/server/**/*`),
|
|
1525
|
+
join(relativeRootDir, `layers/*/server/**/*`),
|
|
1526
|
+
join(relativeRootDir, `layers/*/modules/*/runtime/server/**/*`)
|
|
1527
|
+
],
|
|
1528
|
+
node: [
|
|
1529
|
+
join(relativeModulesDir, `*.*`),
|
|
1530
|
+
join(relativeRootDir, `nuxt.config.*`),
|
|
1531
|
+
join(relativeRootDir, `.config/nuxt.*`),
|
|
1532
|
+
join(relativeRootDir, `layers/*/nuxt.config.*`),
|
|
1533
|
+
join(relativeRootDir, `layers/*/.config/nuxt.*`),
|
|
1534
|
+
join(relativeRootDir, `layers/*/modules/**/*`)
|
|
1535
|
+
],
|
|
1536
|
+
shared: [
|
|
1537
|
+
join(relativeSharedDir, `**/*`),
|
|
1538
|
+
join(relativeModulesDir, `*/shared/**/*`),
|
|
1539
|
+
join(relativeRootDir, `layers/*/shared/**/*`)
|
|
1540
|
+
],
|
|
1541
|
+
sharedDeclarations: [
|
|
1542
|
+
join(relativeSharedDir, `**/*.d.ts`),
|
|
1543
|
+
join(relativeModulesDir, `*/shared/**/*.d.ts`),
|
|
1544
|
+
join(relativeRootDir, `layers/*/shared/**/*.d.ts`)
|
|
1545
|
+
],
|
|
1546
|
+
globalDeclarations: [join(relativeRootDir, `*.d.ts`), join(relativeRootDir, `layers/*/*.d.ts`)]
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
const EXTENSION_RE = /\b(?:\.d\.[cm]?ts|\.\w+)$/g;
|
|
1550
|
+
const excludedAlias = [/^@vue\/.*$/, /^#internal\/nuxt/];
|
|
1551
|
+
async function _generateTypes(nuxt) {
|
|
1552
|
+
const include = new Set(["./nuxt.d.ts"]);
|
|
1553
|
+
const nodeInclude = new Set(["./nuxt.node.d.ts"]);
|
|
1554
|
+
const sharedInclude = new Set(["./nuxt.shared.d.ts"]);
|
|
1555
|
+
const legacyInclude = new Set([...include, ...nodeInclude]);
|
|
1556
|
+
const exclude = /* @__PURE__ */ new Set();
|
|
1557
|
+
const nodeExclude = /* @__PURE__ */ new Set();
|
|
1558
|
+
const sharedExclude = /* @__PURE__ */ new Set();
|
|
1559
|
+
const legacyExclude = /* @__PURE__ */ new Set();
|
|
1560
|
+
if (nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.srcDir) {
|
|
1561
|
+
include.add(join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), "**/*"));
|
|
1562
|
+
legacyInclude.add(join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), "**/*"));
|
|
1563
|
+
}
|
|
1564
|
+
const layerDirs = getLayerDirectories(nuxt);
|
|
1565
|
+
const sourceDirs = layerDirs.map((layer) => layer.app);
|
|
1566
|
+
for (const dir of nuxt.options.modulesDir) {
|
|
1567
|
+
if (!sourceDirs.some((srcDir) => dir.startsWith(srcDir))) exclude.add(relativeWithDot(nuxt.options.buildDir, dir));
|
|
1568
|
+
nodeExclude.add(relativeWithDot(nuxt.options.buildDir, dir));
|
|
1569
|
+
legacyExclude.add(relativeWithDot(nuxt.options.buildDir, dir));
|
|
1570
|
+
}
|
|
1571
|
+
for (const dir of ["dist", ".data"]) {
|
|
1572
|
+
exclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
|
|
1573
|
+
nodeExclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
|
|
1574
|
+
legacyExclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
|
|
1575
|
+
}
|
|
1576
|
+
const rootDirWithSlash = withTrailingSlash$1(nuxt.options.rootDir);
|
|
1577
|
+
for (const dirs of layerDirs) if (!dirs.app.startsWith(rootDirWithSlash) || dirs.root === rootDirWithSlash || dirs.app.includes("node_modules")) {
|
|
1578
|
+
const rootGlob = join(relativeWithDot(nuxt.options.buildDir, dirs.root), "**/*");
|
|
1579
|
+
const paths = resolveLayerPaths(dirs, nuxt.options.buildDir);
|
|
1580
|
+
for (const path of paths.nuxt) {
|
|
1581
|
+
include.add(path);
|
|
1582
|
+
legacyInclude.add(path);
|
|
1583
|
+
if (path !== rootGlob) nodeExclude.add(path);
|
|
1584
|
+
}
|
|
1585
|
+
for (const path of paths.nitro) {
|
|
1586
|
+
exclude.add(path);
|
|
1587
|
+
nodeExclude.add(path);
|
|
1588
|
+
legacyExclude.add(path);
|
|
1589
|
+
}
|
|
1590
|
+
for (const path of paths.node) {
|
|
1591
|
+
nodeInclude.add(path);
|
|
1592
|
+
legacyInclude.add(path);
|
|
1593
|
+
exclude.add(path);
|
|
1594
|
+
}
|
|
1595
|
+
for (const path of paths.shared) {
|
|
1596
|
+
legacyInclude.add(path);
|
|
1597
|
+
sharedInclude.add(path);
|
|
1598
|
+
}
|
|
1599
|
+
for (const path of paths.sharedDeclarations) include.add(path);
|
|
1600
|
+
for (const path of paths.globalDeclarations) {
|
|
1601
|
+
include.add(path);
|
|
1602
|
+
legacyInclude.add(path);
|
|
1603
|
+
sharedInclude.add(path);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
const moduleEntryPaths = [];
|
|
1607
|
+
for (const m of nuxt.options._installedModules) {
|
|
1608
|
+
const path = m.meta?.rawPath || m.entryPath;
|
|
1609
|
+
if (path) moduleEntryPaths.push(getDirectory(path));
|
|
1610
|
+
}
|
|
1611
|
+
const modulePaths = await resolveNuxtModule(rootDirWithSlash, moduleEntryPaths);
|
|
1612
|
+
for (const path of modulePaths) {
|
|
1613
|
+
const relative = relativeWithDot(nuxt.options.buildDir, path);
|
|
1614
|
+
if (!path.includes("node_modules") && path.startsWith(rootDirWithSlash)) {
|
|
1615
|
+
include.add(join(relative, "runtime"));
|
|
1616
|
+
include.add(join(relative, "dist/runtime"));
|
|
1617
|
+
nodeInclude.add(join(relative, "*.*"));
|
|
1618
|
+
}
|
|
1619
|
+
legacyInclude.add(join(relative, "runtime"));
|
|
1620
|
+
legacyInclude.add(join(relative, "dist/runtime"));
|
|
1621
|
+
nodeExclude.add(join(relative, "runtime"));
|
|
1622
|
+
nodeExclude.add(join(relative, "dist/runtime"));
|
|
1623
|
+
exclude.add(join(relative, "runtime/server"));
|
|
1624
|
+
exclude.add(join(relative, "dist/runtime/server"));
|
|
1625
|
+
exclude.add(join(relative, "*.*"));
|
|
1626
|
+
exclude.add(join(relative, "dist/*.*"));
|
|
1627
|
+
legacyExclude.add(join(relative, "runtime/server"));
|
|
1628
|
+
legacyExclude.add(join(relative, "dist/runtime/server"));
|
|
1629
|
+
}
|
|
1630
|
+
const nestedModulesDirs = [];
|
|
1631
|
+
for (const dir of [...nuxt.options.modulesDir].sort()) {
|
|
1632
|
+
const withSlash = withTrailingSlash$1(dir);
|
|
1633
|
+
if (nestedModulesDirs.every((d) => !d.startsWith(withSlash))) nestedModulesDirs.push(withSlash);
|
|
1634
|
+
}
|
|
1635
|
+
let hasTypescriptVersionWithModulePreserve;
|
|
1636
|
+
for (const parent of nestedModulesDirs) hasTypescriptVersionWithModulePreserve ??= await readPackageJSON("typescript", { parent }).then((r) => r?.version && gte(r.version, "5.4.0")).catch(() => void 0);
|
|
1637
|
+
hasTypescriptVersionWithModulePreserve ??= true;
|
|
1638
|
+
const useDecorators = Boolean(nuxt.options.experimental?.decorators);
|
|
1639
|
+
const tsConfig = defu(nuxt.options.typescript?.tsConfig, {
|
|
1640
|
+
compilerOptions: {
|
|
1641
|
+
esModuleInterop: true,
|
|
1642
|
+
skipLibCheck: true,
|
|
1643
|
+
target: "ESNext",
|
|
1644
|
+
allowJs: true,
|
|
1645
|
+
resolveJsonModule: true,
|
|
1646
|
+
moduleDetection: "force",
|
|
1647
|
+
isolatedModules: true,
|
|
1648
|
+
verbatimModuleSyntax: true,
|
|
1649
|
+
allowArbitraryExtensions: true,
|
|
1650
|
+
strict: nuxt.options.typescript?.strict ?? true,
|
|
1651
|
+
noUncheckedIndexedAccess: true,
|
|
1652
|
+
forceConsistentCasingInFileNames: true,
|
|
1653
|
+
noImplicitOverride: true,
|
|
1654
|
+
...useDecorators ? { experimentalDecorators: false } : {},
|
|
1655
|
+
module: hasTypescriptVersionWithModulePreserve ? "preserve" : "ESNext",
|
|
1656
|
+
noEmit: true,
|
|
1657
|
+
lib: [
|
|
1658
|
+
"ESNext",
|
|
1659
|
+
...useDecorators ? ["esnext.decorators"] : [],
|
|
1660
|
+
"dom",
|
|
1661
|
+
"dom.iterable",
|
|
1662
|
+
"webworker"
|
|
1663
|
+
],
|
|
1664
|
+
jsx: "preserve",
|
|
1665
|
+
jsxImportSource: "vue",
|
|
1666
|
+
types: [],
|
|
1667
|
+
paths: {},
|
|
1668
|
+
moduleResolution: nuxt.options.future?.typescriptBundlerResolution || nuxt.options.experimental?.typescriptBundlerResolution ? "Bundler" : "Node",
|
|
1669
|
+
useDefineForClassFields: true,
|
|
1670
|
+
noImplicitThis: true,
|
|
1671
|
+
allowSyntheticDefaultImports: true
|
|
1672
|
+
},
|
|
1673
|
+
include: [...include],
|
|
1674
|
+
exclude: [...exclude]
|
|
1675
|
+
});
|
|
1676
|
+
const nodeTsConfig = defu(nuxt.options.typescript?.nodeTsConfig, {
|
|
1677
|
+
compilerOptions: {
|
|
1678
|
+
esModuleInterop: tsConfig.compilerOptions?.esModuleInterop,
|
|
1679
|
+
skipLibCheck: tsConfig.compilerOptions?.skipLibCheck,
|
|
1680
|
+
target: tsConfig.compilerOptions?.target,
|
|
1681
|
+
allowJs: tsConfig.compilerOptions?.allowJs,
|
|
1682
|
+
resolveJsonModule: tsConfig.compilerOptions?.resolveJsonModule,
|
|
1683
|
+
moduleDetection: tsConfig.compilerOptions?.moduleDetection,
|
|
1684
|
+
isolatedModules: tsConfig.compilerOptions?.isolatedModules,
|
|
1685
|
+
verbatimModuleSyntax: tsConfig.compilerOptions?.verbatimModuleSyntax,
|
|
1686
|
+
allowArbitraryExtensions: tsConfig.compilerOptions?.allowArbitraryExtensions,
|
|
1687
|
+
strict: tsConfig.compilerOptions?.strict,
|
|
1688
|
+
noUncheckedIndexedAccess: tsConfig.compilerOptions?.noUncheckedIndexedAccess,
|
|
1689
|
+
forceConsistentCasingInFileNames: tsConfig.compilerOptions?.forceConsistentCasingInFileNames,
|
|
1690
|
+
noImplicitOverride: tsConfig.compilerOptions?.noImplicitOverride,
|
|
1691
|
+
module: tsConfig.compilerOptions?.module,
|
|
1692
|
+
noEmit: true,
|
|
1693
|
+
types: [],
|
|
1694
|
+
paths: {},
|
|
1695
|
+
moduleResolution: tsConfig.compilerOptions?.moduleResolution,
|
|
1696
|
+
useDefineForClassFields: tsConfig.compilerOptions?.useDefineForClassFields,
|
|
1697
|
+
noImplicitThis: tsConfig.compilerOptions?.noImplicitThis,
|
|
1698
|
+
allowSyntheticDefaultImports: tsConfig.compilerOptions?.allowSyntheticDefaultImports
|
|
1699
|
+
},
|
|
1700
|
+
include: [...nodeInclude],
|
|
1701
|
+
exclude: [...nodeExclude]
|
|
1702
|
+
});
|
|
1703
|
+
const sharedTsConfig = defu(nuxt.options.typescript?.sharedTsConfig, {
|
|
1704
|
+
compilerOptions: {
|
|
1705
|
+
esModuleInterop: tsConfig.compilerOptions?.esModuleInterop,
|
|
1706
|
+
skipLibCheck: tsConfig.compilerOptions?.skipLibCheck,
|
|
1707
|
+
target: tsConfig.compilerOptions?.target,
|
|
1708
|
+
allowJs: tsConfig.compilerOptions?.allowJs,
|
|
1709
|
+
resolveJsonModule: tsConfig.compilerOptions?.resolveJsonModule,
|
|
1710
|
+
moduleDetection: tsConfig.compilerOptions?.moduleDetection,
|
|
1711
|
+
isolatedModules: tsConfig.compilerOptions?.isolatedModules,
|
|
1712
|
+
verbatimModuleSyntax: tsConfig.compilerOptions?.verbatimModuleSyntax,
|
|
1713
|
+
allowArbitraryExtensions: tsConfig.compilerOptions?.allowArbitraryExtensions,
|
|
1714
|
+
strict: tsConfig.compilerOptions?.strict,
|
|
1715
|
+
noUncheckedIndexedAccess: tsConfig.compilerOptions?.noUncheckedIndexedAccess,
|
|
1716
|
+
forceConsistentCasingInFileNames: tsConfig.compilerOptions?.forceConsistentCasingInFileNames,
|
|
1717
|
+
noImplicitOverride: tsConfig.compilerOptions?.noImplicitOverride,
|
|
1718
|
+
module: tsConfig.compilerOptions?.module,
|
|
1719
|
+
noEmit: true,
|
|
1720
|
+
types: [],
|
|
1721
|
+
paths: {},
|
|
1722
|
+
moduleResolution: tsConfig.compilerOptions?.moduleResolution,
|
|
1723
|
+
useDefineForClassFields: tsConfig.compilerOptions?.useDefineForClassFields,
|
|
1724
|
+
noImplicitThis: tsConfig.compilerOptions?.noImplicitThis,
|
|
1725
|
+
allowSyntheticDefaultImports: tsConfig.compilerOptions?.allowSyntheticDefaultImports
|
|
1726
|
+
},
|
|
1727
|
+
include: [...sharedInclude],
|
|
1728
|
+
exclude: [...sharedExclude]
|
|
1729
|
+
});
|
|
1730
|
+
const aliases = nuxt.options.alias;
|
|
1731
|
+
const basePath = tsConfig.compilerOptions.baseUrl ? resolve(nuxt.options.buildDir, tsConfig.compilerOptions.baseUrl) : nuxt.options.buildDir;
|
|
1732
|
+
tsConfig.compilerOptions ||= {};
|
|
1733
|
+
tsConfig.compilerOptions.paths ||= {};
|
|
1734
|
+
tsConfig.include ||= [];
|
|
1735
|
+
const importPaths = nuxt.options.modulesDir.map((d) => directoryToURL(d));
|
|
1736
|
+
for (const alias in aliases) {
|
|
1737
|
+
if (excludedAlias.some((re) => re.test(alias))) continue;
|
|
1738
|
+
let absolutePath = resolve(basePath, aliases[alias]);
|
|
1739
|
+
let stats = await promises.stat(absolutePath).catch(() => null);
|
|
1740
|
+
if (!stats) {
|
|
1741
|
+
const resolvedModule = resolveModulePath(aliases[alias], {
|
|
1742
|
+
try: true,
|
|
1743
|
+
from: importPaths,
|
|
1744
|
+
extensions: [
|
|
1745
|
+
...nuxt.options.extensions,
|
|
1746
|
+
".d.ts",
|
|
1747
|
+
".d.mts",
|
|
1748
|
+
".d.cts"
|
|
1749
|
+
]
|
|
1750
|
+
});
|
|
1751
|
+
if (resolvedModule) {
|
|
1752
|
+
absolutePath = resolvedModule;
|
|
1753
|
+
stats = await promises.stat(resolvedModule).catch(() => null);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
const relativePath = relativeWithDot(nuxt.options.buildDir, absolutePath);
|
|
1757
|
+
if (stats?.isDirectory() || aliases[alias].endsWith("/")) {
|
|
1758
|
+
tsConfig.compilerOptions.paths[alias] = [relativePath];
|
|
1759
|
+
tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`];
|
|
1760
|
+
} else {
|
|
1761
|
+
const path = stats?.isFile() ? relativePath.replace(EXTENSION_RE, "") : aliases[alias];
|
|
1762
|
+
tsConfig.compilerOptions.paths[alias] = [path];
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
const references = [];
|
|
1766
|
+
const nodeReferences = [];
|
|
1767
|
+
const sharedReferences = [];
|
|
1768
|
+
await Promise.all([...nuxt.options.modules, ...nuxt.options._modules].map(async (id) => {
|
|
1769
|
+
if (typeof id !== "string") return;
|
|
1770
|
+
for (const parent of nestedModulesDirs) {
|
|
1771
|
+
const pkg = await readPackageJSON(id, { parent }).catch(() => null);
|
|
1772
|
+
if (pkg) {
|
|
1773
|
+
nodeReferences.push({ types: pkg.name ?? id });
|
|
1774
|
+
references.push({ types: pkg.name ?? id });
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
nodeReferences.push({ types: id });
|
|
1779
|
+
references.push({ types: id });
|
|
1780
|
+
}));
|
|
1781
|
+
const declarations = [];
|
|
1782
|
+
await nuxt.callHook("prepare:types", {
|
|
1783
|
+
references,
|
|
1784
|
+
declarations,
|
|
1785
|
+
tsConfig,
|
|
1786
|
+
nodeTsConfig,
|
|
1787
|
+
nodeReferences,
|
|
1788
|
+
sharedTsConfig,
|
|
1789
|
+
sharedReferences
|
|
1790
|
+
});
|
|
1791
|
+
const legacyTsConfig = defu({}, {
|
|
1792
|
+
...tsConfig,
|
|
1793
|
+
include: [...tsConfig.include, ...legacyInclude],
|
|
1794
|
+
exclude: [...legacyExclude]
|
|
1795
|
+
});
|
|
1796
|
+
async function resolveConfig(tsConfig) {
|
|
1797
|
+
for (const alias in tsConfig.compilerOptions.paths) {
|
|
1798
|
+
const paths = tsConfig.compilerOptions.paths[alias];
|
|
1799
|
+
tsConfig.compilerOptions.paths[alias] = [...new Set(await Promise.all(paths.map(async (path) => {
|
|
1800
|
+
if (!isAbsolute(path)) return path;
|
|
1801
|
+
const stats = await promises.stat(path).catch(() => null);
|
|
1802
|
+
return relativeWithDot(nuxt.options.buildDir, stats?.isFile() ? path.replace(EXTENSION_RE, "") : path);
|
|
1803
|
+
})))];
|
|
1804
|
+
}
|
|
1805
|
+
sortTsPaths(tsConfig.compilerOptions.paths);
|
|
1806
|
+
tsConfig.include = [...new Set(tsConfig.include.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))];
|
|
1807
|
+
tsConfig.exclude = [...new Set(tsConfig.exclude.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))];
|
|
1808
|
+
}
|
|
1809
|
+
await Promise.all([
|
|
1810
|
+
resolveConfig(tsConfig),
|
|
1811
|
+
resolveConfig(nodeTsConfig),
|
|
1812
|
+
resolveConfig(sharedTsConfig),
|
|
1813
|
+
resolveConfig(legacyTsConfig)
|
|
1814
|
+
]);
|
|
1815
|
+
const declaration = [
|
|
1816
|
+
...references.map((ref) => renderReference(ref, nuxt.options.buildDir)),
|
|
1817
|
+
...declarations,
|
|
1818
|
+
"",
|
|
1819
|
+
"export {}",
|
|
1820
|
+
""
|
|
1821
|
+
].join("\n");
|
|
1822
|
+
const nodeDeclaration = [
|
|
1823
|
+
...nodeReferences.map((ref) => renderReference(ref, nuxt.options.buildDir)),
|
|
1824
|
+
"",
|
|
1825
|
+
"export {}",
|
|
1826
|
+
""
|
|
1827
|
+
].join("\n");
|
|
1828
|
+
return {
|
|
1829
|
+
declaration,
|
|
1830
|
+
sharedTsConfig,
|
|
1831
|
+
sharedDeclaration: [
|
|
1832
|
+
...sharedReferences.map((ref) => renderReference(ref, nuxt.options.buildDir)),
|
|
1833
|
+
"",
|
|
1834
|
+
"export {}",
|
|
1835
|
+
""
|
|
1836
|
+
].join("\n"),
|
|
1837
|
+
nodeTsConfig,
|
|
1838
|
+
nodeDeclaration,
|
|
1839
|
+
tsConfig,
|
|
1840
|
+
legacyTsConfig
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
async function writeTypes(nuxt) {
|
|
1844
|
+
const { tsConfig, nodeTsConfig, nodeDeclaration, declaration, legacyTsConfig, sharedDeclaration, sharedTsConfig } = await _generateTypes(nuxt);
|
|
1845
|
+
const appTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.app.json");
|
|
1846
|
+
const legacyTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.json");
|
|
1847
|
+
const nodeTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.node.json");
|
|
1848
|
+
const sharedTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.shared.json");
|
|
1849
|
+
const declarationPath = resolve(nuxt.options.buildDir, "nuxt.d.ts");
|
|
1850
|
+
const nodeDeclarationPath = resolve(nuxt.options.buildDir, "nuxt.node.d.ts");
|
|
1851
|
+
const sharedDeclarationPath = resolve(nuxt.options.buildDir, "nuxt.shared.d.ts");
|
|
1852
|
+
await promises.mkdir(nuxt.options.buildDir, { recursive: true });
|
|
1853
|
+
await Promise.all([
|
|
1854
|
+
promises.writeFile(appTsConfigPath, JSON.stringify(tsConfig, null, 2)),
|
|
1855
|
+
promises.writeFile(legacyTsConfigPath, JSON.stringify(legacyTsConfig, null, 2)),
|
|
1856
|
+
promises.writeFile(nodeTsConfigPath, JSON.stringify(nodeTsConfig, null, 2)),
|
|
1857
|
+
promises.writeFile(sharedTsConfigPath, JSON.stringify(sharedTsConfig, null, 2)),
|
|
1858
|
+
promises.writeFile(declarationPath, declaration),
|
|
1859
|
+
promises.writeFile(nodeDeclarationPath, nodeDeclaration),
|
|
1860
|
+
promises.writeFile(sharedDeclarationPath, sharedDeclaration)
|
|
1861
|
+
]);
|
|
1862
|
+
}
|
|
1863
|
+
function sortTsPaths(paths) {
|
|
1864
|
+
for (const pathKey in paths) if (pathKey.startsWith("#build")) {
|
|
1865
|
+
const pathValue = paths[pathKey];
|
|
1866
|
+
delete paths[pathKey];
|
|
1867
|
+
paths[pathKey] = pathValue;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
function renderReference(ref, baseDir) {
|
|
1871
|
+
return `/// <reference ${"path" in ref ? `path="${isAbsolute(ref.path) ? relative(baseDir, ref.path) : ref.path}"` : `types="${ref.types}"`} />`;
|
|
1872
|
+
}
|
|
1873
|
+
const RELATIVE_WITH_DOT_RE = /^([^.])/;
|
|
1874
|
+
function relativeWithDot(from, to) {
|
|
1875
|
+
return relative(from, to).replace(RELATIVE_WITH_DOT_RE, "./$1") || ".";
|
|
1876
|
+
}
|
|
1877
|
+
function withTrailingSlash$1(dir) {
|
|
1878
|
+
return dir.replace(/[^/]$/, "$&/");
|
|
1879
|
+
}
|
|
1880
|
+
//#endregion
|
|
1881
|
+
//#region src/layout.ts
|
|
1882
|
+
const LAYOUT_RE = /["']/g;
|
|
1883
|
+
function addLayout(template, name) {
|
|
1884
|
+
const nuxt = useNuxt();
|
|
1885
|
+
const { filename, src } = addTemplate(template);
|
|
1886
|
+
const layoutName = kebabCase(name || parse(filename).name).replace(LAYOUT_RE, "");
|
|
1887
|
+
nuxt.hook("app:templates", (app) => {
|
|
1888
|
+
if (layoutName in app.layouts) {
|
|
1889
|
+
const relativePath = reverseResolveAlias(app.layouts[layoutName].file, {
|
|
1890
|
+
...nuxt?.options.alias || {},
|
|
1891
|
+
...strippedAtAliases
|
|
1892
|
+
}).pop() || app.layouts[layoutName].file;
|
|
1893
|
+
return logger.warn(`Not overriding \`${layoutName}\` (provided by \`${relativePath}\`) with \`${src || filename}\`.`);
|
|
1894
|
+
}
|
|
1895
|
+
app.layouts[layoutName] = {
|
|
1896
|
+
file: join("#build", filename),
|
|
1897
|
+
name: layoutName
|
|
1898
|
+
};
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
const strippedAtAliases = {
|
|
1902
|
+
"@": "",
|
|
1903
|
+
"@@": ""
|
|
1904
|
+
};
|
|
1905
|
+
//#endregion
|
|
1906
|
+
//#region src/pages.ts
|
|
1907
|
+
function extendPages(cb) {
|
|
1908
|
+
useNuxt().hook("pages:extend", cb);
|
|
1909
|
+
}
|
|
1910
|
+
function extendRouteRules(route, rule, options = {}) {
|
|
1911
|
+
const nuxt = useNuxt();
|
|
1912
|
+
for (const opts of [nuxt.options, nuxt.options.nitro]) {
|
|
1913
|
+
opts.routeRules ||= {};
|
|
1914
|
+
opts.routeRules[route] = options.override ? defu(rule, opts.routeRules[route]) : defu(opts.routeRules[route], rule);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
function addRouteMiddleware(input, options = {}) {
|
|
1918
|
+
const nuxt = useNuxt();
|
|
1919
|
+
const middlewares = toArray(input);
|
|
1920
|
+
nuxt.hook("app:resolve", (app) => {
|
|
1921
|
+
for (const middleware of middlewares) {
|
|
1922
|
+
const find = app.middleware.findIndex((item) => item.name === middleware.name);
|
|
1923
|
+
if (find >= 0) {
|
|
1924
|
+
const foundPath = app.middleware[find].path;
|
|
1925
|
+
if (foundPath === middleware.path) continue;
|
|
1926
|
+
if (options.override === true) app.middleware[find] = { ...middleware };
|
|
1927
|
+
else logger.warn(`'${middleware.name}' middleware already exists at '${foundPath}'. You can set \`override: true\` to replace it.`);
|
|
1928
|
+
} else if (options.prepend === true) app.middleware.unshift({ ...middleware });
|
|
1929
|
+
else app.middleware.push({ ...middleware });
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
//#endregion
|
|
1934
|
+
//#region src/plugin.ts
|
|
1935
|
+
/**
|
|
1936
|
+
* Normalize a nuxt plugin object
|
|
1937
|
+
*/
|
|
1938
|
+
const pluginSymbol = Symbol.for("nuxt plugin");
|
|
1939
|
+
function normalizePlugin(plugin) {
|
|
1940
|
+
if (typeof plugin === "string") plugin = { src: plugin };
|
|
1941
|
+
else plugin = { ...plugin };
|
|
1942
|
+
if (pluginSymbol in plugin) return plugin;
|
|
1943
|
+
if (!plugin.src) throw new Error("Invalid plugin. src option is required: " + JSON.stringify(plugin));
|
|
1944
|
+
plugin.src = normalize(resolveAlias(plugin.src));
|
|
1945
|
+
if (!existsSync(plugin.src) && isAbsolute$1(plugin.src)) try {
|
|
1946
|
+
plugin.src = resolveModulePath(plugin.src, { extensions: tryUseNuxt()?.options.extensions ?? [
|
|
1947
|
+
".js",
|
|
1948
|
+
".mjs",
|
|
1949
|
+
".cjs",
|
|
1950
|
+
".ts",
|
|
1951
|
+
".tsx",
|
|
1952
|
+
".mts",
|
|
1953
|
+
".cts"
|
|
1954
|
+
] });
|
|
1955
|
+
} catch {}
|
|
1956
|
+
if (plugin.ssr) plugin.mode = "server";
|
|
1957
|
+
if (!plugin.mode) {
|
|
1958
|
+
const [, mode = "all"] = plugin.src.match(MODE_RE) || [];
|
|
1959
|
+
plugin.mode = mode;
|
|
1960
|
+
}
|
|
1961
|
+
plugin[pluginSymbol] = true;
|
|
1962
|
+
return plugin;
|
|
1963
|
+
}
|
|
1964
|
+
function addPlugin(_plugin, opts = {}) {
|
|
1965
|
+
const nuxt = useNuxt();
|
|
1966
|
+
const plugin = normalizePlugin(_plugin);
|
|
1967
|
+
filterInPlace(nuxt.options.plugins, (p) => normalizePlugin(p).src !== plugin.src);
|
|
1968
|
+
nuxt.options.plugins[opts.append ? "push" : "unshift"](plugin);
|
|
1969
|
+
return plugin;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Adds a template and registers as a nuxt plugin.
|
|
1973
|
+
*/
|
|
1974
|
+
function addPluginTemplate(plugin, opts = {}) {
|
|
1975
|
+
return addPlugin(typeof plugin === "string" ? { src: plugin } : {
|
|
1976
|
+
...plugin,
|
|
1977
|
+
src: addTemplate(plugin).dst
|
|
1978
|
+
}, opts);
|
|
1979
|
+
}
|
|
1980
|
+
//#endregion
|
|
1981
|
+
export { addBuildPlugin, addComponent, addComponentExports, addComponentsDir, addDevServerHandler, addImports, addImportsDir, addImportsSources, addLayout, addPlugin, addPluginTemplate, addPrerenderRoutes, addRouteMiddleware, addRspackPlugin, addServerHandler, addServerImports, addServerImportsDir, addServerPlugin, addServerScanDir, addServerTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, assertNuxtCompatibility, buildNuxt, checkNuxtCompatibility, createIsIgnored, createResolver, defineNuxtModule, directoryToURL, extendNuxtSchema, extendPages, extendRouteRules, extendRspackConfig, extendViteConfig, extendWebpackConfig, findPath, getDirectory, getLayerDirectories, getNuxtCtx, getNuxtModuleVersion, getNuxtVersion, hasNuxtCompatibility, hasNuxtModule, hasNuxtModuleCompatibility, importModule, installModule, installModules, isIgnored, isNuxt2, isNuxt3, isNuxtMajorVersion, loadNuxt, loadNuxtConfig, loadNuxtModuleInstance, logger, normalizeModuleTranspilePath, normalizePlugin, normalizeSemanticVersion, normalizeTemplate, nuxtCtx, requireModule, resolveAlias, resolveFiles, resolveIgnorePatterns, resolveModule, resolveModuleWithOptions, resolveNuxtModule, resolvePath, runWithNuxtContext, setGlobalHead, tryImportModule, tryRequireModule, tryResolveModule, tryUseNuxt, updateRuntimeConfig, updateTemplates, useLogger, useNitro, useNuxt, useRuntimeConfig, writeTypes };
|