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.

1091 lines
30 KiB

  1. import '@vite/env';
  2. class HMRContext {
  3. constructor(hmrClient, ownerPath) {
  4. this.hmrClient = hmrClient;
  5. this.ownerPath = ownerPath;
  6. if (!hmrClient.dataMap.has(ownerPath)) {
  7. hmrClient.dataMap.set(ownerPath, {});
  8. }
  9. const mod = hmrClient.hotModulesMap.get(ownerPath);
  10. if (mod) {
  11. mod.callbacks = [];
  12. }
  13. const staleListeners = hmrClient.ctxToListenersMap.get(ownerPath);
  14. if (staleListeners) {
  15. for (const [event, staleFns] of staleListeners) {
  16. const listeners = hmrClient.customListenersMap.get(event);
  17. if (listeners) {
  18. hmrClient.customListenersMap.set(
  19. event,
  20. listeners.filter((l) => !staleFns.includes(l))
  21. );
  22. }
  23. }
  24. }
  25. this.newListeners = /* @__PURE__ */ new Map();
  26. hmrClient.ctxToListenersMap.set(ownerPath, this.newListeners);
  27. }
  28. get data() {
  29. return this.hmrClient.dataMap.get(this.ownerPath);
  30. }
  31. accept(deps, callback) {
  32. if (typeof deps === "function" || !deps) {
  33. this.acceptDeps([this.ownerPath], ([mod]) => deps?.(mod));
  34. } else if (typeof deps === "string") {
  35. this.acceptDeps([deps], ([mod]) => callback?.(mod));
  36. } else if (Array.isArray(deps)) {
  37. this.acceptDeps(deps, callback);
  38. } else {
  39. throw new Error(`invalid hot.accept() usage.`);
  40. }
  41. }
  42. // export names (first arg) are irrelevant on the client side, they're
  43. // extracted in the server for propagation
  44. acceptExports(_, callback) {
  45. this.acceptDeps([this.ownerPath], ([mod]) => callback?.(mod));
  46. }
  47. dispose(cb) {
  48. this.hmrClient.disposeMap.set(this.ownerPath, cb);
  49. }
  50. prune(cb) {
  51. this.hmrClient.pruneMap.set(this.ownerPath, cb);
  52. }
  53. // Kept for backward compatibility (#11036)
  54. // eslint-disable-next-line @typescript-eslint/no-empty-function
  55. decline() {
  56. }
  57. invalidate(message) {
  58. this.hmrClient.notifyListeners("vite:invalidate", {
  59. path: this.ownerPath,
  60. message
  61. });
  62. this.send("vite:invalidate", {
  63. path: this.ownerPath,
  64. message
  65. });
  66. this.hmrClient.logger.debug(
  67. `invalidate ${this.ownerPath}${message ? `: ${message}` : ""}`
  68. );
  69. }
  70. on(event, cb) {
  71. const addToMap = (map) => {
  72. const existing = map.get(event) || [];
  73. existing.push(cb);
  74. map.set(event, existing);
  75. };
  76. addToMap(this.hmrClient.customListenersMap);
  77. addToMap(this.newListeners);
  78. }
  79. off(event, cb) {
  80. const removeFromMap = (map) => {
  81. const existing = map.get(event);
  82. if (existing === void 0) {
  83. return;
  84. }
  85. const pruned = existing.filter((l) => l !== cb);
  86. if (pruned.length === 0) {
  87. map.delete(event);
  88. return;
  89. }
  90. map.set(event, pruned);
  91. };
  92. removeFromMap(this.hmrClient.customListenersMap);
  93. removeFromMap(this.newListeners);
  94. }
  95. send(event, data) {
  96. this.hmrClient.send({ type: "custom", event, data });
  97. }
  98. acceptDeps(deps, callback = () => {
  99. }) {
  100. const mod = this.hmrClient.hotModulesMap.get(this.ownerPath) || {
  101. id: this.ownerPath,
  102. callbacks: []
  103. };
  104. mod.callbacks.push({
  105. deps,
  106. fn: callback
  107. });
  108. this.hmrClient.hotModulesMap.set(this.ownerPath, mod);
  109. }
  110. }
  111. class HMRClient {
  112. constructor(logger, transport, importUpdatedModule) {
  113. this.logger = logger;
  114. this.transport = transport;
  115. this.importUpdatedModule = importUpdatedModule;
  116. this.hotModulesMap = /* @__PURE__ */ new Map();
  117. this.disposeMap = /* @__PURE__ */ new Map();
  118. this.pruneMap = /* @__PURE__ */ new Map();
  119. this.dataMap = /* @__PURE__ */ new Map();
  120. this.customListenersMap = /* @__PURE__ */ new Map();
  121. this.ctxToListenersMap = /* @__PURE__ */ new Map();
  122. this.updateQueue = [];
  123. this.pendingUpdateQueue = false;
  124. }
  125. async notifyListeners(event, data) {
  126. const cbs = this.customListenersMap.get(event);
  127. if (cbs) {
  128. await Promise.allSettled(cbs.map((cb) => cb(data)));
  129. }
  130. }
  131. send(payload) {
  132. this.transport.send(payload).catch((err) => {
  133. this.logger.error(err);
  134. });
  135. }
  136. clear() {
  137. this.hotModulesMap.clear();
  138. this.disposeMap.clear();
  139. this.pruneMap.clear();
  140. this.dataMap.clear();
  141. this.customListenersMap.clear();
  142. this.ctxToListenersMap.clear();
  143. }
  144. // After an HMR update, some modules are no longer imported on the page
  145. // but they may have left behind side effects that need to be cleaned up
  146. // (e.g. style injections)
  147. async prunePaths(paths) {
  148. await Promise.all(
  149. paths.map((path) => {
  150. const disposer = this.disposeMap.get(path);
  151. if (disposer) return disposer(this.dataMap.get(path));
  152. })
  153. );
  154. paths.forEach((path) => {
  155. const fn = this.pruneMap.get(path);
  156. if (fn) {
  157. fn(this.dataMap.get(path));
  158. }
  159. });
  160. }
  161. warnFailedUpdate(err, path) {
  162. if (!err.message.includes("fetch")) {
  163. this.logger.error(err);
  164. }
  165. this.logger.error(
  166. `Failed to reload ${path}. This could be due to syntax errors or importing non-existent modules. (see errors above)`
  167. );
  168. }
  169. /**
  170. * buffer multiple hot updates triggered by the same src change
  171. * so that they are invoked in the same order they were sent.
  172. * (otherwise the order may be inconsistent because of the http request round trip)
  173. */
  174. async queueUpdate(payload) {
  175. this.updateQueue.push(this.fetchUpdate(payload));
  176. if (!this.pendingUpdateQueue) {
  177. this.pendingUpdateQueue = true;
  178. await Promise.resolve();
  179. this.pendingUpdateQueue = false;
  180. const loading = [...this.updateQueue];
  181. this.updateQueue = [];
  182. (await Promise.all(loading)).forEach((fn) => fn && fn());
  183. }
  184. }
  185. async fetchUpdate(update) {
  186. const { path, acceptedPath } = update;
  187. const mod = this.hotModulesMap.get(path);
  188. if (!mod) {
  189. return;
  190. }
  191. let fetchedModule;
  192. const isSelfUpdate = path === acceptedPath;
  193. const qualifiedCallbacks = mod.callbacks.filter(
  194. ({ deps }) => deps.includes(acceptedPath)
  195. );
  196. if (isSelfUpdate || qualifiedCallbacks.length > 0) {
  197. const disposer = this.disposeMap.get(acceptedPath);
  198. if (disposer) await disposer(this.dataMap.get(acceptedPath));
  199. try {
  200. fetchedModule = await this.importUpdatedModule(update);
  201. } catch (e) {
  202. this.warnFailedUpdate(e, acceptedPath);
  203. }
  204. }
  205. return () => {
  206. for (const { deps, fn } of qualifiedCallbacks) {
  207. fn(
  208. deps.map((dep) => dep === acceptedPath ? fetchedModule : void 0)
  209. );
  210. }
  211. const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}`;
  212. this.logger.debug(`hot updated: ${loggedPath}`);
  213. };
  214. }
  215. }
  216. /* @ts-self-types="./index.d.ts" */
  217. let urlAlphabet =
  218. 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
  219. let nanoid = (size = 21) => {
  220. let id = '';
  221. let i = size | 0;
  222. while (i--) {
  223. id += urlAlphabet[(Math.random() * 64) | 0];
  224. }
  225. return id
  226. };
  227. typeof process !== "undefined" && process.platform === "win32";
  228. function promiseWithResolvers() {
  229. let resolve;
  230. let reject;
  231. const promise = new Promise((_resolve, _reject) => {
  232. resolve = _resolve;
  233. reject = _reject;
  234. });
  235. return { promise, resolve, reject };
  236. }
  237. function reviveInvokeError(e) {
  238. const error = new Error(e.message || "Unknown invoke error");
  239. Object.assign(error, e, {
  240. // pass the whole error instead of just the stacktrace
  241. // so that it gets formatted nicely with console.log
  242. runnerError: new Error("RunnerError")
  243. });
  244. return error;
  245. }
  246. const createInvokeableTransport = (transport) => {
  247. if (transport.invoke) {
  248. return {
  249. ...transport,
  250. async invoke(name, data) {
  251. const result = await transport.invoke({
  252. type: "custom",
  253. event: "vite:invoke",
  254. data: {
  255. id: "send",
  256. name,
  257. data
  258. }
  259. });
  260. if ("error" in result) {
  261. throw reviveInvokeError(result.error);
  262. }
  263. return result.result;
  264. }
  265. };
  266. }
  267. if (!transport.send || !transport.connect) {
  268. throw new Error(
  269. "transport must implement send and connect when invoke is not implemented"
  270. );
  271. }
  272. const rpcPromises = /* @__PURE__ */ new Map();
  273. return {
  274. ...transport,
  275. connect({ onMessage, onDisconnection }) {
  276. return transport.connect({
  277. onMessage(payload) {
  278. if (payload.type === "custom" && payload.event === "vite:invoke") {
  279. const data = payload.data;
  280. if (data.id.startsWith("response:")) {
  281. const invokeId = data.id.slice("response:".length);
  282. const promise = rpcPromises.get(invokeId);
  283. if (!promise) return;
  284. if (promise.timeoutId) clearTimeout(promise.timeoutId);
  285. rpcPromises.delete(invokeId);
  286. const { error, result } = data.data;
  287. if (error) {
  288. promise.reject(error);
  289. } else {
  290. promise.resolve(result);
  291. }
  292. return;
  293. }
  294. }
  295. onMessage(payload);
  296. },
  297. onDisconnection
  298. });
  299. },
  300. disconnect() {
  301. rpcPromises.forEach((promise) => {
  302. promise.reject(
  303. new Error(
  304. `transport was disconnected, cannot call ${JSON.stringify(promise.name)}`
  305. )
  306. );
  307. });
  308. rpcPromises.clear();
  309. return transport.disconnect?.();
  310. },
  311. send(data) {
  312. return transport.send(data);
  313. },
  314. async invoke(name, data) {
  315. const promiseId = nanoid();
  316. const wrappedData = {
  317. type: "custom",
  318. event: "vite:invoke",
  319. data: {
  320. name,
  321. id: `send:${promiseId}`,
  322. data
  323. }
  324. };
  325. const sendPromise = transport.send(wrappedData);
  326. const { promise, resolve, reject } = promiseWithResolvers();
  327. const timeout = transport.timeout ?? 6e4;
  328. let timeoutId;
  329. if (timeout > 0) {
  330. timeoutId = setTimeout(() => {
  331. rpcPromises.delete(promiseId);
  332. reject(
  333. new Error(
  334. `transport invoke timed out after ${timeout}ms (data: ${JSON.stringify(wrappedData)})`
  335. )
  336. );
  337. }, timeout);
  338. timeoutId?.unref?.();
  339. }
  340. rpcPromises.set(promiseId, { resolve, reject, name, timeoutId });
  341. if (sendPromise) {
  342. sendPromise.catch((err) => {
  343. clearTimeout(timeoutId);
  344. rpcPromises.delete(promiseId);
  345. reject(err);
  346. });
  347. }
  348. try {
  349. return await promise;
  350. } catch (err) {
  351. throw reviveInvokeError(err);
  352. }
  353. }
  354. };
  355. };
  356. const normalizeModuleRunnerTransport = (transport) => {
  357. const invokeableTransport = createInvokeableTransport(transport);
  358. let isConnected = !invokeableTransport.connect;
  359. let connectingPromise;
  360. return {
  361. ...transport,
  362. ...invokeableTransport.connect ? {
  363. async connect(onMessage) {
  364. if (isConnected) return;
  365. if (connectingPromise) {
  366. await connectingPromise;
  367. return;
  368. }
  369. const maybePromise = invokeableTransport.connect({
  370. onMessage: onMessage ?? (() => {
  371. }),
  372. onDisconnection() {
  373. isConnected = false;
  374. }
  375. });
  376. if (maybePromise) {
  377. connectingPromise = maybePromise;
  378. await connectingPromise;
  379. connectingPromise = void 0;
  380. }
  381. isConnected = true;
  382. }
  383. } : {},
  384. ...invokeableTransport.disconnect ? {
  385. async disconnect() {
  386. if (!isConnected) return;
  387. if (connectingPromise) {
  388. await connectingPromise;
  389. }
  390. isConnected = false;
  391. await invokeableTransport.disconnect();
  392. }
  393. } : {},
  394. async send(data) {
  395. if (!invokeableTransport.send) return;
  396. if (!isConnected) {
  397. if (connectingPromise) {
  398. await connectingPromise;
  399. } else {
  400. throw new Error("send was called before connect");
  401. }
  402. }
  403. await invokeableTransport.send(data);
  404. },
  405. async invoke(name, data) {
  406. if (!isConnected) {
  407. if (connectingPromise) {
  408. await connectingPromise;
  409. } else {
  410. throw new Error("invoke was called before connect");
  411. }
  412. }
  413. return invokeableTransport.invoke(name, data);
  414. }
  415. };
  416. };
  417. const createWebSocketModuleRunnerTransport = (options) => {
  418. const pingInterval = options.pingInterval ?? 3e4;
  419. let ws;
  420. let pingIntervalId;
  421. return {
  422. async connect({ onMessage, onDisconnection }) {
  423. const socket = options.createConnection();
  424. socket.addEventListener("message", async ({ data }) => {
  425. onMessage(JSON.parse(data));
  426. });
  427. let isOpened = socket.readyState === socket.OPEN;
  428. if (!isOpened) {
  429. await new Promise((resolve, reject) => {
  430. socket.addEventListener(
  431. "open",
  432. () => {
  433. isOpened = true;
  434. resolve();
  435. },
  436. { once: true }
  437. );
  438. socket.addEventListener("close", async () => {
  439. if (!isOpened) {
  440. reject(new Error("WebSocket closed without opened."));
  441. return;
  442. }
  443. onMessage({
  444. type: "custom",
  445. event: "vite:ws:disconnect",
  446. data: { webSocket: socket }
  447. });
  448. onDisconnection();
  449. });
  450. });
  451. }
  452. onMessage({
  453. type: "custom",
  454. event: "vite:ws:connect",
  455. data: { webSocket: socket }
  456. });
  457. ws = socket;
  458. pingIntervalId = setInterval(() => {
  459. if (socket.readyState === socket.OPEN) {
  460. socket.send(JSON.stringify({ type: "ping" }));
  461. }
  462. }, pingInterval);
  463. },
  464. disconnect() {
  465. clearInterval(pingIntervalId);
  466. ws?.close();
  467. },
  468. send(data) {
  469. ws.send(JSON.stringify(data));
  470. }
  471. };
  472. };
  473. const hmrConfigName = __HMR_CONFIG_NAME__;
  474. const base$1 = __BASE__ || "/";
  475. function h(e, attrs = {}, ...children) {
  476. const elem = document.createElement(e);
  477. for (const [k, v] of Object.entries(attrs)) {
  478. elem.setAttribute(k, v);
  479. }
  480. elem.append(...children);
  481. return elem;
  482. }
  483. const templateStyle = (
  484. /*css*/
  485. `
  486. :host {
  487. position: fixed;
  488. top: 0;
  489. left: 0;
  490. width: 100%;
  491. height: 100%;
  492. z-index: 99999;
  493. --monospace: 'SFMono-Regular', Consolas,
  494. 'Liberation Mono', Menlo, Courier, monospace;
  495. --red: #ff5555;
  496. --yellow: #e2aa53;
  497. --purple: #cfa4ff;
  498. --cyan: #2dd9da;
  499. --dim: #c9c9c9;
  500. --window-background: #181818;
  501. --window-color: #d8d8d8;
  502. }
  503. .backdrop {
  504. position: fixed;
  505. z-index: 99999;
  506. top: 0;
  507. left: 0;
  508. width: 100%;
  509. height: 100%;
  510. overflow-y: scroll;
  511. margin: 0;
  512. background: rgba(0, 0, 0, 0.66);
  513. }
  514. .window {
  515. font-family: var(--monospace);
  516. line-height: 1.5;
  517. max-width: 80vw;
  518. color: var(--window-color);
  519. box-sizing: border-box;
  520. margin: 30px auto;
  521. padding: 2.5vh 4vw;
  522. position: relative;
  523. background: var(--window-background);
  524. border-radius: 6px 6px 8px 8px;
  525. box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);
  526. overflow: hidden;
  527. border-top: 8px solid var(--red);
  528. direction: ltr;
  529. text-align: left;
  530. }
  531. pre {
  532. font-family: var(--monospace);
  533. font-size: 16px;
  534. margin-top: 0;
  535. margin-bottom: 1em;
  536. overflow-x: scroll;
  537. scrollbar-width: none;
  538. }
  539. pre::-webkit-scrollbar {
  540. display: none;
  541. }
  542. pre.frame::-webkit-scrollbar {
  543. display: block;
  544. height: 5px;
  545. }
  546. pre.frame::-webkit-scrollbar-thumb {
  547. background: #999;
  548. border-radius: 5px;
  549. }
  550. pre.frame {
  551. scrollbar-width: thin;
  552. }
  553. .message {
  554. line-height: 1.3;
  555. font-weight: 600;
  556. white-space: pre-wrap;
  557. }
  558. .message-body {
  559. color: var(--red);
  560. }
  561. .plugin {
  562. color: var(--purple);
  563. }
  564. .file {
  565. color: var(--cyan);
  566. margin-bottom: 0;
  567. white-space: pre-wrap;
  568. word-break: break-all;
  569. }
  570. .frame {
  571. color: var(--yellow);
  572. }
  573. .stack {
  574. font-size: 13px;
  575. color: var(--dim);
  576. }
  577. .tip {
  578. font-size: 13px;
  579. color: #999;
  580. border-top: 1px dotted #999;
  581. padding-top: 13px;
  582. line-height: 1.8;
  583. }
  584. code {
  585. font-size: 13px;
  586. font-family: var(--monospace);
  587. color: var(--yellow);
  588. }
  589. .file-link {
  590. text-decoration: underline;
  591. cursor: pointer;
  592. }
  593. kbd {
  594. line-height: 1.5;
  595. font-family: ui-monospace, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  596. font-size: 0.75rem;
  597. font-weight: 700;
  598. background-color: rgb(38, 40, 44);
  599. color: rgb(166, 167, 171);
  600. padding: 0.15rem 0.3rem;
  601. border-radius: 0.25rem;
  602. border-width: 0.0625rem 0.0625rem 0.1875rem;
  603. border-style: solid;
  604. border-color: rgb(54, 57, 64);
  605. border-image: initial;
  606. }
  607. `
  608. );
  609. const createTemplate = () => h(
  610. "div",
  611. { class: "backdrop", part: "backdrop" },
  612. h(
  613. "div",
  614. { class: "window", part: "window" },
  615. h(
  616. "pre",
  617. { class: "message", part: "message" },
  618. h("span", { class: "plugin", part: "plugin" }),
  619. h("span", { class: "message-body", part: "message-body" })
  620. ),
  621. h("pre", { class: "file", part: "file" }),
  622. h("pre", { class: "frame", part: "frame" }),
  623. h("pre", { class: "stack", part: "stack" }),
  624. h(
  625. "div",
  626. { class: "tip", part: "tip" },
  627. "Click outside, press ",
  628. h("kbd", {}, "Esc"),
  629. " key, or fix the code to dismiss.",
  630. h("br"),
  631. "You can also disable this overlay by setting ",
  632. h("code", { part: "config-option-name" }, "server.hmr.overlay"),
  633. " to ",
  634. h("code", { part: "config-option-value" }, "false"),
  635. " in ",
  636. h("code", { part: "config-file-name" }, hmrConfigName),
  637. "."
  638. )
  639. ),
  640. h("style", {}, templateStyle)
  641. );
  642. const fileRE = /(?:[a-zA-Z]:\\|\/).*?:\d+:\d+/g;
  643. const codeframeRE = /^(?:>?\s*\d+\s+\|.*|\s+\|\s*\^.*)\r?\n/gm;
  644. const { HTMLElement = class {
  645. } } = globalThis;
  646. class ErrorOverlay extends HTMLElement {
  647. constructor(err, links = true) {
  648. super();
  649. this.root = this.attachShadow({ mode: "open" });
  650. this.root.appendChild(createTemplate());
  651. codeframeRE.lastIndex = 0;
  652. const hasFrame = err.frame && codeframeRE.test(err.frame);
  653. const message = hasFrame ? err.message.replace(codeframeRE, "") : err.message;
  654. if (err.plugin) {
  655. this.text(".plugin", `[plugin:${err.plugin}] `);
  656. }
  657. this.text(".message-body", message.trim());
  658. const [file] = (err.loc?.file || err.id || "unknown file").split(`?`);
  659. if (err.loc) {
  660. this.text(".file", `${file}:${err.loc.line}:${err.loc.column}`, links);
  661. } else if (err.id) {
  662. this.text(".file", file);
  663. }
  664. if (hasFrame) {
  665. this.text(".frame", err.frame.trim());
  666. }
  667. this.text(".stack", err.stack, links);
  668. this.root.querySelector(".window").addEventListener("click", (e) => {
  669. e.stopPropagation();
  670. });
  671. this.addEventListener("click", () => {
  672. this.close();
  673. });
  674. this.closeOnEsc = (e) => {
  675. if (e.key === "Escape" || e.code === "Escape") {
  676. this.close();
  677. }
  678. };
  679. document.addEventListener("keydown", this.closeOnEsc);
  680. }
  681. text(selector, text, linkFiles = false) {
  682. const el = this.root.querySelector(selector);
  683. if (!linkFiles) {
  684. el.textContent = text;
  685. } else {
  686. let curIndex = 0;
  687. let match;
  688. fileRE.lastIndex = 0;
  689. while (match = fileRE.exec(text)) {
  690. const { 0: file, index } = match;
  691. const frag = text.slice(curIndex, index);
  692. el.appendChild(document.createTextNode(frag));
  693. const link = document.createElement("a");
  694. link.textContent = file;
  695. link.className = "file-link";
  696. link.onclick = () => {
  697. fetch(
  698. new URL(
  699. `${base$1}__open-in-editor?file=${encodeURIComponent(file)}`,
  700. import.meta.url
  701. )
  702. );
  703. };
  704. el.appendChild(link);
  705. curIndex += frag.length + file.length;
  706. }
  707. }
  708. }
  709. close() {
  710. this.parentNode?.removeChild(this);
  711. document.removeEventListener("keydown", this.closeOnEsc);
  712. }
  713. }
  714. const overlayId = "vite-error-overlay";
  715. const { customElements } = globalThis;
  716. if (customElements && !customElements.get(overlayId)) {
  717. customElements.define(overlayId, ErrorOverlay);
  718. }
  719. console.debug("[vite] connecting...");
  720. const importMetaUrl = new URL(import.meta.url);
  721. const serverHost = __SERVER_HOST__;
  722. const socketProtocol = __HMR_PROTOCOL__ || (importMetaUrl.protocol === "https:" ? "wss" : "ws");
  723. const hmrPort = __HMR_PORT__;
  724. const socketHost = `${__HMR_HOSTNAME__ || importMetaUrl.hostname}:${hmrPort || importMetaUrl.port}${__HMR_BASE__}`;
  725. const directSocketHost = __HMR_DIRECT_TARGET__;
  726. const base = __BASE__ || "/";
  727. const hmrTimeout = __HMR_TIMEOUT__;
  728. const wsToken = __WS_TOKEN__;
  729. const transport = normalizeModuleRunnerTransport(
  730. (() => {
  731. let wsTransport = createWebSocketModuleRunnerTransport({
  732. createConnection: () => new WebSocket(
  733. `${socketProtocol}://${socketHost}?token=${wsToken}`,
  734. "vite-hmr"
  735. ),
  736. pingInterval: hmrTimeout
  737. });
  738. return {
  739. async connect(handlers) {
  740. try {
  741. await wsTransport.connect(handlers);
  742. } catch (e) {
  743. if (!hmrPort) {
  744. wsTransport = createWebSocketModuleRunnerTransport({
  745. createConnection: () => new WebSocket(
  746. `${socketProtocol}://${directSocketHost}?token=${wsToken}`,
  747. "vite-hmr"
  748. ),
  749. pingInterval: hmrTimeout
  750. });
  751. try {
  752. await wsTransport.connect(handlers);
  753. console.info(
  754. "[vite] Direct websocket connection fallback. Check out https://vite.dev/config/server-options.html#server-hmr to remove the previous connection error."
  755. );
  756. } catch (e2) {
  757. if (e2 instanceof Error && e2.message.includes("WebSocket closed without opened.")) {
  758. const currentScriptHostURL = new URL(import.meta.url);
  759. const currentScriptHost = currentScriptHostURL.host + currentScriptHostURL.pathname.replace(/@vite\/client$/, "");
  760. console.error(
  761. `[vite] failed to connect to websocket.
  762. your current setup:
  763. (browser) ${currentScriptHost} <--[HTTP]--> ${serverHost} (server)
  764. (browser) ${socketHost} <--[WebSocket (failing)]--> ${directSocketHost} (server)
  765. Check out your Vite / network configuration and https://vite.dev/config/server-options.html#server-hmr .`
  766. );
  767. }
  768. }
  769. return;
  770. }
  771. console.error(`[vite] failed to connect to websocket (${e}). `);
  772. throw e;
  773. }
  774. },
  775. async disconnect() {
  776. await wsTransport.disconnect();
  777. },
  778. send(data) {
  779. wsTransport.send(data);
  780. }
  781. };
  782. })()
  783. );
  784. let willUnload = false;
  785. if (typeof window !== "undefined") {
  786. window.addEventListener("beforeunload", () => {
  787. willUnload = true;
  788. });
  789. }
  790. function cleanUrl(pathname) {
  791. const url = new URL(pathname, "http://vite.dev");
  792. url.searchParams.delete("direct");
  793. return url.pathname + url.search;
  794. }
  795. let isFirstUpdate = true;
  796. const outdatedLinkTags = /* @__PURE__ */ new WeakSet();
  797. const debounceReload = (time) => {
  798. let timer;
  799. return () => {
  800. if (timer) {
  801. clearTimeout(timer);
  802. timer = null;
  803. }
  804. timer = setTimeout(() => {
  805. location.reload();
  806. }, time);
  807. };
  808. };
  809. const pageReload = debounceReload(50);
  810. const hmrClient = new HMRClient(
  811. {
  812. error: (err) => console.error("[vite]", err),
  813. debug: (...msg) => console.debug("[vite]", ...msg)
  814. },
  815. transport,
  816. async function importUpdatedModule({
  817. acceptedPath,
  818. timestamp,
  819. explicitImportRequired,
  820. isWithinCircularImport
  821. }) {
  822. const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`);
  823. const importPromise = import(
  824. /* @vite-ignore */
  825. base + acceptedPathWithoutQuery.slice(1) + `?${explicitImportRequired ? "import&" : ""}t=${timestamp}${query ? `&${query}` : ""}`
  826. );
  827. if (isWithinCircularImport) {
  828. importPromise.catch(() => {
  829. console.info(
  830. `[hmr] ${acceptedPath} failed to apply HMR as it's within a circular import. Reloading page to reset the execution order. To debug and break the circular import, you can run \`vite --debug hmr\` to log the circular dependency path if a file change triggered it.`
  831. );
  832. pageReload();
  833. });
  834. }
  835. return await importPromise;
  836. }
  837. );
  838. transport.connect(handleMessage);
  839. async function handleMessage(payload) {
  840. switch (payload.type) {
  841. case "connected":
  842. console.debug(`[vite] connected.`);
  843. break;
  844. case "update":
  845. notifyListeners("vite:beforeUpdate", payload);
  846. if (hasDocument) {
  847. if (isFirstUpdate && hasErrorOverlay()) {
  848. location.reload();
  849. return;
  850. } else {
  851. if (enableOverlay) {
  852. clearErrorOverlay();
  853. }
  854. isFirstUpdate = false;
  855. }
  856. }
  857. await Promise.all(
  858. payload.updates.map(async (update) => {
  859. if (update.type === "js-update") {
  860. return hmrClient.queueUpdate(update);
  861. }
  862. const { path, timestamp } = update;
  863. const searchUrl = cleanUrl(path);
  864. const el = Array.from(
  865. document.querySelectorAll("link")
  866. ).find(
  867. (e) => !outdatedLinkTags.has(e) && cleanUrl(e.href).includes(searchUrl)
  868. );
  869. if (!el) {
  870. return;
  871. }
  872. const newPath = `${base}${searchUrl.slice(1)}${searchUrl.includes("?") ? "&" : "?"}t=${timestamp}`;
  873. return new Promise((resolve) => {
  874. const newLinkTag = el.cloneNode();
  875. newLinkTag.href = new URL(newPath, el.href).href;
  876. const removeOldEl = () => {
  877. el.remove();
  878. console.debug(`[vite] css hot updated: ${searchUrl}`);
  879. resolve();
  880. };
  881. newLinkTag.addEventListener("load", removeOldEl);
  882. newLinkTag.addEventListener("error", removeOldEl);
  883. outdatedLinkTags.add(el);
  884. el.after(newLinkTag);
  885. });
  886. })
  887. );
  888. notifyListeners("vite:afterUpdate", payload);
  889. break;
  890. case "custom": {
  891. notifyListeners(payload.event, payload.data);
  892. if (payload.event === "vite:ws:disconnect") {
  893. if (hasDocument && !willUnload) {
  894. console.log(`[vite] server connection lost. Polling for restart...`);
  895. const socket = payload.data.webSocket;
  896. const url = new URL(socket.url);
  897. url.search = "";
  898. await waitForSuccessfulPing(url.href);
  899. location.reload();
  900. }
  901. }
  902. break;
  903. }
  904. case "full-reload":
  905. notifyListeners("vite:beforeFullReload", payload);
  906. if (hasDocument) {
  907. if (payload.path && payload.path.endsWith(".html")) {
  908. const pagePath = decodeURI(location.pathname);
  909. const payloadPath = base + payload.path.slice(1);
  910. if (pagePath === payloadPath || payload.path === "/index.html" || pagePath.endsWith("/") && pagePath + "index.html" === payloadPath) {
  911. pageReload();
  912. }
  913. return;
  914. } else {
  915. pageReload();
  916. }
  917. }
  918. break;
  919. case "prune":
  920. notifyListeners("vite:beforePrune", payload);
  921. await hmrClient.prunePaths(payload.paths);
  922. break;
  923. case "error": {
  924. notifyListeners("vite:error", payload);
  925. if (hasDocument) {
  926. const err = payload.err;
  927. if (enableOverlay) {
  928. createErrorOverlay(err);
  929. } else {
  930. console.error(
  931. `[vite] Internal Server Error
  932. ${err.message}
  933. ${err.stack}`
  934. );
  935. }
  936. }
  937. break;
  938. }
  939. case "ping":
  940. break;
  941. default: {
  942. const check = payload;
  943. return check;
  944. }
  945. }
  946. }
  947. function notifyListeners(event, data) {
  948. hmrClient.notifyListeners(event, data);
  949. }
  950. const enableOverlay = __HMR_ENABLE_OVERLAY__;
  951. const hasDocument = "document" in globalThis;
  952. function createErrorOverlay(err) {
  953. clearErrorOverlay();
  954. const { customElements } = globalThis;
  955. if (customElements) {
  956. const ErrorOverlayConstructor = customElements.get(overlayId);
  957. document.body.appendChild(new ErrorOverlayConstructor(err));
  958. }
  959. }
  960. function clearErrorOverlay() {
  961. document.querySelectorAll(overlayId).forEach((n) => n.close());
  962. }
  963. function hasErrorOverlay() {
  964. return document.querySelectorAll(overlayId).length;
  965. }
  966. async function waitForSuccessfulPing(socketUrl, ms = 1e3) {
  967. async function ping() {
  968. const socket = new WebSocket(socketUrl, "vite-ping");
  969. return new Promise((resolve) => {
  970. function onOpen() {
  971. resolve(true);
  972. close();
  973. }
  974. function onError() {
  975. resolve(false);
  976. close();
  977. }
  978. function close() {
  979. socket.removeEventListener("open", onOpen);
  980. socket.removeEventListener("error", onError);
  981. socket.close();
  982. }
  983. socket.addEventListener("open", onOpen);
  984. socket.addEventListener("error", onError);
  985. });
  986. }
  987. if (await ping()) {
  988. return;
  989. }
  990. await wait(ms);
  991. while (true) {
  992. if (document.visibilityState === "visible") {
  993. if (await ping()) {
  994. break;
  995. }
  996. await wait(ms);
  997. } else {
  998. await waitForWindowShow();
  999. }
  1000. }
  1001. }
  1002. function wait(ms) {
  1003. return new Promise((resolve) => setTimeout(resolve, ms));
  1004. }
  1005. function waitForWindowShow() {
  1006. return new Promise((resolve) => {
  1007. const onChange = async () => {
  1008. if (document.visibilityState === "visible") {
  1009. resolve();
  1010. document.removeEventListener("visibilitychange", onChange);
  1011. }
  1012. };
  1013. document.addEventListener("visibilitychange", onChange);
  1014. });
  1015. }
  1016. const sheetsMap = /* @__PURE__ */ new Map();
  1017. if ("document" in globalThis) {
  1018. document.querySelectorAll("style[data-vite-dev-id]").forEach((el) => {
  1019. sheetsMap.set(el.getAttribute("data-vite-dev-id"), el);
  1020. });
  1021. }
  1022. const cspNonce = "document" in globalThis ? document.querySelector("meta[property=csp-nonce]")?.nonce : void 0;
  1023. let lastInsertedStyle;
  1024. function updateStyle(id, content) {
  1025. let style = sheetsMap.get(id);
  1026. if (!style) {
  1027. style = document.createElement("style");
  1028. style.setAttribute("type", "text/css");
  1029. style.setAttribute("data-vite-dev-id", id);
  1030. style.textContent = content;
  1031. if (cspNonce) {
  1032. style.setAttribute("nonce", cspNonce);
  1033. }
  1034. if (!lastInsertedStyle) {
  1035. document.head.appendChild(style);
  1036. setTimeout(() => {
  1037. lastInsertedStyle = void 0;
  1038. }, 0);
  1039. } else {
  1040. lastInsertedStyle.insertAdjacentElement("afterend", style);
  1041. }
  1042. lastInsertedStyle = style;
  1043. } else {
  1044. style.textContent = content;
  1045. }
  1046. sheetsMap.set(id, style);
  1047. }
  1048. function removeStyle(id) {
  1049. const style = sheetsMap.get(id);
  1050. if (style) {
  1051. document.head.removeChild(style);
  1052. sheetsMap.delete(id);
  1053. }
  1054. }
  1055. function createHotContext(ownerPath) {
  1056. return new HMRContext(hmrClient, ownerPath);
  1057. }
  1058. function injectQuery(url, queryToInject) {
  1059. if (url[0] !== "." && url[0] !== "/") {
  1060. return url;
  1061. }
  1062. const pathname = url.replace(/[?#].*$/, "");
  1063. const { search, hash } = new URL(url, "http://vite.dev");
  1064. return `${pathname}?${queryToInject}${search ? `&` + search.slice(1) : ""}${hash || ""}`;
  1065. }
  1066. export { ErrorOverlay, createHotContext, injectQuery, removeStyle, updateStyle };