You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
12 KiB
396 lines
12 KiB
2 years ago
|
import { createRequire } from 'node:module';
|
||
|
import { dirname } from 'node:path';
|
||
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
||
|
import vm from 'node:vm';
|
||
|
import { isNodeBuiltin } from 'mlly';
|
||
|
import { resolve } from 'pathe';
|
||
|
import createDebug from 'debug';
|
||
|
import { normalizeModuleId, slash, isInternalRequest, VALID_ID_PREFIX, normalizeRequestId, toFilePath, cleanUrl, isPrimitive } from './utils.mjs';
|
||
|
import { extractSourceMap } from './source-map.mjs';
|
||
|
import 'node:fs';
|
||
|
import 'source-map-support';
|
||
|
|
||
|
const debugExecute = createDebug("vite-node:client:execute");
|
||
|
const debugNative = createDebug("vite-node:client:native");
|
||
|
const clientStub = {
|
||
|
injectQuery: (id) => id,
|
||
|
createHotContext() {
|
||
|
return {
|
||
|
accept: () => {
|
||
|
},
|
||
|
prune: () => {
|
||
|
},
|
||
|
dispose: () => {
|
||
|
},
|
||
|
decline: () => {
|
||
|
},
|
||
|
invalidate: () => {
|
||
|
},
|
||
|
on: () => {
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
updateStyle(id, css) {
|
||
|
if (typeof document === "undefined")
|
||
|
return;
|
||
|
const element = document.getElementById(id);
|
||
|
if (element)
|
||
|
element.remove();
|
||
|
const head = document.querySelector("head");
|
||
|
const style = document.createElement("style");
|
||
|
style.setAttribute("type", "text/css");
|
||
|
style.id = id;
|
||
|
style.innerHTML = css;
|
||
|
head == null ? void 0 : head.appendChild(style);
|
||
|
}
|
||
|
};
|
||
|
const DEFAULT_REQUEST_STUBS = {
|
||
|
"/@vite/client": clientStub,
|
||
|
"@vite/client": clientStub
|
||
|
};
|
||
|
class ModuleCacheMap extends Map {
|
||
|
normalizePath(fsPath) {
|
||
|
return normalizeModuleId(fsPath);
|
||
|
}
|
||
|
update(fsPath, mod) {
|
||
|
fsPath = this.normalizePath(fsPath);
|
||
|
if (!super.has(fsPath))
|
||
|
super.set(fsPath, mod);
|
||
|
else
|
||
|
Object.assign(super.get(fsPath), mod);
|
||
|
return this;
|
||
|
}
|
||
|
setByModuleId(modulePath, mod) {
|
||
|
return super.set(modulePath, mod);
|
||
|
}
|
||
|
set(fsPath, mod) {
|
||
|
return this.setByModuleId(this.normalizePath(fsPath), mod);
|
||
|
}
|
||
|
getByModuleId(modulePath) {
|
||
|
if (!super.has(modulePath))
|
||
|
super.set(modulePath, {});
|
||
|
return super.get(modulePath);
|
||
|
}
|
||
|
get(fsPath) {
|
||
|
return this.getByModuleId(this.normalizePath(fsPath));
|
||
|
}
|
||
|
deleteByModuleId(modulePath) {
|
||
|
return super.delete(modulePath);
|
||
|
}
|
||
|
delete(fsPath) {
|
||
|
return this.deleteByModuleId(this.normalizePath(fsPath));
|
||
|
}
|
||
|
invalidateDepTree(ids, invalidated = /* @__PURE__ */ new Set()) {
|
||
|
for (const _id of ids) {
|
||
|
const id = this.normalizePath(_id);
|
||
|
if (invalidated.has(id))
|
||
|
continue;
|
||
|
invalidated.add(id);
|
||
|
const mod = super.get(id);
|
||
|
if (mod == null ? void 0 : mod.importers)
|
||
|
this.invalidateDepTree(mod.importers, invalidated);
|
||
|
super.delete(id);
|
||
|
}
|
||
|
return invalidated;
|
||
|
}
|
||
|
invalidateSubDepTree(ids, invalidated = /* @__PURE__ */ new Set()) {
|
||
|
for (const _id of ids) {
|
||
|
const id = this.normalizePath(_id);
|
||
|
if (invalidated.has(id))
|
||
|
continue;
|
||
|
invalidated.add(id);
|
||
|
const subIds = Array.from(super.entries()).filter(([, mod]) => {
|
||
|
var _a;
|
||
|
return (_a = mod.importers) == null ? void 0 : _a.has(id);
|
||
|
}).map(([key]) => key);
|
||
|
subIds.length && this.invalidateSubDepTree(subIds, invalidated);
|
||
|
super.delete(id);
|
||
|
}
|
||
|
return invalidated;
|
||
|
}
|
||
|
getSourceMap(id) {
|
||
|
const cache = this.get(id);
|
||
|
if (cache.map)
|
||
|
return cache.map;
|
||
|
const map = cache.code && extractSourceMap(cache.code);
|
||
|
if (map) {
|
||
|
cache.map = map;
|
||
|
return map;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
class ViteNodeRunner {
|
||
|
constructor(options) {
|
||
|
this.options = options;
|
||
|
this.root = options.root ?? process.cwd();
|
||
|
this.moduleCache = options.moduleCache ?? new ModuleCacheMap();
|
||
|
this.debug = options.debug ?? (typeof process !== "undefined" ? !!process.env.VITE_NODE_DEBUG_RUNNER : false);
|
||
|
}
|
||
|
async executeFile(file) {
|
||
|
const url = `/@fs/${slash(resolve(file))}`;
|
||
|
return await this.cachedRequest(url, url, []);
|
||
|
}
|
||
|
async executeId(rawId) {
|
||
|
const [id, url] = await this.resolveUrl(rawId);
|
||
|
return await this.cachedRequest(id, url, []);
|
||
|
}
|
||
|
getSourceMap(id) {
|
||
|
return this.moduleCache.getSourceMap(id);
|
||
|
}
|
||
|
async cachedRequest(id, fsPath, callstack) {
|
||
|
const importee = callstack[callstack.length - 1];
|
||
|
const mod = this.moduleCache.get(fsPath);
|
||
|
if (!mod.importers)
|
||
|
mod.importers = /* @__PURE__ */ new Set();
|
||
|
if (importee)
|
||
|
mod.importers.add(importee);
|
||
|
if (callstack.includes(fsPath) && mod.exports)
|
||
|
return mod.exports;
|
||
|
if (mod.promise)
|
||
|
return mod.promise;
|
||
|
const promise = this.directRequest(id, fsPath, callstack);
|
||
|
Object.assign(mod, { promise, evaluated: false });
|
||
|
try {
|
||
|
return await promise;
|
||
|
} finally {
|
||
|
mod.evaluated = true;
|
||
|
}
|
||
|
}
|
||
|
shouldResolveId(id, _importee) {
|
||
|
return !isInternalRequest(id) && !isNodeBuiltin(id);
|
||
|
}
|
||
|
async _resolveUrl(id, importee) {
|
||
|
if (!this.shouldResolveId(id))
|
||
|
return [id, id];
|
||
|
if (importee && id.startsWith(VALID_ID_PREFIX))
|
||
|
importee = void 0;
|
||
|
id = normalizeRequestId(id, this.options.base);
|
||
|
if (!this.options.resolveId)
|
||
|
return [id, toFilePath(id, this.root)];
|
||
|
const resolved = await this.options.resolveId(id, importee);
|
||
|
const resolvedId = resolved ? normalizeRequestId(resolved.id, this.options.base) : id;
|
||
|
const fsPath = resolved ? resolvedId : toFilePath(id, this.root);
|
||
|
return [resolvedId, fsPath];
|
||
|
}
|
||
|
async resolveUrl(id, importee) {
|
||
|
const resolveKey = `resolve:${id}`;
|
||
|
this.moduleCache.setByModuleId(resolveKey, { resolving: true });
|
||
|
try {
|
||
|
return await this._resolveUrl(id, importee);
|
||
|
} finally {
|
||
|
this.moduleCache.deleteByModuleId(resolveKey);
|
||
|
}
|
||
|
}
|
||
|
async dependencyRequest(id, fsPath, callstack) {
|
||
|
var _a;
|
||
|
const getStack = () => {
|
||
|
return `stack:
|
||
|
${[...callstack, fsPath].reverse().map((p) => `- ${p}`).join("\n")}`;
|
||
|
};
|
||
|
let debugTimer;
|
||
|
if (this.debug)
|
||
|
debugTimer = setTimeout(() => console.warn(() => `module ${fsPath} takes over 2s to load.
|
||
|
${getStack()}`), 2e3);
|
||
|
try {
|
||
|
if (callstack.includes(fsPath)) {
|
||
|
const depExports = (_a = this.moduleCache.get(fsPath)) == null ? void 0 : _a.exports;
|
||
|
if (depExports)
|
||
|
return depExports;
|
||
|
throw new Error(`[vite-node] Failed to resolve circular dependency, ${getStack()}`);
|
||
|
}
|
||
|
return await this.cachedRequest(id, fsPath, callstack);
|
||
|
} finally {
|
||
|
if (debugTimer)
|
||
|
clearTimeout(debugTimer);
|
||
|
}
|
||
|
}
|
||
|
async directRequest(id, fsPath, _callstack) {
|
||
|
const moduleId = normalizeModuleId(fsPath);
|
||
|
const callstack = [..._callstack, moduleId];
|
||
|
const mod = this.moduleCache.getByModuleId(moduleId);
|
||
|
const request = async (dep) => {
|
||
|
const [id2, depFsPath] = await this.resolveUrl(dep, fsPath);
|
||
|
return this.dependencyRequest(id2, depFsPath, callstack);
|
||
|
};
|
||
|
const requestStubs = this.options.requestStubs || DEFAULT_REQUEST_STUBS;
|
||
|
if (id in requestStubs)
|
||
|
return requestStubs[id];
|
||
|
let { code: transformed, externalize } = await this.options.fetchModule(id);
|
||
|
if (externalize) {
|
||
|
debugNative(externalize);
|
||
|
const exports2 = await this.interopedImport(externalize);
|
||
|
mod.exports = exports2;
|
||
|
return exports2;
|
||
|
}
|
||
|
if (transformed == null)
|
||
|
throw new Error(`[vite-node] Failed to load "${id}" imported from ${callstack[callstack.length - 2]}`);
|
||
|
const modulePath = cleanUrl(moduleId);
|
||
|
const href = pathToFileURL(modulePath).href;
|
||
|
const meta = { url: href };
|
||
|
const exports = /* @__PURE__ */ Object.create(null);
|
||
|
Object.defineProperty(exports, Symbol.toStringTag, {
|
||
|
value: "Module",
|
||
|
enumerable: false,
|
||
|
configurable: false
|
||
|
});
|
||
|
const cjsExports = new Proxy(exports, {
|
||
|
set: (_, p, value) => {
|
||
|
if (p === "default" && this.shouldInterop(modulePath, { default: value })) {
|
||
|
exportAll(cjsExports, value);
|
||
|
exports.default = value;
|
||
|
return true;
|
||
|
}
|
||
|
if (!Reflect.has(exports, "default"))
|
||
|
exports.default = {};
|
||
|
if (isPrimitive(exports.default)) {
|
||
|
defineExport(exports, p, () => void 0);
|
||
|
return true;
|
||
|
}
|
||
|
exports.default[p] = value;
|
||
|
if (p !== "default")
|
||
|
defineExport(exports, p, () => value);
|
||
|
return true;
|
||
|
}
|
||
|
});
|
||
|
Object.assign(mod, { code: transformed, exports });
|
||
|
const __filename = fileURLToPath(href);
|
||
|
const moduleProxy = {
|
||
|
set exports(value) {
|
||
|
exportAll(cjsExports, value);
|
||
|
exports.default = value;
|
||
|
},
|
||
|
get exports() {
|
||
|
return cjsExports;
|
||
|
}
|
||
|
};
|
||
|
let hotContext;
|
||
|
if (this.options.createHotContext) {
|
||
|
Object.defineProperty(meta, "hot", {
|
||
|
enumerable: true,
|
||
|
get: () => {
|
||
|
var _a, _b;
|
||
|
hotContext || (hotContext = (_b = (_a = this.options).createHotContext) == null ? void 0 : _b.call(_a, this, `/@fs/${fsPath}`));
|
||
|
return hotContext;
|
||
|
},
|
||
|
set: (value) => {
|
||
|
hotContext = value;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
const context = this.prepareContext({
|
||
|
__vite_ssr_import__: request,
|
||
|
__vite_ssr_dynamic_import__: request,
|
||
|
__vite_ssr_exports__: exports,
|
||
|
__vite_ssr_exportAll__: (obj) => exportAll(exports, obj),
|
||
|
__vite_ssr_import_meta__: meta,
|
||
|
require: createRequire(href),
|
||
|
exports: cjsExports,
|
||
|
module: moduleProxy,
|
||
|
__filename,
|
||
|
__dirname: dirname(__filename)
|
||
|
});
|
||
|
debugExecute(__filename);
|
||
|
if (transformed[0] === "#")
|
||
|
transformed = transformed.replace(/^\#\!.*/, (s) => " ".repeat(s.length));
|
||
|
const codeDefinition = `'use strict';async (${Object.keys(context).join(",")})=>{{`;
|
||
|
const code = `${codeDefinition}${transformed}
|
||
|
}}`;
|
||
|
const fn = vm.runInThisContext(code, {
|
||
|
filename: __filename,
|
||
|
lineOffset: 0,
|
||
|
columnOffset: -codeDefinition.length
|
||
|
});
|
||
|
await fn(...Object.values(context));
|
||
|
return exports;
|
||
|
}
|
||
|
prepareContext(context) {
|
||
|
return context;
|
||
|
}
|
||
|
shouldInterop(path, mod) {
|
||
|
if (this.options.interopDefault === false)
|
||
|
return false;
|
||
|
return !path.endsWith(".mjs") && "default" in mod;
|
||
|
}
|
||
|
async interopedImport(path) {
|
||
|
const importedModule = await import(path);
|
||
|
if (!this.shouldInterop(path, importedModule))
|
||
|
return importedModule;
|
||
|
const { mod, defaultExport } = interopModule(importedModule);
|
||
|
const modKeys = Reflect.ownKeys(mod);
|
||
|
let defaultKeys = !isPrimitive(defaultExport) ? Reflect.ownKeys(defaultExport) : [];
|
||
|
if (typeof mod !== "function" && typeof defaultExport === "function") {
|
||
|
const reservedKeys = ["arguments", "caller", "prototype", "name", "length"];
|
||
|
defaultKeys = defaultKeys.filter((n) => typeof n === "string" && !reservedKeys.includes(n));
|
||
|
}
|
||
|
return new Proxy(mod, {
|
||
|
get(mod2, prop) {
|
||
|
if (prop === "default")
|
||
|
return defaultExport;
|
||
|
return mod2[prop] ?? (defaultExport == null ? void 0 : defaultExport[prop]);
|
||
|
},
|
||
|
has(mod2, prop) {
|
||
|
if (prop === "default")
|
||
|
return defaultExport !== void 0;
|
||
|
return prop in mod2 || defaultExport && prop in defaultExport;
|
||
|
},
|
||
|
ownKeys() {
|
||
|
if (!defaultExport || isPrimitive(defaultExport))
|
||
|
return modKeys;
|
||
|
const allKeys = [...modKeys, "default", ...defaultKeys];
|
||
|
return Array.from(new Set(allKeys));
|
||
|
},
|
||
|
getOwnPropertyDescriptor(mod2, prop) {
|
||
|
const descriptor = Reflect.getOwnPropertyDescriptor(mod2, prop);
|
||
|
if (descriptor)
|
||
|
return descriptor;
|
||
|
if (prop === "default" && defaultExport !== void 0) {
|
||
|
return {
|
||
|
value: defaultExport,
|
||
|
enumerable: true,
|
||
|
configurable: true
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
function interopModule(mod) {
|
||
|
if (isPrimitive(mod)) {
|
||
|
return {
|
||
|
mod: { default: mod },
|
||
|
defaultExport: mod
|
||
|
};
|
||
|
}
|
||
|
let defaultExport = "default" in mod ? mod.default : mod;
|
||
|
if (!isPrimitive(defaultExport) && "__esModule" in defaultExport) {
|
||
|
mod = defaultExport;
|
||
|
if ("default" in defaultExport)
|
||
|
defaultExport = defaultExport.default;
|
||
|
}
|
||
|
return { mod, defaultExport };
|
||
|
}
|
||
|
function defineExport(exports, key, value) {
|
||
|
Object.defineProperty(exports, key, {
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
get: value
|
||
|
});
|
||
|
}
|
||
|
function exportAll(exports, sourceModule) {
|
||
|
if (exports === sourceModule)
|
||
|
return;
|
||
|
if (isPrimitive(sourceModule) || Array.isArray(sourceModule))
|
||
|
return;
|
||
|
for (const key in sourceModule) {
|
||
|
if (key !== "default") {
|
||
|
try {
|
||
|
defineExport(exports, key, () => sourceModule[key]);
|
||
|
} catch (_err) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export { DEFAULT_REQUEST_STUBS, ModuleCacheMap, ViteNodeRunner };
|