client.mjs 32 KB

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