27efb683880b3a0b7227a32adba72f6c571948cfbfb06301ae6a664634cd16247e03f1f6875bfd0e709a6243abd18140a9ccbd05df5a046a3428acaf5b6f96 25 KB

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