client.mjs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. import '@vite/env';
  2. const base$1 = __BASE__ || '/';
  3. // set :host styles to make playwright detect the element as visible
  4. const template = /*html*/ `
  5. <style>
  6. :host {
  7. position: fixed;
  8. top: 0;
  9. left: 0;
  10. width: 100%;
  11. height: 100%;
  12. z-index: 99999;
  13. --monospace: 'SFMono-Regular', Consolas,
  14. 'Liberation Mono', Menlo, Courier, monospace;
  15. --red: #ff5555;
  16. --yellow: #e2aa53;
  17. --purple: #cfa4ff;
  18. --cyan: #2dd9da;
  19. --dim: #c9c9c9;
  20. --window-background: #181818;
  21. --window-color: #d8d8d8;
  22. }
  23. .backdrop {
  24. position: fixed;
  25. z-index: 99999;
  26. top: 0;
  27. left: 0;
  28. width: 100%;
  29. height: 100%;
  30. overflow-y: scroll;
  31. margin: 0;
  32. background: rgba(0, 0, 0, 0.66);
  33. }
  34. .window {
  35. font-family: var(--monospace);
  36. line-height: 1.5;
  37. width: 800px;
  38. color: var(--window-color);
  39. margin: 30px auto;
  40. padding: 25px 40px;
  41. position: relative;
  42. background: var(--window-background);
  43. border-radius: 6px 6px 8px 8px;
  44. box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);
  45. overflow: hidden;
  46. border-top: 8px solid var(--red);
  47. direction: ltr;
  48. text-align: left;
  49. }
  50. pre {
  51. font-family: var(--monospace);
  52. font-size: 16px;
  53. margin-top: 0;
  54. margin-bottom: 1em;
  55. overflow-x: scroll;
  56. scrollbar-width: none;
  57. }
  58. pre::-webkit-scrollbar {
  59. display: none;
  60. }
  61. .message {
  62. line-height: 1.3;
  63. font-weight: 600;
  64. white-space: pre-wrap;
  65. }
  66. .message-body {
  67. color: var(--red);
  68. }
  69. .plugin {
  70. color: var(--purple);
  71. }
  72. .file {
  73. color: var(--cyan);
  74. margin-bottom: 0;
  75. white-space: pre-wrap;
  76. word-break: break-all;
  77. }
  78. .frame {
  79. color: var(--yellow);
  80. }
  81. .stack {
  82. font-size: 13px;
  83. color: var(--dim);
  84. }
  85. .tip {
  86. font-size: 13px;
  87. color: #999;
  88. border-top: 1px dotted #999;
  89. padding-top: 13px;
  90. }
  91. code {
  92. font-size: 13px;
  93. font-family: var(--monospace);
  94. color: var(--yellow);
  95. }
  96. .file-link {
  97. text-decoration: underline;
  98. cursor: pointer;
  99. }
  100. </style>
  101. <div class="backdrop" part="backdrop">
  102. <div class="window" part="window">
  103. <pre class="message" part="message"><span class="plugin"></span><span class="message-body"></span></pre>
  104. <pre class="file" part="file"></pre>
  105. <pre class="frame" part="frame"></pre>
  106. <pre class="stack" part="stack"></pre>
  107. <div class="tip" part="tip">
  108. Click outside or fix the code to dismiss.<br>
  109. You can also disable this overlay by setting
  110. <code>server.hmr.overlay</code> to <code>false</code> in <code>vite.config.js.</code>
  111. </div>
  112. </div>
  113. </div>
  114. `;
  115. const fileRE = /(?:[a-zA-Z]:\\|\/).*?:\d+:\d+/g;
  116. const codeframeRE = /^(?:>?\s+\d+\s+\|.*|\s+\|\s*\^.*)\r?\n/gm;
  117. // Allow `ErrorOverlay` to extend `HTMLElement` even in environments where
  118. // `HTMLElement` was not originally defined.
  119. const { HTMLElement = class {
  120. } } = globalThis;
  121. class ErrorOverlay extends HTMLElement {
  122. constructor(err, links = true) {
  123. var _a;
  124. super();
  125. this.root = this.attachShadow({ mode: 'open' });
  126. this.root.innerHTML = template;
  127. codeframeRE.lastIndex = 0;
  128. const hasFrame = err.frame && codeframeRE.test(err.frame);
  129. const message = hasFrame
  130. ? err.message.replace(codeframeRE, '')
  131. : err.message;
  132. if (err.plugin) {
  133. this.text('.plugin', `[plugin:${err.plugin}] `);
  134. }
  135. this.text('.message-body', message.trim());
  136. const [file] = (((_a = err.loc) === null || _a === void 0 ? void 0 : _a.file) || err.id || 'unknown file').split(`?`);
  137. if (err.loc) {
  138. this.text('.file', `${file}:${err.loc.line}:${err.loc.column}`, links);
  139. }
  140. else if (err.id) {
  141. this.text('.file', file);
  142. }
  143. if (hasFrame) {
  144. this.text('.frame', err.frame.trim());
  145. }
  146. this.text('.stack', err.stack, links);
  147. this.root.querySelector('.window').addEventListener('click', (e) => {
  148. e.stopPropagation();
  149. });
  150. this.addEventListener('click', () => {
  151. this.close();
  152. });
  153. }
  154. text(selector, text, linkFiles = false) {
  155. const el = this.root.querySelector(selector);
  156. if (!linkFiles) {
  157. el.textContent = text;
  158. }
  159. else {
  160. let curIndex = 0;
  161. let match;
  162. fileRE.lastIndex = 0;
  163. while ((match = fileRE.exec(text))) {
  164. const { 0: file, index } = match;
  165. if (index != null) {
  166. const frag = text.slice(curIndex, index);
  167. el.appendChild(document.createTextNode(frag));
  168. const link = document.createElement('a');
  169. link.textContent = file;
  170. link.className = 'file-link';
  171. link.onclick = () => {
  172. fetch(`${base$1}__open-in-editor?file=` + encodeURIComponent(file));
  173. };
  174. el.appendChild(link);
  175. curIndex += frag.length + file.length;
  176. }
  177. }
  178. }
  179. }
  180. close() {
  181. var _a;
  182. (_a = this.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this);
  183. }
  184. }
  185. const overlayId = 'vite-error-overlay';
  186. const { customElements } = globalThis; // Ensure `customElements` is defined before the next line.
  187. if (customElements && !customElements.get(overlayId)) {
  188. customElements.define(overlayId, ErrorOverlay);
  189. }
  190. console.debug('[vite] connecting...');
  191. const importMetaUrl = new URL(import.meta.url);
  192. // use server configuration, then fallback to inference
  193. const serverHost = __SERVER_HOST__;
  194. const socketProtocol = __HMR_PROTOCOL__ || (importMetaUrl.protocol === 'https:' ? 'wss' : 'ws');
  195. const hmrPort = __HMR_PORT__;
  196. const socketHost = `${__HMR_HOSTNAME__ || importMetaUrl.hostname}:${hmrPort || importMetaUrl.port}${__HMR_BASE__}`;
  197. const directSocketHost = __HMR_DIRECT_TARGET__;
  198. const base = __BASE__ || '/';
  199. const messageBuffer = [];
  200. let socket;
  201. try {
  202. let fallback;
  203. // only use fallback when port is inferred to prevent confusion
  204. if (!hmrPort) {
  205. fallback = () => {
  206. // fallback to connecting directly to the hmr server
  207. // for servers which does not support proxying websocket
  208. socket = setupWebSocket(socketProtocol, directSocketHost, () => {
  209. const currentScriptHostURL = new URL(import.meta.url);
  210. const currentScriptHost = currentScriptHostURL.host +
  211. currentScriptHostURL.pathname.replace(/@vite\/client$/, '');
  212. console.error('[vite] failed to connect to websocket.\n' +
  213. 'your current setup:\n' +
  214. ` (browser) ${currentScriptHost} <--[HTTP]--> ${serverHost} (server)\n` +
  215. ` (browser) ${socketHost} <--[WebSocket (failing)]--> ${directSocketHost} (server)\n` +
  216. 'Check out your Vite / network configuration and https://vitejs.dev/config/server-options.html#server-hmr .');
  217. });
  218. socket.addEventListener('open', () => {
  219. console.info('[vite] Direct websocket connection fallback. Check out https://vitejs.dev/config/server-options.html#server-hmr to remove the previous connection error.');
  220. }, { once: true });
  221. };
  222. }
  223. socket = setupWebSocket(socketProtocol, socketHost, fallback);
  224. }
  225. catch (error) {
  226. console.error(`[vite] failed to connect to websocket (${error}). `);
  227. }
  228. function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {
  229. const socket = new WebSocket(`${protocol}://${hostAndPath}`, 'vite-hmr');
  230. let isOpened = false;
  231. socket.addEventListener('open', () => {
  232. isOpened = true;
  233. }, { once: true });
  234. // Listen for messages
  235. socket.addEventListener('message', async ({ data }) => {
  236. handleMessage(JSON.parse(data));
  237. });
  238. // ping server
  239. socket.addEventListener('close', async ({ wasClean }) => {
  240. if (wasClean)
  241. return;
  242. if (!isOpened && onCloseWithoutOpen) {
  243. onCloseWithoutOpen();
  244. return;
  245. }
  246. console.log(`[vite] server connection lost. polling for restart...`);
  247. await waitForSuccessfulPing(protocol, hostAndPath);
  248. location.reload();
  249. });
  250. return socket;
  251. }
  252. function warnFailedFetch(err, path) {
  253. if (!err.message.match('fetch')) {
  254. console.error(err);
  255. }
  256. console.error(`[hmr] Failed to reload ${path}. ` +
  257. `This could be due to syntax errors or importing non-existent ` +
  258. `modules. (see errors above)`);
  259. }
  260. function cleanUrl(pathname) {
  261. const url = new URL(pathname, location.toString());
  262. url.searchParams.delete('direct');
  263. return url.pathname + url.search;
  264. }
  265. let isFirstUpdate = true;
  266. const outdatedLinkTags = new WeakSet();
  267. async function handleMessage(payload) {
  268. switch (payload.type) {
  269. case 'connected':
  270. console.debug(`[vite] connected.`);
  271. sendMessageBuffer();
  272. // proxy(nginx, docker) hmr ws maybe caused timeout,
  273. // so send ping package let ws keep alive.
  274. setInterval(() => {
  275. if (socket.readyState === socket.OPEN) {
  276. socket.send('{"type":"ping"}');
  277. }
  278. }, __HMR_TIMEOUT__);
  279. break;
  280. case 'update':
  281. notifyListeners('vite:beforeUpdate', payload);
  282. // if this is the first update and there's already an error overlay, it
  283. // means the page opened with existing server compile error and the whole
  284. // module script failed to load (since one of the nested imports is 500).
  285. // in this case a normal update won't work and a full reload is needed.
  286. if (isFirstUpdate && hasErrorOverlay()) {
  287. window.location.reload();
  288. return;
  289. }
  290. else {
  291. clearErrorOverlay();
  292. isFirstUpdate = false;
  293. }
  294. await Promise.all(payload.updates.map(async (update) => {
  295. if (update.type === 'js-update') {
  296. return queueUpdate(fetchUpdate(update));
  297. }
  298. // css-update
  299. // this is only sent when a css file referenced with <link> is updated
  300. const { path, timestamp } = update;
  301. const searchUrl = cleanUrl(path);
  302. // can't use querySelector with `[href*=]` here since the link may be
  303. // using relative paths so we need to use link.href to grab the full
  304. // URL for the include check.
  305. const el = Array.from(document.querySelectorAll('link')).find((e) => !outdatedLinkTags.has(e) && cleanUrl(e.href).includes(searchUrl));
  306. if (!el) {
  307. return;
  308. }
  309. const newPath = `${base}${searchUrl.slice(1)}${searchUrl.includes('?') ? '&' : '?'}t=${timestamp}`;
  310. // rather than swapping the href on the existing tag, we will
  311. // create a new link tag. Once the new stylesheet has loaded we
  312. // will remove the existing link tag. This removes a Flash Of
  313. // Unstyled Content that can occur when swapping out the tag href
  314. // directly, as the new stylesheet has not yet been loaded.
  315. return new Promise((resolve) => {
  316. const newLinkTag = el.cloneNode();
  317. newLinkTag.href = new URL(newPath, el.href).href;
  318. const removeOldEl = () => {
  319. el.remove();
  320. console.debug(`[vite] css hot updated: ${searchUrl}`);
  321. resolve();
  322. };
  323. newLinkTag.addEventListener('load', removeOldEl);
  324. newLinkTag.addEventListener('error', removeOldEl);
  325. outdatedLinkTags.add(el);
  326. el.after(newLinkTag);
  327. });
  328. }));
  329. notifyListeners('vite:afterUpdate', payload);
  330. break;
  331. case 'custom': {
  332. notifyListeners(payload.event, payload.data);
  333. break;
  334. }
  335. case 'full-reload':
  336. notifyListeners('vite:beforeFullReload', payload);
  337. if (payload.path && payload.path.endsWith('.html')) {
  338. // if html file is edited, only reload the page if the browser is
  339. // currently on that page.
  340. const pagePath = decodeURI(location.pathname);
  341. const payloadPath = base + payload.path.slice(1);
  342. if (pagePath === payloadPath ||
  343. payload.path === '/index.html' ||
  344. (pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath)) {
  345. location.reload();
  346. }
  347. return;
  348. }
  349. else {
  350. location.reload();
  351. }
  352. break;
  353. case 'prune':
  354. notifyListeners('vite:beforePrune', payload);
  355. // After an HMR update, some modules are no longer imported on the page
  356. // but they may have left behind side effects that need to be cleaned up
  357. // (.e.g style injections)
  358. // TODO Trigger their dispose callbacks.
  359. payload.paths.forEach((path) => {
  360. const fn = pruneMap.get(path);
  361. if (fn) {
  362. fn(dataMap.get(path));
  363. }
  364. });
  365. break;
  366. case 'error': {
  367. notifyListeners('vite:error', payload);
  368. const err = payload.err;
  369. if (enableOverlay) {
  370. createErrorOverlay(err);
  371. }
  372. else {
  373. console.error(`[vite] Internal Server Error\n${err.message}\n${err.stack}`);
  374. }
  375. break;
  376. }
  377. default: {
  378. const check = payload;
  379. return check;
  380. }
  381. }
  382. }
  383. function notifyListeners(event, data) {
  384. const cbs = customListenersMap.get(event);
  385. if (cbs) {
  386. cbs.forEach((cb) => cb(data));
  387. }
  388. }
  389. const enableOverlay = __HMR_ENABLE_OVERLAY__;
  390. function createErrorOverlay(err) {
  391. if (!enableOverlay)
  392. return;
  393. clearErrorOverlay();
  394. document.body.appendChild(new ErrorOverlay(err));
  395. }
  396. function clearErrorOverlay() {
  397. document
  398. .querySelectorAll(overlayId)
  399. .forEach((n) => n.close());
  400. }
  401. function hasErrorOverlay() {
  402. return document.querySelectorAll(overlayId).length;
  403. }
  404. let pending = false;
  405. let queued = [];
  406. /**
  407. * buffer multiple hot updates triggered by the same src change
  408. * so that they are invoked in the same order they were sent.
  409. * (otherwise the order may be inconsistent because of the http request round trip)
  410. */
  411. async function queueUpdate(p) {
  412. queued.push(p);
  413. if (!pending) {
  414. pending = true;
  415. await Promise.resolve();
  416. pending = false;
  417. const loading = [...queued];
  418. queued = [];
  419. (await Promise.all(loading)).forEach((fn) => fn && fn());
  420. }
  421. }
  422. async function waitForSuccessfulPing(socketProtocol, hostAndPath, ms = 1000) {
  423. const pingHostProtocol = socketProtocol === 'wss' ? 'https' : 'http';
  424. // eslint-disable-next-line no-constant-condition
  425. while (true) {
  426. try {
  427. // A fetch on a websocket URL will return a successful promise with status 400,
  428. // but will reject a networking error.
  429. // When running on middleware mode, it returns status 426, and an cors error happens if mode is not no-cors
  430. await fetch(`${pingHostProtocol}://${hostAndPath}`, {
  431. mode: 'no-cors',
  432. });
  433. break;
  434. }
  435. catch (e) {
  436. // wait ms before attempting to ping again
  437. await new Promise((resolve) => setTimeout(resolve, ms));
  438. }
  439. }
  440. }
  441. const sheetsMap = new Map();
  442. // all css imports should be inserted at the same position
  443. // because after build it will be a single css file
  444. let lastInsertedStyle;
  445. function updateStyle(id, content) {
  446. let style = sheetsMap.get(id);
  447. {
  448. if (style && !(style instanceof HTMLStyleElement)) {
  449. removeStyle(id);
  450. style = undefined;
  451. }
  452. if (!style) {
  453. style = document.createElement('style');
  454. style.setAttribute('type', 'text/css');
  455. style.setAttribute('data-vite-dev-id', id);
  456. style.textContent = content;
  457. if (!lastInsertedStyle) {
  458. document.head.appendChild(style);
  459. // reset lastInsertedStyle after async
  460. // because dynamically imported css will be splitted into a different file
  461. setTimeout(() => {
  462. lastInsertedStyle = undefined;
  463. }, 0);
  464. }
  465. else {
  466. lastInsertedStyle.insertAdjacentElement('afterend', style);
  467. }
  468. lastInsertedStyle = style;
  469. }
  470. else {
  471. style.textContent = content;
  472. }
  473. }
  474. sheetsMap.set(id, style);
  475. }
  476. function removeStyle(id) {
  477. const style = sheetsMap.get(id);
  478. if (style) {
  479. if (style instanceof CSSStyleSheet) {
  480. document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => s !== style);
  481. }
  482. else {
  483. document.head.removeChild(style);
  484. }
  485. sheetsMap.delete(id);
  486. }
  487. }
  488. async function fetchUpdate({ path, acceptedPath, timestamp, explicitImportRequired, }) {
  489. const mod = hotModulesMap.get(path);
  490. if (!mod) {
  491. // In a code-splitting project,
  492. // it is common that the hot-updating module is not loaded yet.
  493. // https://github.com/vitejs/vite/issues/721
  494. return;
  495. }
  496. let fetchedModule;
  497. const isSelfUpdate = path === acceptedPath;
  498. // determine the qualified callbacks before we re-import the modules
  499. const qualifiedCallbacks = mod.callbacks.filter(({ deps }) => deps.includes(acceptedPath));
  500. if (isSelfUpdate || qualifiedCallbacks.length > 0) {
  501. const disposer = disposeMap.get(acceptedPath);
  502. if (disposer)
  503. await disposer(dataMap.get(acceptedPath));
  504. const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`);
  505. try {
  506. fetchedModule = await import(
  507. /* @vite-ignore */
  508. base +
  509. acceptedPathWithoutQuery.slice(1) +
  510. `?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${query ? `&${query}` : ''}`);
  511. }
  512. catch (e) {
  513. warnFailedFetch(e, acceptedPath);
  514. }
  515. }
  516. return () => {
  517. for (const { deps, fn } of qualifiedCallbacks) {
  518. fn(deps.map((dep) => (dep === acceptedPath ? fetchedModule : undefined)));
  519. }
  520. const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}`;
  521. console.debug(`[vite] hot updated: ${loggedPath}`);
  522. };
  523. }
  524. function sendMessageBuffer() {
  525. if (socket.readyState === 1) {
  526. messageBuffer.forEach((msg) => socket.send(msg));
  527. messageBuffer.length = 0;
  528. }
  529. }
  530. const hotModulesMap = new Map();
  531. const disposeMap = new Map();
  532. const pruneMap = new Map();
  533. const dataMap = new Map();
  534. const customListenersMap = new Map();
  535. const ctxToListenersMap = new Map();
  536. function createHotContext(ownerPath) {
  537. if (!dataMap.has(ownerPath)) {
  538. dataMap.set(ownerPath, {});
  539. }
  540. // when a file is hot updated, a new context is created
  541. // clear its stale callbacks
  542. const mod = hotModulesMap.get(ownerPath);
  543. if (mod) {
  544. mod.callbacks = [];
  545. }
  546. // clear stale custom event listeners
  547. const staleListeners = ctxToListenersMap.get(ownerPath);
  548. if (staleListeners) {
  549. for (const [event, staleFns] of staleListeners) {
  550. const listeners = customListenersMap.get(event);
  551. if (listeners) {
  552. customListenersMap.set(event, listeners.filter((l) => !staleFns.includes(l)));
  553. }
  554. }
  555. }
  556. const newListeners = new Map();
  557. ctxToListenersMap.set(ownerPath, newListeners);
  558. function acceptDeps(deps, callback = () => { }) {
  559. const mod = hotModulesMap.get(ownerPath) || {
  560. id: ownerPath,
  561. callbacks: [],
  562. };
  563. mod.callbacks.push({
  564. deps,
  565. fn: callback,
  566. });
  567. hotModulesMap.set(ownerPath, mod);
  568. }
  569. const hot = {
  570. get data() {
  571. return dataMap.get(ownerPath);
  572. },
  573. accept(deps, callback) {
  574. if (typeof deps === 'function' || !deps) {
  575. // self-accept: hot.accept(() => {})
  576. acceptDeps([ownerPath], ([mod]) => deps === null || deps === void 0 ? void 0 : deps(mod));
  577. }
  578. else if (typeof deps === 'string') {
  579. // explicit deps
  580. acceptDeps([deps], ([mod]) => callback === null || callback === void 0 ? void 0 : callback(mod));
  581. }
  582. else if (Array.isArray(deps)) {
  583. acceptDeps(deps, callback);
  584. }
  585. else {
  586. throw new Error(`invalid hot.accept() usage.`);
  587. }
  588. },
  589. // export names (first arg) are irrelevant on the client side, they're
  590. // extracted in the server for propagation
  591. acceptExports(_, callback) {
  592. acceptDeps([ownerPath], ([mod]) => callback === null || callback === void 0 ? void 0 : callback(mod));
  593. },
  594. dispose(cb) {
  595. disposeMap.set(ownerPath, cb);
  596. },
  597. prune(cb) {
  598. pruneMap.set(ownerPath, cb);
  599. },
  600. // Kept for backward compatibility (#11036)
  601. // @ts-expect-error untyped
  602. // eslint-disable-next-line @typescript-eslint/no-empty-function
  603. decline() { },
  604. // tell the server to re-perform hmr propagation from this module as root
  605. invalidate(message) {
  606. notifyListeners('vite:invalidate', { path: ownerPath, message });
  607. this.send('vite:invalidate', { path: ownerPath, message });
  608. console.debug(`[vite] invalidate ${ownerPath}${message ? `: ${message}` : ''}`);
  609. },
  610. // custom events
  611. on(event, cb) {
  612. const addToMap = (map) => {
  613. const existing = map.get(event) || [];
  614. existing.push(cb);
  615. map.set(event, existing);
  616. };
  617. addToMap(customListenersMap);
  618. addToMap(newListeners);
  619. },
  620. send(event, data) {
  621. messageBuffer.push(JSON.stringify({ type: 'custom', event, data }));
  622. sendMessageBuffer();
  623. },
  624. };
  625. return hot;
  626. }
  627. /**
  628. * urls here are dynamic import() urls that couldn't be statically analyzed
  629. */
  630. function injectQuery(url, queryToInject) {
  631. // skip urls that won't be handled by vite
  632. if (!url.startsWith('.') && !url.startsWith('/')) {
  633. return url;
  634. }
  635. // can't use pathname from URL since it may be relative like ../
  636. const pathname = url.replace(/#.*$/, '').replace(/\?.*$/, '');
  637. const { search, hash } = new URL(url, 'http://vitejs.dev');
  638. return `${pathname}?${queryToInject}${search ? `&` + search.slice(1) : ''}${hash || ''}`;
  639. }
  640. export { ErrorOverlay, createHotContext, injectQuery, removeStyle, updateStyle };
  641. //# sourceMappingURL=client.mjs.map