'use strict'; const process = require('node:process'); const perfectDebounce = require('perfect-debounce'); const c = require('picocolors'); const sirv = require('sirv'); const dirs = require('../dirs.cjs'); const node_path = require('node:path'); const fs = require('fs-extra'); const node_buffer = require('node:buffer'); const pluginutils = require('@rollup/pluginutils'); const Debug = require('debug'); const errorStackParserEs = require('error-stack-parser-es'); const node_http = require('node:http'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const process__default = /*#__PURE__*/_interopDefaultCompat(process); const c__default = /*#__PURE__*/_interopDefaultCompat(c); const sirv__default = /*#__PURE__*/_interopDefaultCompat(sirv); const fs__default = /*#__PURE__*/_interopDefaultCompat(fs); const Debug__default = /*#__PURE__*/_interopDefaultCompat(Debug); const DEFAULT_TIMEOUT = 6e4; function defaultSerialize(i) { return i; } const defaultDeserialize = defaultSerialize; const { clearTimeout, setTimeout: setTimeout$1 } = globalThis; const random = Math.random.bind(Math); function createBirpc(functions, options) { const { post, on, off = () => { }, eventNames = [], serialize = defaultSerialize, deserialize = defaultDeserialize, resolver, bind = "rpc", timeout = DEFAULT_TIMEOUT } = options; const rpcPromiseMap = /* @__PURE__ */ new Map(); let _promise; let closed = false; const rpc = new Proxy({}, { get(_, method) { if (method === "$functions") return functions; if (method === "$close") return close; if (method === "then" && !eventNames.includes("then") && !("then" in functions)) return void 0; const sendEvent = (...args) => { post(serialize({ m: method, a: args, t: "q" })); }; if (eventNames.includes(method)) { sendEvent.asEvent = sendEvent; return sendEvent; } const sendCall = async (...args) => { if (closed) throw new Error(`[birpc] rpc is closed, cannot call "${method}"`); if (_promise) { try { await _promise; } finally { _promise = void 0; } } return new Promise((resolve, reject) => { const id = nanoid(); let timeoutId; if (timeout >= 0) { timeoutId = setTimeout$1(() => { try { options.onTimeoutError?.(method, args); throw new Error(`[birpc] timeout on calling "${method}"`); } catch (e) { reject(e); } rpcPromiseMap.delete(id); }, timeout); if (typeof timeoutId === "object") timeoutId = timeoutId.unref?.(); } rpcPromiseMap.set(id, { resolve, reject, timeoutId, method }); post(serialize({ m: method, a: args, i: id, t: "q" })); }); }; sendCall.asEvent = sendEvent; return sendCall; } }); function close() { closed = true; rpcPromiseMap.forEach(({ reject, method }) => { reject(new Error(`[birpc] rpc is closed, cannot call "${method}"`)); }); rpcPromiseMap.clear(); off(onMessage); } async function onMessage(data, ...extra) { const msg = deserialize(data); if (msg.t === "q") { const { m: method, a: args } = msg; let result, error; const fn = resolver ? resolver(method, functions[method]) : functions[method]; if (!fn) { error = new Error(`[birpc] function "${method}" not found`); } else { try { result = await fn.apply(bind === "rpc" ? rpc : functions, args); } catch (e) { error = e; } } if (msg.i) { if (error && options.onError) options.onError(error, method, args); post(serialize({ t: "s", i: msg.i, r: result, e: error }), ...extra); } } else { const { i: ack, r: result, e: error } = msg; const promise = rpcPromiseMap.get(ack); if (promise) { clearTimeout(promise.timeoutId); if (error) promise.reject(error); else promise.resolve(result); } rpcPromiseMap.delete(ack); } } _promise = on(onMessage); return rpc; } const cacheMap = /* @__PURE__ */ new WeakMap(); function cachedMap(items, fn) { return items.map((i) => { let r = cacheMap.get(i); if (!r) { r = fn(i); cacheMap.set(i, r); } return r; }); } function createBirpcGroup(functions, channels, options = {}) { const getChannels = () => typeof channels === "function" ? channels() : channels; const getClients = (channels2 = getChannels()) => cachedMap(channels2, (s) => createBirpc(functions, { ...options, ...s })); const broadcastProxy = new Proxy({}, { get(_, method) { const client = getClients(); const callbacks = client.map((c) => c[method]); const sendCall = (...args) => { return Promise.all(callbacks.map((i) => i(...args))); }; sendCall.asEvent = (...args) => { callbacks.map((i) => i.asEvent(...args)); }; return sendCall; } }); function updateChannels(fn) { const channels2 = getChannels(); fn?.(channels2); return getClients(channels2); } getClients(); return { get clients() { return getClients(); }, functions, updateChannels, broadcast: broadcastProxy, /** * @deprecated use `broadcast` */ // @ts-expect-error deprecated boardcast: broadcastProxy }; } const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; function nanoid(size = 21) { let id = ""; let i = size; while (i--) id += urlAlphabet[random() * 64 | 0]; return id; } function createRPCServer(name, ws, functions, options = {}) { const event = `${name}:rpc`; const group = createBirpcGroup( functions, () => cachedMap( Array.from(ws?.clients || []), (channel) => { if (channel.socket.readyState === channel.socket.CLOSED) return void 0; return { on: (fn) => { function handler(data, source) { if (!source.socket) throw new Error("source.socket is undefined"); if (channel.socket === source.socket) fn(data, source); } ws.on(event, handler); channel.socket.on("close", () => { ws.off(event, handler); }); }, post: (data) => { channel.send(event, data); } }; } ).filter((c) => !!c), options ); ws.on("connection", () => { group.updateChannels(); }); return group.broadcast; } const defaults = Object.freeze({ ignoreUnknown: false, respectType: false, respectFunctionNames: false, respectFunctionProperties: false, unorderedObjects: true, unorderedArrays: false, unorderedSets: false, excludeKeys: void 0, excludeValues: void 0, replacer: void 0 }); function objectHash(object, options) { if (options) { options = { ...defaults, ...options }; } else { options = defaults; } const hasher = createHasher(options); hasher.dispatch(object); return hasher.toString(); } const defaultPrototypesKeys = Object.freeze([ "prototype", "__proto__", "constructor" ]); function createHasher(options) { let buff = ""; let context = /* @__PURE__ */ new Map(); const write = (str) => { buff += str; }; return { toString() { return buff; }, getContext() { return context; }, dispatch(value) { if (options.replacer) { value = options.replacer(value); } const type = value === null ? "null" : typeof value; return this[type](value); }, object(object) { if (object && typeof object.toJSON === "function") { return this.object(object.toJSON()); } const objString = Object.prototype.toString.call(object); let objType = ""; const objectLength = objString.length; if (objectLength < 10) { objType = "unknown:[" + objString + "]"; } else { objType = objString.slice(8, objectLength - 1); } objType = objType.toLowerCase(); let objectNumber = null; if ((objectNumber = context.get(object)) === void 0) { context.set(object, context.size); } else { return this.dispatch("[CIRCULAR:" + objectNumber + "]"); } if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(object)) { write("buffer:"); return write(object.toString("utf8")); } if (objType !== "object" && objType !== "function" && objType !== "asyncfunction") { if (this[objType]) { this[objType](object); } else if (!options.ignoreUnknown) { this.unkown(object, objType); } } else { let keys = Object.keys(object); if (options.unorderedObjects) { keys = keys.sort(); } let extraKeys = []; if (options.respectType !== false && !isNativeFunction(object)) { extraKeys = defaultPrototypesKeys; } if (options.excludeKeys) { keys = keys.filter((key) => { return !options.excludeKeys(key); }); extraKeys = extraKeys.filter((key) => { return !options.excludeKeys(key); }); } write("object:" + (keys.length + extraKeys.length) + ":"); const dispatchForKey = (key) => { this.dispatch(key); write(":"); if (!options.excludeValues) { this.dispatch(object[key]); } write(","); }; for (const key of keys) { dispatchForKey(key); } for (const key of extraKeys) { dispatchForKey(key); } } }, array(arr, unordered) { unordered = unordered === void 0 ? options.unorderedArrays !== false : unordered; write("array:" + arr.length + ":"); if (!unordered || arr.length <= 1) { for (const entry of arr) { this.dispatch(entry); } return; } const contextAdditions = /* @__PURE__ */ new Map(); const entries = arr.map((entry) => { const hasher = createHasher(options); hasher.dispatch(entry); for (const [key, value] of hasher.getContext()) { contextAdditions.set(key, value); } return hasher.toString(); }); context = contextAdditions; entries.sort(); return this.array(entries, false); }, date(date) { return write("date:" + date.toJSON()); }, symbol(sym) { return write("symbol:" + sym.toString()); }, unkown(value, type) { write(type); if (!value) { return; } write(":"); if (value && typeof value.entries === "function") { return this.array( Array.from(value.entries()), true /* ordered */ ); } }, error(err) { return write("error:" + err.toString()); }, boolean(bool) { return write("bool:" + bool); }, string(string) { write("string:" + string.length + ":"); write(string); }, function(fn) { write("fn:"); if (isNativeFunction(fn)) { this.dispatch("[native]"); } else { this.dispatch(fn.toString()); } if (options.respectFunctionNames !== false) { this.dispatch("function-name:" + String(fn.name)); } if (options.respectFunctionProperties) { this.object(fn); } }, number(number) { return write("number:" + number); }, xml(xml) { return write("xml:" + xml.toString()); }, null() { return write("Null"); }, undefined() { return write("Undefined"); }, regexp(regex) { return write("regex:" + regex.toString()); }, uint8array(arr) { write("uint8array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint8clampedarray(arr) { write("uint8clampedarray:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int8array(arr) { write("int8array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint16array(arr) { write("uint16array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int16array(arr) { write("int16array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint32array(arr) { write("uint32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int32array(arr) { write("int32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, float32array(arr) { write("float32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, float64array(arr) { write("float64array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, arraybuffer(arr) { write("arraybuffer:"); return this.dispatch(new Uint8Array(arr)); }, url(url) { return write("url:" + url.toString()); }, map(map) { write("map:"); const arr = [...map]; return this.array(arr, options.unorderedSets !== false); }, set(set) { write("set:"); const arr = [...set]; return this.array(arr, options.unorderedSets !== false); }, file(file) { write("file:"); return this.dispatch([file.name, file.size, file.type, file.lastModfied]); }, blob() { if (options.ignoreUnknown) { return write("[blob]"); } throw new Error( 'Hashing Blob objects is currently not supported\nUse "options.replacer" or "options.ignoreUnknown"\n' ); }, domwindow() { return write("domwindow"); }, bigint(number) { return write("bigint:" + number.toString()); }, /* Node.js standard native objects */ process() { return write("process"); }, timer() { return write("timer"); }, pipe() { return write("pipe"); }, tcp() { return write("tcp"); }, udp() { return write("udp"); }, tty() { return write("tty"); }, statwatcher() { return write("statwatcher"); }, securecontext() { return write("securecontext"); }, connection() { return write("connection"); }, zlib() { return write("zlib"); }, context() { return write("context"); }, nodescript() { return write("nodescript"); }, httpparser() { return write("httpparser"); }, dataview() { return write("dataview"); }, signal() { return write("signal"); }, fsevent() { return write("fsevent"); }, tlswrap() { return write("tlswrap"); } }; } const nativeFunc = "[native code] }"; const nativeFuncLength = nativeFunc.length; function isNativeFunction(f) { if (typeof f !== "function") { return false; } return Function.prototype.toString.call(f).slice(-nativeFuncLength) === nativeFunc; } var __defProp$1 = Object.defineProperty; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => { __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class WordArray { constructor(words, sigBytes) { __publicField$1(this, "words"); __publicField$1(this, "sigBytes"); words = this.words = words || []; this.sigBytes = sigBytes === void 0 ? words.length * 4 : sigBytes; } toString(encoder) { return (encoder || Hex).stringify(this); } concat(wordArray) { this.clamp(); if (this.sigBytes % 4) { for (let i = 0; i < wordArray.sigBytes; i++) { const thatByte = wordArray.words[i >>> 2] >>> 24 - i % 4 * 8 & 255; this.words[this.sigBytes + i >>> 2] |= thatByte << 24 - (this.sigBytes + i) % 4 * 8; } } else { for (let j = 0; j < wordArray.sigBytes; j += 4) { this.words[this.sigBytes + j >>> 2] = wordArray.words[j >>> 2]; } } this.sigBytes += wordArray.sigBytes; return this; } clamp() { this.words[this.sigBytes >>> 2] &= 4294967295 << 32 - this.sigBytes % 4 * 8; this.words.length = Math.ceil(this.sigBytes / 4); } clone() { return new WordArray([...this.words]); } } const Hex = { stringify(wordArray) { const hexChars = []; for (let i = 0; i < wordArray.sigBytes; i++) { const bite = wordArray.words[i >>> 2] >>> 24 - i % 4 * 8 & 255; hexChars.push((bite >>> 4).toString(16), (bite & 15).toString(16)); } return hexChars.join(""); } }; const Base64 = { stringify(wordArray) { const keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; const base64Chars = []; for (let i = 0; i < wordArray.sigBytes; i += 3) { const byte1 = wordArray.words[i >>> 2] >>> 24 - i % 4 * 8 & 255; const byte2 = wordArray.words[i + 1 >>> 2] >>> 24 - (i + 1) % 4 * 8 & 255; const byte3 = wordArray.words[i + 2 >>> 2] >>> 24 - (i + 2) % 4 * 8 & 255; const triplet = byte1 << 16 | byte2 << 8 | byte3; for (let j = 0; j < 4 && i * 8 + j * 6 < wordArray.sigBytes * 8; j++) { base64Chars.push(keyStr.charAt(triplet >>> 6 * (3 - j) & 63)); } } return base64Chars.join(""); } }; const Latin1 = { parse(latin1Str) { const latin1StrLength = latin1Str.length; const words = []; for (let i = 0; i < latin1StrLength; i++) { words[i >>> 2] |= (latin1Str.charCodeAt(i) & 255) << 24 - i % 4 * 8; } return new WordArray(words, latin1StrLength); } }; const Utf8 = { parse(utf8Str) { return Latin1.parse(unescape(encodeURIComponent(utf8Str))); } }; class BufferedBlockAlgorithm { constructor() { __publicField$1(this, "_data", new WordArray()); __publicField$1(this, "_nDataBytes", 0); __publicField$1(this, "_minBufferSize", 0); __publicField$1(this, "blockSize", 512 / 32); } reset() { this._data = new WordArray(); this._nDataBytes = 0; } _append(data) { if (typeof data === "string") { data = Utf8.parse(data); } this._data.concat(data); this._nDataBytes += data.sigBytes; } _doProcessBlock(_dataWords, _offset) { } _process(doFlush) { let processedWords; let nBlocksReady = this._data.sigBytes / (this.blockSize * 4); if (doFlush) { nBlocksReady = Math.ceil(nBlocksReady); } else { nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); } const nWordsReady = nBlocksReady * this.blockSize; const nBytesReady = Math.min(nWordsReady * 4, this._data.sigBytes); if (nWordsReady) { for (let offset = 0; offset < nWordsReady; offset += this.blockSize) { this._doProcessBlock(this._data.words, offset); } processedWords = this._data.words.splice(0, nWordsReady); this._data.sigBytes -= nBytesReady; } return new WordArray(processedWords, nBytesReady); } } class Hasher extends BufferedBlockAlgorithm { update(messageUpdate) { this._append(messageUpdate); this._process(); return this; } finalize(messageUpdate) { if (messageUpdate) { this._append(messageUpdate); } } } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, key + "" , value); return value; }; const H = [ 1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225 ]; const K = [ 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998 ]; const W = []; class SHA256 extends Hasher { constructor() { super(...arguments); __publicField(this, "_hash", new WordArray([...H])); } /** * Resets the internal state of the hash object to initial values. */ reset() { super.reset(); this._hash = new WordArray([...H]); } _doProcessBlock(M, offset) { const H2 = this._hash.words; let a = H2[0]; let b = H2[1]; let c = H2[2]; let d = H2[3]; let e = H2[4]; let f = H2[5]; let g = H2[6]; let h = H2[7]; for (let i = 0; i < 64; i++) { if (i < 16) { W[i] = M[offset + i] | 0; } else { const gamma0x = W[i - 15]; const gamma0 = (gamma0x << 25 | gamma0x >>> 7) ^ (gamma0x << 14 | gamma0x >>> 18) ^ gamma0x >>> 3; const gamma1x = W[i - 2]; const gamma1 = (gamma1x << 15 | gamma1x >>> 17) ^ (gamma1x << 13 | gamma1x >>> 19) ^ gamma1x >>> 10; W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; } const ch = e & f ^ ~e & g; const maj = a & b ^ a & c ^ b & c; const sigma0 = (a << 30 | a >>> 2) ^ (a << 19 | a >>> 13) ^ (a << 10 | a >>> 22); const sigma1 = (e << 26 | e >>> 6) ^ (e << 21 | e >>> 11) ^ (e << 7 | e >>> 25); const t1 = h + sigma1 + ch + K[i] + W[i]; const t2 = sigma0 + maj; h = g; g = f; f = e; e = d + t1 | 0; d = c; c = b; b = a; a = t1 + t2 | 0; } H2[0] = H2[0] + a | 0; H2[1] = H2[1] + b | 0; H2[2] = H2[2] + c | 0; H2[3] = H2[3] + d | 0; H2[4] = H2[4] + e | 0; H2[5] = H2[5] + f | 0; H2[6] = H2[6] + g | 0; H2[7] = H2[7] + h | 0; } /** * Finishes the hash calculation and returns the hash as a WordArray. * * @param {string} messageUpdate - Additional message content to include in the hash. * @returns {WordArray} The finalised hash as a WordArray. */ finalize(messageUpdate) { super.finalize(messageUpdate); const nBitsTotal = this._nDataBytes * 8; const nBitsLeft = this._data.sigBytes * 8; this._data.words[nBitsLeft >>> 5] |= 128 << 24 - nBitsLeft % 32; this._data.words[(nBitsLeft + 64 >>> 9 << 4) + 14] = Math.floor( nBitsTotal / 4294967296 ); this._data.words[(nBitsLeft + 64 >>> 9 << 4) + 15] = nBitsTotal; this._data.sigBytes = this._data.words.length * 4; this._process(); return this._hash; } } function sha256base64(message) { return new SHA256().finalize(message).toString(Base64); } function hash(object, options = {}) { const hashed = typeof object === "string" ? object : objectHash(object, options); return sha256base64(hashed).slice(0, 10); } async function generateBuild(ctx) { const { outputDir = ".vite-inspect" } = ctx.options; const targetDir = node_path.isAbsolute(outputDir) ? outputDir : node_path.resolve(process__default.cwd(), outputDir); const reportsDir = node_path.join(targetDir, "reports"); await fs__default.emptyDir(targetDir); await fs__default.ensureDir(reportsDir); await fs__default.copy(dirs.DIR_CLIENT, targetDir); await Promise.all([ fs__default.writeFile( node_path.join(targetDir, "index.html"), (await fs__default.readFile(node_path.join(targetDir, "index.html"), "utf-8")).replace( 'data-vite-inspect-mode="DEV"', 'data-vite-inspect-mode="BUILD"' ) ), fs__default.writeJSON( node_path.join(reportsDir, "metadata.json"), ctx.getMetadata(), { spaces: 2 } ), ...[...ctx._idToInstances.values()].flatMap( (v) => [...v.environments.values()].map((e) => { const key = `${v.id}-${e.env.name}`; return [key, e]; }) ).map(async ([key, env]) => { await fs__default.ensureDir(node_path.join(reportsDir, key)); await fs__default.ensureDir(node_path.join(reportsDir, key, "transforms")); return await Promise.all([ fs__default.writeJSON( node_path.join(reportsDir, key, "modules.json"), env.getModulesList(), { spaces: 2 } ), fs__default.writeJSON( node_path.join(reportsDir, key, "metric-plugins.json"), env.getPluginMetrics(), { spaces: 2 } ), ...Object.entries(env.data.transform).map(([id, info]) => fs__default.writeJSON( node_path.join(reportsDir, key, "transforms", `${hash(id)}.json`), { resolvedId: id, transforms: info }, { spaces: 2 } )) ]); }) ]); return targetDir; } const DUMMY_LOAD_PLUGIN_NAME = "__load__"; async function openBrowser(address) { await import('open').then((r) => r.default(address, { newInstance: true })).catch(() => { }); } function serializePlugin(plugin) { return JSON.parse(JSON.stringify(plugin, (key, value) => { if (typeof value === "function") { let name = value.name; if (name === "anonymous") name = ""; if (name === key) name = ""; if (name) return `[Function ${name}]`; return "[Function]"; } if (key === "api" && value) return "[Object API]"; return value; })); } function removeVersionQuery(url) { if (url.includes("v=")) { return url.replace(/&v=\w+/, "").replace(/\?v=\w+/, "?").replace(/\?$/, ""); } return url; } let viteCount = 0; class InspectContext { constructor(options) { this.options = options; this.filter = pluginutils.createFilter(options.include, options.exclude); } _configToInstances = /* @__PURE__ */ new Map(); _idToInstances = /* @__PURE__ */ new Map(); filter; getMetadata() { return { instances: [...this._idToInstances.values()].map((vite) => ({ root: vite.config.root, vite: vite.id, plugins: vite.config.plugins.map((i) => serializePlugin(i)), environments: [...vite.environments.keys()], environmentPlugins: Object.fromEntries( [...vite.environments.entries()].map(([name, env]) => { return [name, env.env.getTopLevelConfig().plugins.map((i) => vite.config.plugins.indexOf(i))]; }) ) })), embedded: this.options.embedded }; } getViteContext(configOrId) { if (typeof configOrId === "string") { if (!this._idToInstances.has(configOrId)) throw new Error(`Can not found vite context for ${configOrId}`); return this._idToInstances.get(configOrId); } if (this._configToInstances.has(configOrId)) return this._configToInstances.get(configOrId); const id = `vite${++viteCount}`; const vite = new InspectContextVite(id, this, configOrId); this._idToInstances.set(id, vite); this._configToInstances.set(configOrId, vite); return vite; } getEnvContext(env) { if (!env) return void 0; const vite = this.getViteContext(env.getTopLevelConfig()); return vite.getEnvContext(env); } queryEnv(query) { const vite = this.getViteContext(query.vite); const env = vite.getEnvContext(query.env); return env; } } class InspectContextVite { constructor(id, context, config) { this.id = id; this.context = context; this.config = config; } environments = /* @__PURE__ */ new Map(); data = { serverMetrics: { middleware: {} } }; getEnvContext(env) { if (typeof env === "string") { if (!this.environments.has(env)) throw new Error(`Can not found environment context for ${env}`); return this.environments.get(env); } if (env.getTopLevelConfig() !== this.config) throw new Error("Environment config does not match Vite config"); if (!this.environments.has(env.name)) this.environments.set(env.name, new InspectContextViteEnv(this.context, this, env)); return this.environments.get(env.name); } } class InspectContextViteEnv { constructor(contextMain, contextVite, env) { this.contextMain = contextMain; this.contextVite = contextVite; this.env = env; } data = { transform: {}, resolveId: {}, transformCounter: {} }; recordTransform(id, info, preTransformCode) { id = this.normalizeId(id); if (!this.data.transform[id] || !this.data.transform[id].some((tr) => tr.result)) { this.data.transform[id] = [{ name: DUMMY_LOAD_PLUGIN_NAME, result: preTransformCode, start: info.start, end: info.start, sourcemaps: info.sourcemaps }]; this.data.transformCounter[id] = (this.data.transformCounter[id] || 0) + 1; } this.data.transform[id].push(info); } recordLoad(id, info) { id = this.normalizeId(id); this.data.transform[id] = [info]; this.data.transformCounter[id] = (this.data.transformCounter[id] || 0) + 1; } recordResolveId(id, info) { id = this.normalizeId(id); if (!this.data.resolveId[id]) this.data.resolveId[id] = []; this.data.resolveId[id].push(info); } invalidate(id) { id = this.normalizeId(id); delete this.data.transform[id]; } normalizeId(id) { if (this.contextMain.options.removeVersionQuery !== false) return removeVersionQuery(id); return id; } getModulesList() { const moduleGraph = this.env.mode === "dev" ? this.env.moduleGraph : void 0; const getDeps = (id) => Array.from(moduleGraph?.getModuleById(id)?.importedModules || []).map((i) => i.id || "").filter(Boolean); const getImporters = (id) => Array.from(moduleGraph?.getModuleById(id)?.importers || []).map((i) => i.id || "").filter(Boolean); function isVirtual(pluginName, transformName) { return pluginName !== DUMMY_LOAD_PLUGIN_NAME && transformName !== "vite:load-fallback" && transformName !== "vite:build-load-fallback"; } const transformedIdMap = Object.values(this.data.resolveId).reduce((map, ids2) => { ids2.forEach((id) => { map[id.result] ??= []; map[id.result].push(id); }); return map; }, {}); const ids = new Set(Object.keys(this.data.transform).concat(Object.keys(transformedIdMap))); return Array.from(ids).sort().map((id) => { let totalTime = 0; const plugins = (this.data.transform[id] || []).filter((tr) => tr.result).map((transItem) => { const delta = transItem.end - transItem.start; totalTime += delta; return { name: transItem.name, transform: delta }; }).concat( // @ts-expect-error transform is optional (transformedIdMap[id] || []).map((idItem) => { return { name: idItem.name, resolveId: idItem.end - idItem.start }; }) ); function getSize(str) { if (!str) return 0; return node_buffer.Buffer.byteLength(str, "utf8"); } return { id, deps: getDeps(id), importers: getImporters(id), plugins, virtual: isVirtual(plugins[0]?.name || "", this.data.transform[id]?.[0].name || ""), totalTime, invokeCount: this.data.transformCounter?.[id] || 0, sourceSize: getSize(this.data.transform[id]?.[0]?.result), distSize: getSize(this.data.transform[id]?.[this.data.transform[id].length - 1]?.result) }; }); } resolveId(id = "", ssr = false) { if (id.startsWith("./")) id = node_path.resolve(this.env.getTopLevelConfig().root, id).replace(/\\/g, "/"); return this.resolveIdRecursive(id, ssr); } resolveIdRecursive(id, ssr = false) { const resolved = this.data.resolveId[id]?.[0]?.result; return resolved ? this.resolveIdRecursive(resolved, ssr) : id; } getPluginMetrics() { const map = {}; const defaultMetricInfo = () => ({ transform: { invokeCount: 0, totalTime: 0 }, resolveId: { invokeCount: 0, totalTime: 0 } }); this.env.getTopLevelConfig().plugins.forEach((i) => { map[i.name] = { ...defaultMetricInfo(), name: i.name, enforce: i.enforce }; }); Object.values(this.data.transform).forEach((transformInfos) => { transformInfos.forEach(({ name, start, end }) => { if (name === DUMMY_LOAD_PLUGIN_NAME) return; if (!map[name]) map[name] = { ...defaultMetricInfo(), name }; map[name].transform.totalTime += end - start; map[name].transform.invokeCount += 1; }); }); Object.values(this.data.resolveId).forEach((resolveIdInfos) => { resolveIdInfos.forEach(({ name, start, end }) => { if (!map[name]) map[name] = { ...defaultMetricInfo(), name }; map[name].resolveId.totalTime += end - start; map[name].resolveId.invokeCount += 1; }); }); const metrics = Object.values(map).filter(Boolean).sort((a, b) => a.name.localeCompare(b.name)); return metrics; } async getModuleTransformInfo(id, clear = false) { if (clear) { this.clearId(id); try { if (this.env.mode === "dev") await this.env.transformRequest(id); } catch { } } const resolvedId = this.resolveId(id); return { resolvedId, transforms: this.data.transform[resolvedId] || [] }; } clearId(_id) { const id = this.resolveId(_id); if (id) { const moduleGraph = this.env.mode === "dev" ? this.env.moduleGraph : void 0; const mod = moduleGraph?.getModuleById(id); if (mod) moduleGraph?.invalidateModule(mod); this.invalidate(id); } } } const debug = Debug__default("vite-plugin-inspect"); function hijackHook(plugin, name, wrapper) { if (!plugin[name]) return; debug(`hijack plugin "${name}"`, plugin.name); let order = plugin.order || plugin.enforce || "normal"; const hook = plugin[name]; if ("handler" in hook) { const oldFn = hook.handler; order += `-${hook.order || hook.enforce || "normal"}`; hook.handler = function(...args) { return wrapper(oldFn, this, args, order); }; } else if ("transform" in hook) { const oldFn = hook.transform; order += `-${hook.order || hook.enforce || "normal"}`; hook.transform = function(...args) { return wrapper(oldFn, this, args, order); }; } else { const oldFn = hook; plugin[name] = function(...args) { return wrapper(oldFn, this, args, order); }; } } const hijackedPlugins = /* @__PURE__ */ new WeakSet(); function hijackPlugin(plugin, ctx) { if (hijackedPlugins.has(plugin)) return; hijackedPlugins.add(plugin); hijackHook(plugin, "transform", async (fn, context, args, order) => { const code = args[0]; const id = args[1]; let _result; let error; const start = Date.now(); try { _result = await fn.apply(context, args); } catch (_err) { error = _err; } const end = Date.now(); const result = error ? "[Error]" : typeof _result === "string" ? _result : _result?.code; if (ctx.filter(id)) { const sourcemaps = typeof _result === "string" ? null : _result?.map; ctx.getEnvContext(context?.environment)?.recordTransform(id, { name: plugin.name, result, start, end, order, sourcemaps, error: error ? parseError(error) : void 0 }, code); } if (error) throw error; return _result; }); hijackHook(plugin, "load", async (fn, context, args) => { const id = args[0]; let _result; let error; const start = Date.now(); try { _result = await fn.apply(context, args); } catch (err) { error = err; } const end = Date.now(); const result = error ? "[Error]" : typeof _result === "string" ? _result : _result?.code; const sourcemaps = typeof _result === "string" ? null : _result?.map; if (result) { ctx.getEnvContext(context?.environment)?.recordLoad(id, { name: plugin.name, result, start, end, sourcemaps, error: error ? parseError(error) : void 0 }); } if (error) throw error; return _result; }); hijackHook(plugin, "resolveId", async (fn, context, args) => { const id = args[0]; let _result; let error; const start = Date.now(); try { _result = await fn.apply(context, args); } catch (err) { error = err; } const end = Date.now(); if (!ctx.filter(id)) { if (error) throw error; return _result; } const result = error ? stringifyError(error) : typeof _result === "object" ? _result?.id : _result; if (result && result !== id) { ctx.getEnvContext(context?.environment)?.recordResolveId(id, { name: plugin.name, result, start, end, error }); } if (error) throw error; return _result; }); } function parseError(error) { const stack = errorStackParserEs.parse(error, { allowEmpty: true }); const message = error.message || String(error); return { message, stack, raw: error }; } function stringifyError(err) { return String(err.stack ? err.stack : err); } function createPreviewServer(staticPath) { const server = node_http.createServer(); const statics = sirv__default(staticPath); server.on("request", (req, res) => { statics(req, res, () => { res.statusCode = 404; res.end("File not found"); }); }); server.listen(0, () => { const { port } = server.address(); const url = `http://localhost:${port}`; console.log(` ${c__default.green("\u279C")} ${c__default.bold("Inspect Preview Started")}: ${url}`); openBrowser(url); }); } function createServerRpc(ctx) { const rpc = { async getMetadata() { return ctx.getMetadata(); }, async getModulesList(query) { return ctx.queryEnv(query).getModulesList(); }, async getPluginMetrics(query) { return ctx.queryEnv(query).getPluginMetrics(); }, async getModuleTransformInfo(query, id, clear) { return ctx.queryEnv(query).getModuleTransformInfo(id, clear); }, async resolveId(query, id) { return ctx.queryEnv(query).resolveId(id); }, async getServerMetrics(query) { return ctx.getViteContext(query.vite).data.serverMetrics || {}; }, async onModuleUpdated() { }, async list() { return { root: ctx.getViteContext("vite1").config.root, modules: await ctx.queryEnv({ vite: "vite1", env: "client" }).getModulesList(), ssrModules: await ctx.queryEnv({ vite: "vite1", env: "server" }).getModulesList() }; } }; return rpc; } const NAME = "vite-plugin-inspect"; const isCI = !!process__default.env.CI; function PluginInspect(options = {}) { const { dev = true, build = false, silent = false, open: _open = false } = options; if (!dev && !build) { return { name: NAME }; } const ctx = new InspectContext(options); const timestampRE = /\bt=\d{13}&?\b/; const trailingSeparatorRE = /[?&]$/; function setupMiddlewarePerf(ctx2, middlewares) { let firstMiddlewareIndex = -1; middlewares.forEach((middleware, index) => { const { handle: originalHandle } = middleware; if (typeof originalHandle !== "function" || !originalHandle.name) return middleware; middleware.handle = function(...middlewareArgs) { let req; if (middlewareArgs.length === 4) [, req] = middlewareArgs; else [req] = middlewareArgs; const start = Date.now(); const url = req.url?.replace(timestampRE, "").replace(trailingSeparatorRE, ""); ctx2.data.serverMetrics.middleware[url] ??= []; if (firstMiddlewareIndex < 0) firstMiddlewareIndex = index; if (index === firstMiddlewareIndex) ctx2.data.serverMetrics.middleware[url] = []; const result = originalHandle.apply(this, middlewareArgs); Promise.resolve(result).then(() => { const total = Date.now() - start; const metrics = ctx2.data.serverMetrics.middleware[url]; ctx2.data.serverMetrics.middleware[url].push({ self: metrics.length ? Math.max(total - metrics[metrics.length - 1].total, 0) : total, total, name: originalHandle.name }); }); return result; }; Object.defineProperty(middleware.handle, "name", { value: originalHandle.name, configurable: true, enumerable: true }); return middleware; }); } function configureServer(server) { const config = server.config; Object.values(server.environments).forEach((env) => { const envCtx = ctx.getEnvContext(env); const _invalidateModule = env.moduleGraph.invalidateModule; env.moduleGraph.invalidateModule = function(...args) { const mod = args[0]; if (mod?.id) envCtx.invalidate(mod.id); return _invalidateModule.apply(this, args); }; }); const base = (options.base ?? server.config.base) || "/"; server.middlewares.use(`${base}__inspect`, sirv__default(dirs.DIR_CLIENT, { single: true, dev: true })); const rpc = createServerRpc(ctx); const rpcServer = createRPCServer( "vite-plugin-inspect", server.ws, rpc ); const debouncedModuleUpdated = perfectDebounce.debounce(() => { rpcServer.onModuleUpdated.asEvent(); }, 100); server.middlewares.use((req, res, next) => { debouncedModuleUpdated(); next(); }); const _print = server.printUrls; server.printUrls = () => { let host = `${config.server.https ? "https" : "http"}://localhost:${config.server.port || "80"}`; const url = server.resolvedUrls?.local[0]; if (url) { try { const u = new URL(url); host = `${u.protocol}//${u.host}`; } catch (error) { config.logger.warn(`Parse resolved url failed: ${error}`); } } _print(); if (!silent) { const colorUrl = (url2) => c__default.green(url2.replace(/:(\d+)\//, (_, port) => `:${c__default.bold(port)}/`)); config.logger.info(` ${c__default.green("\u279C")} ${c__default.bold("Inspect")}: ${colorUrl(`${host}${base}__inspect/`)}`); } if (_open && !isCI) { setTimeout(() => { openBrowser(`${host}${base}__inspect/`); }, 500); } }; return rpc; } const plugin = { name: NAME, enforce: "pre", apply(_, { command }) { if (command === "serve" && dev) return true; if (command === "build" && build) return true; return false; }, configResolved(config) { config.plugins.forEach((plugin2) => hijackPlugin(plugin2, ctx)); const _createResolver = config.createResolver; config.createResolver = function(...args) { const _resolver = _createResolver.apply(this, args); return async function(...args2) { const id = args2[0]; const aliasOnly = args2[2]; const ssr = args2[3]; const start = Date.now(); const result = await _resolver.apply(this, args2); const end = Date.now(); if (result && result !== id) { const pluginName = aliasOnly ? "alias" : "vite:resolve (+alias)"; const vite = ctx.getViteContext(config); const env = vite.getEnvContext(ssr ? "ssr" : "client"); env.recordResolveId(id, { name: pluginName, result, start, end }); } return result; }; }; }, configureServer(server) { const rpc = configureServer(server); plugin.api = { rpc }; return () => { setupMiddlewarePerf( ctx.getViteContext(server.config), server.middlewares.stack ); }; }, load: { order: "pre", handler(id) { ctx.getEnvContext(this.environment)?.invalidate(id); return null; } }, hotUpdate({ modules, environment }) { const ids = modules.map((module) => module.id); environment.hot.send({ type: "custom", event: "vite-plugin-inspect:update", data: { ids } }); }, async buildEnd() { if (!build) return; const dir = await generateBuild(ctx); this.environment.logger.info(`${c__default.green("Inspect report generated at")} ${c__default.dim(`${dir}`)}`); if (_open && !isCI) createPreviewServer(dir); } }; return plugin; } exports.PluginInspect = PluginInspect;