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.
279 lines
8.0 KiB
279 lines
8.0 KiB
'use strict'; |
|
|
|
var node_events = require('node:events'); |
|
var browser = require('./chunk-browser.cjs'); |
|
var createDebug = require('debug'); |
|
var utils = require('./utils.cjs'); |
|
|
|
function createHmrEmitter() { |
|
const emitter = new node_events.EventEmitter(); |
|
return emitter; |
|
} |
|
function viteNodeHmrPlugin() { |
|
const emitter = createHmrEmitter(); |
|
return { |
|
name: "vite-node:hmr", |
|
config() { |
|
if (process.platform === "darwin" && false) { |
|
return { |
|
server: { |
|
watch: { |
|
useFsEvents: false, |
|
usePolling: false |
|
} |
|
} |
|
}; |
|
} |
|
}, |
|
configureServer(server) { |
|
const _send = server.ws.send; |
|
server.emitter = emitter; |
|
server.ws.send = function(payload) { |
|
_send(payload); |
|
emitter.emit("message", payload); |
|
}; |
|
const environments = server.environments; |
|
if (environments) { |
|
environments.ssr.hot.send = function(payload) { |
|
_send(payload); |
|
emitter.emit("message", payload); |
|
}; |
|
} |
|
} |
|
}; |
|
} |
|
|
|
const debugHmr = createDebug("vite-node:hmr"); |
|
const cache = /* @__PURE__ */ new WeakMap(); |
|
function getCache(runner) { |
|
if (!cache.has(runner)) { |
|
cache.set(runner, { |
|
hotModulesMap: /* @__PURE__ */ new Map(), |
|
dataMap: /* @__PURE__ */ new Map(), |
|
disposeMap: /* @__PURE__ */ new Map(), |
|
pruneMap: /* @__PURE__ */ new Map(), |
|
customListenersMap: /* @__PURE__ */ new Map(), |
|
ctxToListenersMap: /* @__PURE__ */ new Map(), |
|
messageBuffer: [], |
|
isFirstUpdate: false, |
|
pending: false, |
|
queued: [] |
|
}); |
|
} |
|
return cache.get(runner); |
|
} |
|
function sendMessageBuffer(runner, emitter) { |
|
const maps = getCache(runner); |
|
maps.messageBuffer.forEach((msg) => emitter.emit("custom", msg)); |
|
maps.messageBuffer.length = 0; |
|
} |
|
async function reload(runner, files) { |
|
Array.from(runner.moduleCache.keys()).forEach((fsPath) => { |
|
if (!fsPath.includes("node_modules")) { |
|
runner.moduleCache.delete(fsPath); |
|
} |
|
}); |
|
return Promise.all(files.map((file) => runner.executeId(file))); |
|
} |
|
async function notifyListeners(runner, event, data) { |
|
const maps = getCache(runner); |
|
const cbs = maps.customListenersMap.get(event); |
|
if (cbs) { |
|
await Promise.all(cbs.map((cb) => cb(data))); |
|
} |
|
} |
|
async function queueUpdate(runner, p) { |
|
const maps = getCache(runner); |
|
maps.queued.push(p); |
|
if (!maps.pending) { |
|
maps.pending = true; |
|
await Promise.resolve(); |
|
maps.pending = false; |
|
const loading = [...maps.queued]; |
|
maps.queued = []; |
|
(await Promise.all(loading)).forEach((fn) => fn && fn()); |
|
} |
|
} |
|
async function fetchUpdate(runner, { path, acceptedPath }) { |
|
path = utils.normalizeRequestId(path); |
|
acceptedPath = utils.normalizeRequestId(acceptedPath); |
|
const maps = getCache(runner); |
|
const mod = maps.hotModulesMap.get(path); |
|
if (!mod) { |
|
return; |
|
} |
|
const isSelfUpdate = path === acceptedPath; |
|
let fetchedModule; |
|
const qualifiedCallbacks = mod.callbacks.filter( |
|
({ deps }) => deps.includes(acceptedPath) |
|
); |
|
if (isSelfUpdate || qualifiedCallbacks.length > 0) { |
|
const disposer = maps.disposeMap.get(acceptedPath); |
|
if (disposer) { |
|
await disposer(maps.dataMap.get(acceptedPath)); |
|
} |
|
try { |
|
[fetchedModule] = await reload(runner, [acceptedPath]); |
|
} catch (e) { |
|
warnFailedFetch(e, acceptedPath); |
|
} |
|
} |
|
return () => { |
|
for (const { deps, fn } of qualifiedCallbacks) { |
|
fn(deps.map((dep) => dep === acceptedPath ? fetchedModule : void 0)); |
|
} |
|
const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}`; |
|
console.log(`${browser.f.cyan("[vite-node]")} hot updated: ${loggedPath}`); |
|
}; |
|
} |
|
function warnFailedFetch(err, path) { |
|
if (!err.message.match("fetch")) { |
|
console.error(err); |
|
} |
|
console.error( |
|
`[hmr] Failed to reload ${path}. This could be due to syntax errors or importing non-existent modules. (see errors above)` |
|
); |
|
} |
|
async function handleMessage(runner, emitter, files, payload) { |
|
const maps = getCache(runner); |
|
switch (payload.type) { |
|
case "connected": |
|
sendMessageBuffer(runner, emitter); |
|
break; |
|
case "update": |
|
await notifyListeners(runner, "vite:beforeUpdate", payload); |
|
await Promise.all( |
|
payload.updates.map((update) => { |
|
if (update.type === "js-update") { |
|
return queueUpdate(runner, fetchUpdate(runner, update)); |
|
} |
|
console.error(`${browser.f.cyan("[vite-node]")} no support css hmr.}`); |
|
return null; |
|
}) |
|
); |
|
await notifyListeners(runner, "vite:afterUpdate", payload); |
|
break; |
|
case "full-reload": |
|
await notifyListeners(runner, "vite:beforeFullReload", payload); |
|
maps.customListenersMap.delete("vite:beforeFullReload"); |
|
await reload(runner, files); |
|
break; |
|
case "custom": |
|
await notifyListeners(runner, payload.event, payload.data); |
|
break; |
|
case "prune": |
|
await notifyListeners(runner, "vite:beforePrune", payload); |
|
payload.paths.forEach((path) => { |
|
const fn = maps.pruneMap.get(path); |
|
if (fn) { |
|
fn(maps.dataMap.get(path)); |
|
} |
|
}); |
|
break; |
|
case "error": { |
|
await notifyListeners(runner, "vite:error", payload); |
|
const err = payload.err; |
|
console.error( |
|
`${browser.f.cyan("[vite-node]")} Internal Server Error |
|
${err.message} |
|
${err.stack}` |
|
); |
|
break; |
|
} |
|
} |
|
} |
|
function createHotContext(runner, emitter, files, ownerPath) { |
|
debugHmr("createHotContext", ownerPath); |
|
const maps = getCache(runner); |
|
if (!maps.dataMap.has(ownerPath)) { |
|
maps.dataMap.set(ownerPath, {}); |
|
} |
|
const mod = maps.hotModulesMap.get(ownerPath); |
|
if (mod) { |
|
mod.callbacks = []; |
|
} |
|
const newListeners = /* @__PURE__ */ new Map(); |
|
maps.ctxToListenersMap.set(ownerPath, newListeners); |
|
function acceptDeps(deps, callback = () => { |
|
}) { |
|
const mod2 = maps.hotModulesMap.get(ownerPath) || { |
|
id: ownerPath, |
|
callbacks: [] |
|
}; |
|
mod2.callbacks.push({ |
|
deps, |
|
fn: callback |
|
}); |
|
maps.hotModulesMap.set(ownerPath, mod2); |
|
} |
|
const hot = { |
|
get data() { |
|
return maps.dataMap.get(ownerPath); |
|
}, |
|
acceptExports(_, callback) { |
|
acceptDeps([ownerPath], callback && (([mod2]) => callback(mod2))); |
|
}, |
|
accept(deps, callback) { |
|
if (typeof deps === "function" || !deps) { |
|
acceptDeps([ownerPath], ([mod2]) => deps && deps(mod2)); |
|
} else if (typeof deps === "string") { |
|
acceptDeps([deps], ([mod2]) => callback && callback(mod2)); |
|
} else if (Array.isArray(deps)) { |
|
acceptDeps(deps, callback); |
|
} else { |
|
throw new TypeError("invalid hot.accept() usage."); |
|
} |
|
}, |
|
dispose(cb) { |
|
maps.disposeMap.set(ownerPath, cb); |
|
}, |
|
prune(cb) { |
|
maps.pruneMap.set(ownerPath, cb); |
|
}, |
|
invalidate() { |
|
notifyListeners(runner, "vite:invalidate", { |
|
path: ownerPath, |
|
message: void 0 |
|
}); |
|
return reload(runner, files); |
|
}, |
|
on(event, cb) { |
|
const addToMap = (map) => { |
|
const existing = map.get(event) || []; |
|
existing.push(cb); |
|
map.set(event, existing); |
|
}; |
|
addToMap(maps.customListenersMap); |
|
addToMap(newListeners); |
|
}, |
|
off(event, cb) { |
|
const removeFromMap = (map) => { |
|
const existing = map.get(event); |
|
if (existing === void 0) { |
|
return; |
|
} |
|
const pruned = existing.filter((l) => l !== cb); |
|
if (pruned.length === 0) { |
|
map.delete(event); |
|
return; |
|
} |
|
map.set(event, pruned); |
|
}; |
|
removeFromMap(maps.customListenersMap); |
|
removeFromMap(newListeners); |
|
}, |
|
send(event, data) { |
|
maps.messageBuffer.push(JSON.stringify({ type: "custom", event, data })); |
|
sendMessageBuffer(runner, emitter); |
|
} |
|
}; |
|
return hot; |
|
} |
|
|
|
exports.createHmrEmitter = createHmrEmitter; |
|
exports.createHotContext = createHotContext; |
|
exports.getCache = getCache; |
|
exports.handleMessage = handleMessage; |
|
exports.reload = reload; |
|
exports.sendMessageBuffer = sendMessageBuffer; |
|
exports.viteNodeHmrPlugin = viteNodeHmrPlugin;
|
|
|