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.
658 lines
23 KiB
658 lines
23 KiB
import '@vite/env'; |
|
|
|
const base$1 = __BASE__ || '/'; |
|
// set :host styles to make playwright detect the element as visible |
|
const template = /*html*/ ` |
|
<style> |
|
:host { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
z-index: 99999; |
|
--monospace: 'SFMono-Regular', Consolas, |
|
'Liberation Mono', Menlo, Courier, monospace; |
|
--red: #ff5555; |
|
--yellow: #e2aa53; |
|
--purple: #cfa4ff; |
|
--cyan: #2dd9da; |
|
--dim: #c9c9c9; |
|
|
|
--window-background: #181818; |
|
--window-color: #d8d8d8; |
|
} |
|
|
|
.backdrop { |
|
position: fixed; |
|
z-index: 99999; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
overflow-y: scroll; |
|
margin: 0; |
|
background: rgba(0, 0, 0, 0.66); |
|
} |
|
|
|
.window { |
|
font-family: var(--monospace); |
|
line-height: 1.5; |
|
width: 800px; |
|
color: var(--window-color); |
|
margin: 30px auto; |
|
padding: 25px 40px; |
|
position: relative; |
|
background: var(--window-background); |
|
border-radius: 6px 6px 8px 8px; |
|
box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22); |
|
overflow: hidden; |
|
border-top: 8px solid var(--red); |
|
direction: ltr; |
|
text-align: left; |
|
} |
|
|
|
pre { |
|
font-family: var(--monospace); |
|
font-size: 16px; |
|
margin-top: 0; |
|
margin-bottom: 1em; |
|
overflow-x: scroll; |
|
scrollbar-width: none; |
|
} |
|
|
|
pre::-webkit-scrollbar { |
|
display: none; |
|
} |
|
|
|
.message { |
|
line-height: 1.3; |
|
font-weight: 600; |
|
white-space: pre-wrap; |
|
} |
|
|
|
.message-body { |
|
color: var(--red); |
|
} |
|
|
|
.plugin { |
|
color: var(--purple); |
|
} |
|
|
|
.file { |
|
color: var(--cyan); |
|
margin-bottom: 0; |
|
white-space: pre-wrap; |
|
word-break: break-all; |
|
} |
|
|
|
.frame { |
|
color: var(--yellow); |
|
} |
|
|
|
.stack { |
|
font-size: 13px; |
|
color: var(--dim); |
|
} |
|
|
|
.tip { |
|
font-size: 13px; |
|
color: #999; |
|
border-top: 1px dotted #999; |
|
padding-top: 13px; |
|
} |
|
|
|
code { |
|
font-size: 13px; |
|
font-family: var(--monospace); |
|
color: var(--yellow); |
|
} |
|
|
|
.file-link { |
|
text-decoration: underline; |
|
cursor: pointer; |
|
} |
|
</style> |
|
<div class="backdrop" part="backdrop"> |
|
<div class="window" part="window"> |
|
<pre class="message" part="message"><span class="plugin"></span><span class="message-body"></span></pre> |
|
<pre class="file" part="file"></pre> |
|
<pre class="frame" part="frame"></pre> |
|
<pre class="stack" part="stack"></pre> |
|
<div class="tip" part="tip"> |
|
Click outside or fix the code to dismiss.<br> |
|
You can also disable this overlay by setting |
|
<code>server.hmr.overlay</code> to <code>false</code> in <code>vite.config.js.</code> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
const fileRE = /(?:[a-zA-Z]:\\|\/).*?:\d+:\d+/g; |
|
const codeframeRE = /^(?:>?\s+\d+\s+\|.*|\s+\|\s*\^.*)\r?\n/gm; |
|
// Allow `ErrorOverlay` to extend `HTMLElement` even in environments where |
|
// `HTMLElement` was not originally defined. |
|
const { HTMLElement = class { |
|
} } = globalThis; |
|
class ErrorOverlay extends HTMLElement { |
|
constructor(err, links = true) { |
|
var _a; |
|
super(); |
|
this.root = this.attachShadow({ mode: 'open' }); |
|
this.root.innerHTML = template; |
|
codeframeRE.lastIndex = 0; |
|
const hasFrame = err.frame && codeframeRE.test(err.frame); |
|
const message = hasFrame |
|
? err.message.replace(codeframeRE, '') |
|
: err.message; |
|
if (err.plugin) { |
|
this.text('.plugin', `[plugin:${err.plugin}] `); |
|
} |
|
this.text('.message-body', message.trim()); |
|
const [file] = (((_a = err.loc) === null || _a === void 0 ? void 0 : _a.file) || err.id || 'unknown file').split(`?`); |
|
if (err.loc) { |
|
this.text('.file', `${file}:${err.loc.line}:${err.loc.column}`, links); |
|
} |
|
else if (err.id) { |
|
this.text('.file', file); |
|
} |
|
if (hasFrame) { |
|
this.text('.frame', err.frame.trim()); |
|
} |
|
this.text('.stack', err.stack, links); |
|
this.root.querySelector('.window').addEventListener('click', (e) => { |
|
e.stopPropagation(); |
|
}); |
|
this.addEventListener('click', () => { |
|
this.close(); |
|
}); |
|
} |
|
text(selector, text, linkFiles = false) { |
|
const el = this.root.querySelector(selector); |
|
if (!linkFiles) { |
|
el.textContent = text; |
|
} |
|
else { |
|
let curIndex = 0; |
|
let match; |
|
fileRE.lastIndex = 0; |
|
while ((match = fileRE.exec(text))) { |
|
const { 0: file, index } = match; |
|
if (index != null) { |
|
const frag = text.slice(curIndex, index); |
|
el.appendChild(document.createTextNode(frag)); |
|
const link = document.createElement('a'); |
|
link.textContent = file; |
|
link.className = 'file-link'; |
|
link.onclick = () => { |
|
fetch(`${base$1}__open-in-editor?file=` + encodeURIComponent(file)); |
|
}; |
|
el.appendChild(link); |
|
curIndex += frag.length + file.length; |
|
} |
|
} |
|
} |
|
} |
|
close() { |
|
var _a; |
|
(_a = this.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this); |
|
} |
|
} |
|
const overlayId = 'vite-error-overlay'; |
|
const { customElements } = globalThis; // Ensure `customElements` is defined before the next line. |
|
if (customElements && !customElements.get(overlayId)) { |
|
customElements.define(overlayId, ErrorOverlay); |
|
} |
|
|
|
console.debug('[vite] connecting...'); |
|
const importMetaUrl = new URL(import.meta.url); |
|
// use server configuration, then fallback to inference |
|
const serverHost = __SERVER_HOST__; |
|
const socketProtocol = __HMR_PROTOCOL__ || (importMetaUrl.protocol === 'https:' ? 'wss' : 'ws'); |
|
const hmrPort = __HMR_PORT__; |
|
const socketHost = `${__HMR_HOSTNAME__ || importMetaUrl.hostname}:${hmrPort || importMetaUrl.port}${__HMR_BASE__}`; |
|
const directSocketHost = __HMR_DIRECT_TARGET__; |
|
const base = __BASE__ || '/'; |
|
const messageBuffer = []; |
|
let socket; |
|
try { |
|
let fallback; |
|
// only use fallback when port is inferred to prevent confusion |
|
if (!hmrPort) { |
|
fallback = () => { |
|
// fallback to connecting directly to the hmr server |
|
// for servers which does not support proxying websocket |
|
socket = setupWebSocket(socketProtocol, directSocketHost, () => { |
|
const currentScriptHostURL = new URL(import.meta.url); |
|
const currentScriptHost = currentScriptHostURL.host + |
|
currentScriptHostURL.pathname.replace(/@vite\/client$/, ''); |
|
console.error('[vite] failed to connect to websocket.\n' + |
|
'your current setup:\n' + |
|
` (browser) ${currentScriptHost} <--[HTTP]--> ${serverHost} (server)\n` + |
|
` (browser) ${socketHost} <--[WebSocket (failing)]--> ${directSocketHost} (server)\n` + |
|
'Check out your Vite / network configuration and https://vitejs.dev/config/server-options.html#server-hmr .'); |
|
}); |
|
socket.addEventListener('open', () => { |
|
console.info('[vite] Direct websocket connection fallback. Check out https://vitejs.dev/config/server-options.html#server-hmr to remove the previous connection error.'); |
|
}, { once: true }); |
|
}; |
|
} |
|
socket = setupWebSocket(socketProtocol, socketHost, fallback); |
|
} |
|
catch (error) { |
|
console.error(`[vite] failed to connect to websocket (${error}). `); |
|
} |
|
function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) { |
|
const socket = new WebSocket(`${protocol}://${hostAndPath}`, 'vite-hmr'); |
|
let isOpened = false; |
|
socket.addEventListener('open', () => { |
|
isOpened = true; |
|
}, { once: true }); |
|
// Listen for messages |
|
socket.addEventListener('message', async ({ data }) => { |
|
handleMessage(JSON.parse(data)); |
|
}); |
|
// ping server |
|
socket.addEventListener('close', async ({ wasClean }) => { |
|
if (wasClean) |
|
return; |
|
if (!isOpened && onCloseWithoutOpen) { |
|
onCloseWithoutOpen(); |
|
return; |
|
} |
|
console.log(`[vite] server connection lost. polling for restart...`); |
|
await waitForSuccessfulPing(protocol, hostAndPath); |
|
location.reload(); |
|
}); |
|
return socket; |
|
} |
|
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)`); |
|
} |
|
function cleanUrl(pathname) { |
|
const url = new URL(pathname, location.toString()); |
|
url.searchParams.delete('direct'); |
|
return url.pathname + url.search; |
|
} |
|
let isFirstUpdate = true; |
|
const outdatedLinkTags = new WeakSet(); |
|
async function handleMessage(payload) { |
|
switch (payload.type) { |
|
case 'connected': |
|
console.debug(`[vite] connected.`); |
|
sendMessageBuffer(); |
|
// proxy(nginx, docker) hmr ws maybe caused timeout, |
|
// so send ping package let ws keep alive. |
|
setInterval(() => { |
|
if (socket.readyState === socket.OPEN) { |
|
socket.send('{"type":"ping"}'); |
|
} |
|
}, __HMR_TIMEOUT__); |
|
break; |
|
case 'update': |
|
notifyListeners('vite:beforeUpdate', payload); |
|
// if this is the first update and there's already an error overlay, it |
|
// means the page opened with existing server compile error and the whole |
|
// module script failed to load (since one of the nested imports is 500). |
|
// in this case a normal update won't work and a full reload is needed. |
|
if (isFirstUpdate && hasErrorOverlay()) { |
|
window.location.reload(); |
|
return; |
|
} |
|
else { |
|
clearErrorOverlay(); |
|
isFirstUpdate = false; |
|
} |
|
await Promise.all(payload.updates.map(async (update) => { |
|
if (update.type === 'js-update') { |
|
return queueUpdate(fetchUpdate(update)); |
|
} |
|
// css-update |
|
// this is only sent when a css file referenced with <link> is updated |
|
const { path, timestamp } = update; |
|
const searchUrl = cleanUrl(path); |
|
// can't use querySelector with `[href*=]` here since the link may be |
|
// using relative paths so we need to use link.href to grab the full |
|
// URL for the include check. |
|
const el = Array.from(document.querySelectorAll('link')).find((e) => !outdatedLinkTags.has(e) && cleanUrl(e.href).includes(searchUrl)); |
|
if (!el) { |
|
return; |
|
} |
|
const newPath = `${base}${searchUrl.slice(1)}${searchUrl.includes('?') ? '&' : '?'}t=${timestamp}`; |
|
// rather than swapping the href on the existing tag, we will |
|
// create a new link tag. Once the new stylesheet has loaded we |
|
// will remove the existing link tag. This removes a Flash Of |
|
// Unstyled Content that can occur when swapping out the tag href |
|
// directly, as the new stylesheet has not yet been loaded. |
|
return new Promise((resolve) => { |
|
const newLinkTag = el.cloneNode(); |
|
newLinkTag.href = new URL(newPath, el.href).href; |
|
const removeOldEl = () => { |
|
el.remove(); |
|
console.debug(`[vite] css hot updated: ${searchUrl}`); |
|
resolve(); |
|
}; |
|
newLinkTag.addEventListener('load', removeOldEl); |
|
newLinkTag.addEventListener('error', removeOldEl); |
|
outdatedLinkTags.add(el); |
|
el.after(newLinkTag); |
|
}); |
|
})); |
|
notifyListeners('vite:afterUpdate', payload); |
|
break; |
|
case 'custom': { |
|
notifyListeners(payload.event, payload.data); |
|
break; |
|
} |
|
case 'full-reload': |
|
notifyListeners('vite:beforeFullReload', payload); |
|
if (payload.path && payload.path.endsWith('.html')) { |
|
// if html file is edited, only reload the page if the browser is |
|
// currently on that page. |
|
const pagePath = decodeURI(location.pathname); |
|
const payloadPath = base + payload.path.slice(1); |
|
if (pagePath === payloadPath || |
|
payload.path === '/index.html' || |
|
(pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath)) { |
|
location.reload(); |
|
} |
|
return; |
|
} |
|
else { |
|
location.reload(); |
|
} |
|
break; |
|
case 'prune': |
|
notifyListeners('vite:beforePrune', payload); |
|
// After an HMR update, some modules are no longer imported on the page |
|
// but they may have left behind side effects that need to be cleaned up |
|
// (.e.g style injections) |
|
// TODO Trigger their dispose callbacks. |
|
payload.paths.forEach((path) => { |
|
const fn = pruneMap.get(path); |
|
if (fn) { |
|
fn(dataMap.get(path)); |
|
} |
|
}); |
|
break; |
|
case 'error': { |
|
notifyListeners('vite:error', payload); |
|
const err = payload.err; |
|
if (enableOverlay) { |
|
createErrorOverlay(err); |
|
} |
|
else { |
|
console.error(`[vite] Internal Server Error\n${err.message}\n${err.stack}`); |
|
} |
|
break; |
|
} |
|
default: { |
|
const check = payload; |
|
return check; |
|
} |
|
} |
|
} |
|
function notifyListeners(event, data) { |
|
const cbs = customListenersMap.get(event); |
|
if (cbs) { |
|
cbs.forEach((cb) => cb(data)); |
|
} |
|
} |
|
const enableOverlay = __HMR_ENABLE_OVERLAY__; |
|
function createErrorOverlay(err) { |
|
if (!enableOverlay) |
|
return; |
|
clearErrorOverlay(); |
|
document.body.appendChild(new ErrorOverlay(err)); |
|
} |
|
function clearErrorOverlay() { |
|
document |
|
.querySelectorAll(overlayId) |
|
.forEach((n) => n.close()); |
|
} |
|
function hasErrorOverlay() { |
|
return document.querySelectorAll(overlayId).length; |
|
} |
|
let pending = false; |
|
let queued = []; |
|
/** |
|
* buffer multiple hot updates triggered by the same src change |
|
* so that they are invoked in the same order they were sent. |
|
* (otherwise the order may be inconsistent because of the http request round trip) |
|
*/ |
|
async function queueUpdate(p) { |
|
queued.push(p); |
|
if (!pending) { |
|
pending = true; |
|
await Promise.resolve(); |
|
pending = false; |
|
const loading = [...queued]; |
|
queued = []; |
|
(await Promise.all(loading)).forEach((fn) => fn && fn()); |
|
} |
|
} |
|
async function waitForSuccessfulPing(socketProtocol, hostAndPath, ms = 1000) { |
|
const pingHostProtocol = socketProtocol === 'wss' ? 'https' : 'http'; |
|
// eslint-disable-next-line no-constant-condition |
|
while (true) { |
|
try { |
|
// A fetch on a websocket URL will return a successful promise with status 400, |
|
// but will reject a networking error. |
|
// When running on middleware mode, it returns status 426, and an cors error happens if mode is not no-cors |
|
await fetch(`${pingHostProtocol}://${hostAndPath}`, { |
|
mode: 'no-cors', |
|
}); |
|
break; |
|
} |
|
catch (e) { |
|
// wait ms before attempting to ping again |
|
await new Promise((resolve) => setTimeout(resolve, ms)); |
|
} |
|
} |
|
} |
|
const sheetsMap = new Map(); |
|
// all css imports should be inserted at the same position |
|
// because after build it will be a single css file |
|
let lastInsertedStyle; |
|
function updateStyle(id, content) { |
|
let style = sheetsMap.get(id); |
|
{ |
|
if (style && !(style instanceof HTMLStyleElement)) { |
|
removeStyle(id); |
|
style = undefined; |
|
} |
|
if (!style) { |
|
style = document.createElement('style'); |
|
style.setAttribute('type', 'text/css'); |
|
style.setAttribute('data-vite-dev-id', id); |
|
style.textContent = content; |
|
if (!lastInsertedStyle) { |
|
document.head.appendChild(style); |
|
// reset lastInsertedStyle after async |
|
// because dynamically imported css will be splitted into a different file |
|
setTimeout(() => { |
|
lastInsertedStyle = undefined; |
|
}, 0); |
|
} |
|
else { |
|
lastInsertedStyle.insertAdjacentElement('afterend', style); |
|
} |
|
lastInsertedStyle = style; |
|
} |
|
else { |
|
style.textContent = content; |
|
} |
|
} |
|
sheetsMap.set(id, style); |
|
} |
|
function removeStyle(id) { |
|
const style = sheetsMap.get(id); |
|
if (style) { |
|
if (style instanceof CSSStyleSheet) { |
|
document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => s !== style); |
|
} |
|
else { |
|
document.head.removeChild(style); |
|
} |
|
sheetsMap.delete(id); |
|
} |
|
} |
|
async function fetchUpdate({ path, acceptedPath, timestamp, explicitImportRequired, }) { |
|
const mod = hotModulesMap.get(path); |
|
if (!mod) { |
|
// In a code-splitting project, |
|
// it is common that the hot-updating module is not loaded yet. |
|
// https://github.com/vitejs/vite/issues/721 |
|
return; |
|
} |
|
let fetchedModule; |
|
const isSelfUpdate = path === acceptedPath; |
|
// determine the qualified callbacks before we re-import the modules |
|
const qualifiedCallbacks = mod.callbacks.filter(({ deps }) => deps.includes(acceptedPath)); |
|
if (isSelfUpdate || qualifiedCallbacks.length > 0) { |
|
const disposer = disposeMap.get(acceptedPath); |
|
if (disposer) |
|
await disposer(dataMap.get(acceptedPath)); |
|
const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`); |
|
try { |
|
fetchedModule = await import( |
|
/* @vite-ignore */ |
|
base + |
|
acceptedPathWithoutQuery.slice(1) + |
|
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${query ? `&${query}` : ''}`); |
|
} |
|
catch (e) { |
|
warnFailedFetch(e, acceptedPath); |
|
} |
|
} |
|
return () => { |
|
for (const { deps, fn } of qualifiedCallbacks) { |
|
fn(deps.map((dep) => (dep === acceptedPath ? fetchedModule : undefined))); |
|
} |
|
const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}`; |
|
console.debug(`[vite] hot updated: ${loggedPath}`); |
|
}; |
|
} |
|
function sendMessageBuffer() { |
|
if (socket.readyState === 1) { |
|
messageBuffer.forEach((msg) => socket.send(msg)); |
|
messageBuffer.length = 0; |
|
} |
|
} |
|
const hotModulesMap = new Map(); |
|
const disposeMap = new Map(); |
|
const pruneMap = new Map(); |
|
const dataMap = new Map(); |
|
const customListenersMap = new Map(); |
|
const ctxToListenersMap = new Map(); |
|
function createHotContext(ownerPath) { |
|
if (!dataMap.has(ownerPath)) { |
|
dataMap.set(ownerPath, {}); |
|
} |
|
// when a file is hot updated, a new context is created |
|
// clear its stale callbacks |
|
const mod = hotModulesMap.get(ownerPath); |
|
if (mod) { |
|
mod.callbacks = []; |
|
} |
|
// clear stale custom event listeners |
|
const staleListeners = ctxToListenersMap.get(ownerPath); |
|
if (staleListeners) { |
|
for (const [event, staleFns] of staleListeners) { |
|
const listeners = customListenersMap.get(event); |
|
if (listeners) { |
|
customListenersMap.set(event, listeners.filter((l) => !staleFns.includes(l))); |
|
} |
|
} |
|
} |
|
const newListeners = new Map(); |
|
ctxToListenersMap.set(ownerPath, newListeners); |
|
function acceptDeps(deps, callback = () => { }) { |
|
const mod = hotModulesMap.get(ownerPath) || { |
|
id: ownerPath, |
|
callbacks: [], |
|
}; |
|
mod.callbacks.push({ |
|
deps, |
|
fn: callback, |
|
}); |
|
hotModulesMap.set(ownerPath, mod); |
|
} |
|
const hot = { |
|
get data() { |
|
return dataMap.get(ownerPath); |
|
}, |
|
accept(deps, callback) { |
|
if (typeof deps === 'function' || !deps) { |
|
// self-accept: hot.accept(() => {}) |
|
acceptDeps([ownerPath], ([mod]) => deps === null || deps === void 0 ? void 0 : deps(mod)); |
|
} |
|
else if (typeof deps === 'string') { |
|
// explicit deps |
|
acceptDeps([deps], ([mod]) => callback === null || callback === void 0 ? void 0 : callback(mod)); |
|
} |
|
else if (Array.isArray(deps)) { |
|
acceptDeps(deps, callback); |
|
} |
|
else { |
|
throw new Error(`invalid hot.accept() usage.`); |
|
} |
|
}, |
|
// export names (first arg) are irrelevant on the client side, they're |
|
// extracted in the server for propagation |
|
acceptExports(_, callback) { |
|
acceptDeps([ownerPath], ([mod]) => callback === null || callback === void 0 ? void 0 : callback(mod)); |
|
}, |
|
dispose(cb) { |
|
disposeMap.set(ownerPath, cb); |
|
}, |
|
prune(cb) { |
|
pruneMap.set(ownerPath, cb); |
|
}, |
|
// Kept for backward compatibility (#11036) |
|
// @ts-expect-error untyped |
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
decline() { }, |
|
// tell the server to re-perform hmr propagation from this module as root |
|
invalidate(message) { |
|
notifyListeners('vite:invalidate', { path: ownerPath, message }); |
|
this.send('vite:invalidate', { path: ownerPath, message }); |
|
console.debug(`[vite] invalidate ${ownerPath}${message ? `: ${message}` : ''}`); |
|
}, |
|
// custom events |
|
on(event, cb) { |
|
const addToMap = (map) => { |
|
const existing = map.get(event) || []; |
|
existing.push(cb); |
|
map.set(event, existing); |
|
}; |
|
addToMap(customListenersMap); |
|
addToMap(newListeners); |
|
}, |
|
send(event, data) { |
|
messageBuffer.push(JSON.stringify({ type: 'custom', event, data })); |
|
sendMessageBuffer(); |
|
}, |
|
}; |
|
return hot; |
|
} |
|
/** |
|
* urls here are dynamic import() urls that couldn't be statically analyzed |
|
*/ |
|
function injectQuery(url, queryToInject) { |
|
// skip urls that won't be handled by vite |
|
if (!url.startsWith('.') && !url.startsWith('/')) { |
|
return url; |
|
} |
|
// can't use pathname from URL since it may be relative like ../ |
|
const pathname = url.replace(/#.*$/, '').replace(/\?.*$/, ''); |
|
const { search, hash } = new URL(url, 'http://vitejs.dev'); |
|
return `${pathname}?${queryToInject}${search ? `&` + search.slice(1) : ''}${hash || ''}`; |
|
} |
|
|
|
export { ErrorOverlay, createHotContext, injectQuery, removeStyle, updateStyle }; |
|
//# sourceMappingURL=client.mjs.map
|
|
|