1 | import '@vite/env';
|
---|
2 |
|
---|
3 | class HMRContext {
|
---|
4 | constructor(hmrClient, ownerPath) {
|
---|
5 | this.hmrClient = hmrClient;
|
---|
6 | this.ownerPath = ownerPath;
|
---|
7 | if (!hmrClient.dataMap.has(ownerPath)) {
|
---|
8 | hmrClient.dataMap.set(ownerPath, {});
|
---|
9 | }
|
---|
10 | const mod = hmrClient.hotModulesMap.get(ownerPath);
|
---|
11 | if (mod) {
|
---|
12 | mod.callbacks = [];
|
---|
13 | }
|
---|
14 | const staleListeners = hmrClient.ctxToListenersMap.get(ownerPath);
|
---|
15 | if (staleListeners) {
|
---|
16 | for (const [event, staleFns] of staleListeners) {
|
---|
17 | const listeners = hmrClient.customListenersMap.get(event);
|
---|
18 | if (listeners) {
|
---|
19 | hmrClient.customListenersMap.set(
|
---|
20 | event,
|
---|
21 | listeners.filter((l) => !staleFns.includes(l))
|
---|
22 | );
|
---|
23 | }
|
---|
24 | }
|
---|
25 | }
|
---|
26 | this.newListeners = /* @__PURE__ */ new Map();
|
---|
27 | hmrClient.ctxToListenersMap.set(ownerPath, this.newListeners);
|
---|
28 | }
|
---|
29 | get data() {
|
---|
30 | return this.hmrClient.dataMap.get(this.ownerPath);
|
---|
31 | }
|
---|
32 | accept(deps, callback) {
|
---|
33 | if (typeof deps === "function" || !deps) {
|
---|
34 | this.acceptDeps([this.ownerPath], ([mod]) => deps?.(mod));
|
---|
35 | } else if (typeof deps === "string") {
|
---|
36 | this.acceptDeps([deps], ([mod]) => callback?.(mod));
|
---|
37 | } else if (Array.isArray(deps)) {
|
---|
38 | this.acceptDeps(deps, callback);
|
---|
39 | } else {
|
---|
40 | throw new Error(`invalid hot.accept() usage.`);
|
---|
41 | }
|
---|
42 | }
|
---|
43 | // export names (first arg) are irrelevant on the client side, they're
|
---|
44 | // extracted in the server for propagation
|
---|
45 | acceptExports(_, callback) {
|
---|
46 | this.acceptDeps([this.ownerPath], ([mod]) => callback?.(mod));
|
---|
47 | }
|
---|
48 | dispose(cb) {
|
---|
49 | this.hmrClient.disposeMap.set(this.ownerPath, cb);
|
---|
50 | }
|
---|
51 | prune(cb) {
|
---|
52 | this.hmrClient.pruneMap.set(this.ownerPath, cb);
|
---|
53 | }
|
---|
54 | // Kept for backward compatibility (#11036)
|
---|
55 | // eslint-disable-next-line @typescript-eslint/no-empty-function
|
---|
56 | decline() {
|
---|
57 | }
|
---|
58 | invalidate(message) {
|
---|
59 | this.hmrClient.notifyListeners("vite:invalidate", {
|
---|
60 | path: this.ownerPath,
|
---|
61 | message
|
---|
62 | });
|
---|
63 | this.send("vite:invalidate", { path: this.ownerPath, message });
|
---|
64 | this.hmrClient.logger.debug(
|
---|
65 | `[vite] invalidate ${this.ownerPath}${message ? `: ${message}` : ""}`
|
---|
66 | );
|
---|
67 | }
|
---|
68 | on(event, cb) {
|
---|
69 | const addToMap = (map) => {
|
---|
70 | const existing = map.get(event) || [];
|
---|
71 | existing.push(cb);
|
---|
72 | map.set(event, existing);
|
---|
73 | };
|
---|
74 | addToMap(this.hmrClient.customListenersMap);
|
---|
75 | addToMap(this.newListeners);
|
---|
76 | }
|
---|
77 | off(event, cb) {
|
---|
78 | const removeFromMap = (map) => {
|
---|
79 | const existing = map.get(event);
|
---|
80 | if (existing === void 0) {
|
---|
81 | return;
|
---|
82 | }
|
---|
83 | const pruned = existing.filter((l) => l !== cb);
|
---|
84 | if (pruned.length === 0) {
|
---|
85 | map.delete(event);
|
---|
86 | return;
|
---|
87 | }
|
---|
88 | map.set(event, pruned);
|
---|
89 | };
|
---|
90 | removeFromMap(this.hmrClient.customListenersMap);
|
---|
91 | removeFromMap(this.newListeners);
|
---|
92 | }
|
---|
93 | send(event, data) {
|
---|
94 | this.hmrClient.messenger.send(
|
---|
95 | JSON.stringify({ type: "custom", event, data })
|
---|
96 | );
|
---|
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 HMRMessenger {
|
---|
112 | constructor(connection) {
|
---|
113 | this.connection = connection;
|
---|
114 | this.queue = [];
|
---|
115 | }
|
---|
116 | send(message) {
|
---|
117 | this.queue.push(message);
|
---|
118 | this.flush();
|
---|
119 | }
|
---|
120 | flush() {
|
---|
121 | if (this.connection.isReady()) {
|
---|
122 | this.queue.forEach((msg) => this.connection.send(msg));
|
---|
123 | this.queue = [];
|
---|
124 | }
|
---|
125 | }
|
---|
126 | }
|
---|
127 | class HMRClient {
|
---|
128 | constructor(logger, connection, importUpdatedModule) {
|
---|
129 | this.logger = logger;
|
---|
130 | this.importUpdatedModule = importUpdatedModule;
|
---|
131 | this.hotModulesMap = /* @__PURE__ */ new Map();
|
---|
132 | this.disposeMap = /* @__PURE__ */ new Map();
|
---|
133 | this.pruneMap = /* @__PURE__ */ new Map();
|
---|
134 | this.dataMap = /* @__PURE__ */ new Map();
|
---|
135 | this.customListenersMap = /* @__PURE__ */ new Map();
|
---|
136 | this.ctxToListenersMap = /* @__PURE__ */ new Map();
|
---|
137 | this.updateQueue = [];
|
---|
138 | this.pendingUpdateQueue = false;
|
---|
139 | this.messenger = new HMRMessenger(connection);
|
---|
140 | }
|
---|
141 | async notifyListeners(event, data) {
|
---|
142 | const cbs = this.customListenersMap.get(event);
|
---|
143 | if (cbs) {
|
---|
144 | await Promise.allSettled(cbs.map((cb) => cb(data)));
|
---|
145 | }
|
---|
146 | }
|
---|
147 | clear() {
|
---|
148 | this.hotModulesMap.clear();
|
---|
149 | this.disposeMap.clear();
|
---|
150 | this.pruneMap.clear();
|
---|
151 | this.dataMap.clear();
|
---|
152 | this.customListenersMap.clear();
|
---|
153 | this.ctxToListenersMap.clear();
|
---|
154 | }
|
---|
155 | // After an HMR update, some modules are no longer imported on the page
|
---|
156 | // but they may have left behind side effects that need to be cleaned up
|
---|
157 | // (.e.g style injections)
|
---|
158 | async prunePaths(paths) {
|
---|
159 | await Promise.all(
|
---|
160 | paths.map((path) => {
|
---|
161 | const disposer = this.disposeMap.get(path);
|
---|
162 | if (disposer) return disposer(this.dataMap.get(path));
|
---|
163 | })
|
---|
164 | );
|
---|
165 | paths.forEach((path) => {
|
---|
166 | const fn = this.pruneMap.get(path);
|
---|
167 | if (fn) {
|
---|
168 | fn(this.dataMap.get(path));
|
---|
169 | }
|
---|
170 | });
|
---|
171 | }
|
---|
172 | warnFailedUpdate(err, path) {
|
---|
173 | if (!err.message.includes("fetch")) {
|
---|
174 | this.logger.error(err);
|
---|
175 | }
|
---|
176 | this.logger.error(
|
---|
177 | `[hmr] Failed to reload ${path}. This could be due to syntax errors or importing non-existent modules. (see errors above)`
|
---|
178 | );
|
---|
179 | }
|
---|
180 | /**
|
---|
181 | * buffer multiple hot updates triggered by the same src change
|
---|
182 | * so that they are invoked in the same order they were sent.
|
---|
183 | * (otherwise the order may be inconsistent because of the http request round trip)
|
---|
184 | */
|
---|
185 | async queueUpdate(payload) {
|
---|
186 | this.updateQueue.push(this.fetchUpdate(payload));
|
---|
187 | if (!this.pendingUpdateQueue) {
|
---|
188 | this.pendingUpdateQueue = true;
|
---|
189 | await Promise.resolve();
|
---|
190 | this.pendingUpdateQueue = false;
|
---|
191 | const loading = [...this.updateQueue];
|
---|
192 | this.updateQueue = [];
|
---|
193 | (await Promise.all(loading)).forEach((fn) => fn && fn());
|
---|
194 | }
|
---|
195 | }
|
---|
196 | async fetchUpdate(update) {
|
---|
197 | const { path, acceptedPath } = update;
|
---|
198 | const mod = this.hotModulesMap.get(path);
|
---|
199 | if (!mod) {
|
---|
200 | return;
|
---|
201 | }
|
---|
202 | let fetchedModule;
|
---|
203 | const isSelfUpdate = path === acceptedPath;
|
---|
204 | const qualifiedCallbacks = mod.callbacks.filter(
|
---|
205 | ({ deps }) => deps.includes(acceptedPath)
|
---|
206 | );
|
---|
207 | if (isSelfUpdate || qualifiedCallbacks.length > 0) {
|
---|
208 | const disposer = this.disposeMap.get(acceptedPath);
|
---|
209 | if (disposer) await disposer(this.dataMap.get(acceptedPath));
|
---|
210 | try {
|
---|
211 | fetchedModule = await this.importUpdatedModule(update);
|
---|
212 | } catch (e) {
|
---|
213 | this.warnFailedUpdate(e, acceptedPath);
|
---|
214 | }
|
---|
215 | }
|
---|
216 | return () => {
|
---|
217 | for (const { deps, fn } of qualifiedCallbacks) {
|
---|
218 | fn(
|
---|
219 | deps.map((dep) => dep === acceptedPath ? fetchedModule : void 0)
|
---|
220 | );
|
---|
221 | }
|
---|
222 | const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}`;
|
---|
223 | this.logger.debug(`[vite] hot updated: ${loggedPath}`);
|
---|
224 | };
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | const hmrConfigName = __HMR_CONFIG_NAME__;
|
---|
229 | const base$1 = __BASE__ || "/";
|
---|
230 | function h(e, attrs = {}, ...children) {
|
---|
231 | const elem = document.createElement(e);
|
---|
232 | for (const [k, v] of Object.entries(attrs)) {
|
---|
233 | elem.setAttribute(k, v);
|
---|
234 | }
|
---|
235 | elem.append(...children);
|
---|
236 | return elem;
|
---|
237 | }
|
---|
238 | const templateStyle = (
|
---|
239 | /*css*/
|
---|
240 | `
|
---|
241 | :host {
|
---|
242 | position: fixed;
|
---|
243 | top: 0;
|
---|
244 | left: 0;
|
---|
245 | width: 100%;
|
---|
246 | height: 100%;
|
---|
247 | z-index: 99999;
|
---|
248 | --monospace: 'SFMono-Regular', Consolas,
|
---|
249 | 'Liberation Mono', Menlo, Courier, monospace;
|
---|
250 | --red: #ff5555;
|
---|
251 | --yellow: #e2aa53;
|
---|
252 | --purple: #cfa4ff;
|
---|
253 | --cyan: #2dd9da;
|
---|
254 | --dim: #c9c9c9;
|
---|
255 |
|
---|
256 | --window-background: #181818;
|
---|
257 | --window-color: #d8d8d8;
|
---|
258 | }
|
---|
259 |
|
---|
260 | .backdrop {
|
---|
261 | position: fixed;
|
---|
262 | z-index: 99999;
|
---|
263 | top: 0;
|
---|
264 | left: 0;
|
---|
265 | width: 100%;
|
---|
266 | height: 100%;
|
---|
267 | overflow-y: scroll;
|
---|
268 | margin: 0;
|
---|
269 | background: rgba(0, 0, 0, 0.66);
|
---|
270 | }
|
---|
271 |
|
---|
272 | .window {
|
---|
273 | font-family: var(--monospace);
|
---|
274 | line-height: 1.5;
|
---|
275 | max-width: 80vw;
|
---|
276 | color: var(--window-color);
|
---|
277 | box-sizing: border-box;
|
---|
278 | margin: 30px auto;
|
---|
279 | padding: 2.5vh 4vw;
|
---|
280 | position: relative;
|
---|
281 | background: var(--window-background);
|
---|
282 | border-radius: 6px 6px 8px 8px;
|
---|
283 | box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);
|
---|
284 | overflow: hidden;
|
---|
285 | border-top: 8px solid var(--red);
|
---|
286 | direction: ltr;
|
---|
287 | text-align: left;
|
---|
288 | }
|
---|
289 |
|
---|
290 | pre {
|
---|
291 | font-family: var(--monospace);
|
---|
292 | font-size: 16px;
|
---|
293 | margin-top: 0;
|
---|
294 | margin-bottom: 1em;
|
---|
295 | overflow-x: scroll;
|
---|
296 | scrollbar-width: none;
|
---|
297 | }
|
---|
298 |
|
---|
299 | pre::-webkit-scrollbar {
|
---|
300 | display: none;
|
---|
301 | }
|
---|
302 |
|
---|
303 | pre.frame::-webkit-scrollbar {
|
---|
304 | display: block;
|
---|
305 | height: 5px;
|
---|
306 | }
|
---|
307 |
|
---|
308 | pre.frame::-webkit-scrollbar-thumb {
|
---|
309 | background: #999;
|
---|
310 | border-radius: 5px;
|
---|
311 | }
|
---|
312 |
|
---|
313 | pre.frame {
|
---|
314 | scrollbar-width: thin;
|
---|
315 | }
|
---|
316 |
|
---|
317 | .message {
|
---|
318 | line-height: 1.3;
|
---|
319 | font-weight: 600;
|
---|
320 | white-space: pre-wrap;
|
---|
321 | }
|
---|
322 |
|
---|
323 | .message-body {
|
---|
324 | color: var(--red);
|
---|
325 | }
|
---|
326 |
|
---|
327 | .plugin {
|
---|
328 | color: var(--purple);
|
---|
329 | }
|
---|
330 |
|
---|
331 | .file {
|
---|
332 | color: var(--cyan);
|
---|
333 | margin-bottom: 0;
|
---|
334 | white-space: pre-wrap;
|
---|
335 | word-break: break-all;
|
---|
336 | }
|
---|
337 |
|
---|
338 | .frame {
|
---|
339 | color: var(--yellow);
|
---|
340 | }
|
---|
341 |
|
---|
342 | .stack {
|
---|
343 | font-size: 13px;
|
---|
344 | color: var(--dim);
|
---|
345 | }
|
---|
346 |
|
---|
347 | .tip {
|
---|
348 | font-size: 13px;
|
---|
349 | color: #999;
|
---|
350 | border-top: 1px dotted #999;
|
---|
351 | padding-top: 13px;
|
---|
352 | line-height: 1.8;
|
---|
353 | }
|
---|
354 |
|
---|
355 | code {
|
---|
356 | font-size: 13px;
|
---|
357 | font-family: var(--monospace);
|
---|
358 | color: var(--yellow);
|
---|
359 | }
|
---|
360 |
|
---|
361 | .file-link {
|
---|
362 | text-decoration: underline;
|
---|
363 | cursor: pointer;
|
---|
364 | }
|
---|
365 |
|
---|
366 | kbd {
|
---|
367 | line-height: 1.5;
|
---|
368 | font-family: ui-monospace, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
---|
369 | font-size: 0.75rem;
|
---|
370 | font-weight: 700;
|
---|
371 | background-color: rgb(38, 40, 44);
|
---|
372 | color: rgb(166, 167, 171);
|
---|
373 | padding: 0.15rem 0.3rem;
|
---|
374 | border-radius: 0.25rem;
|
---|
375 | border-width: 0.0625rem 0.0625rem 0.1875rem;
|
---|
376 | border-style: solid;
|
---|
377 | border-color: rgb(54, 57, 64);
|
---|
378 | border-image: initial;
|
---|
379 | }
|
---|
380 | `
|
---|
381 | );
|
---|
382 | const createTemplate = () => h(
|
---|
383 | "div",
|
---|
384 | { class: "backdrop", part: "backdrop" },
|
---|
385 | h(
|
---|
386 | "div",
|
---|
387 | { class: "window", part: "window" },
|
---|
388 | h(
|
---|
389 | "pre",
|
---|
390 | { class: "message", part: "message" },
|
---|
391 | h("span", { class: "plugin", part: "plugin" }),
|
---|
392 | h("span", { class: "message-body", part: "message-body" })
|
---|
393 | ),
|
---|
394 | h("pre", { class: "file", part: "file" }),
|
---|
395 | h("pre", { class: "frame", part: "frame" }),
|
---|
396 | h("pre", { class: "stack", part: "stack" }),
|
---|
397 | h(
|
---|
398 | "div",
|
---|
399 | { class: "tip", part: "tip" },
|
---|
400 | "Click outside, press ",
|
---|
401 | h("kbd", {}, "Esc"),
|
---|
402 | " key, or fix the code to dismiss.",
|
---|
403 | h("br"),
|
---|
404 | "You can also disable this overlay by setting ",
|
---|
405 | h("code", { part: "config-option-name" }, "server.hmr.overlay"),
|
---|
406 | " to ",
|
---|
407 | h("code", { part: "config-option-value" }, "false"),
|
---|
408 | " in ",
|
---|
409 | h("code", { part: "config-file-name" }, hmrConfigName),
|
---|
410 | "."
|
---|
411 | )
|
---|
412 | ),
|
---|
413 | h("style", {}, templateStyle)
|
---|
414 | );
|
---|
415 | const fileRE = /(?:[a-zA-Z]:\\|\/).*?:\d+:\d+/g;
|
---|
416 | const codeframeRE = /^(?:>?\s*\d+\s+\|.*|\s+\|\s*\^.*)\r?\n/gm;
|
---|
417 | const { HTMLElement = class {
|
---|
418 | } } = globalThis;
|
---|
419 | class ErrorOverlay extends HTMLElement {
|
---|
420 | constructor(err, links = true) {
|
---|
421 | super();
|
---|
422 | this.root = this.attachShadow({ mode: "open" });
|
---|
423 | this.root.appendChild(createTemplate());
|
---|
424 | codeframeRE.lastIndex = 0;
|
---|
425 | const hasFrame = err.frame && codeframeRE.test(err.frame);
|
---|
426 | const message = hasFrame ? err.message.replace(codeframeRE, "") : err.message;
|
---|
427 | if (err.plugin) {
|
---|
428 | this.text(".plugin", `[plugin:${err.plugin}] `);
|
---|
429 | }
|
---|
430 | this.text(".message-body", message.trim());
|
---|
431 | const [file] = (err.loc?.file || err.id || "unknown file").split(`?`);
|
---|
432 | if (err.loc) {
|
---|
433 | this.text(".file", `${file}:${err.loc.line}:${err.loc.column}`, links);
|
---|
434 | } else if (err.id) {
|
---|
435 | this.text(".file", file);
|
---|
436 | }
|
---|
437 | if (hasFrame) {
|
---|
438 | this.text(".frame", err.frame.trim());
|
---|
439 | }
|
---|
440 | this.text(".stack", err.stack, links);
|
---|
441 | this.root.querySelector(".window").addEventListener("click", (e) => {
|
---|
442 | e.stopPropagation();
|
---|
443 | });
|
---|
444 | this.addEventListener("click", () => {
|
---|
445 | this.close();
|
---|
446 | });
|
---|
447 | this.closeOnEsc = (e) => {
|
---|
448 | if (e.key === "Escape" || e.code === "Escape") {
|
---|
449 | this.close();
|
---|
450 | }
|
---|
451 | };
|
---|
452 | document.addEventListener("keydown", this.closeOnEsc);
|
---|
453 | }
|
---|
454 | text(selector, text, linkFiles = false) {
|
---|
455 | const el = this.root.querySelector(selector);
|
---|
456 | if (!linkFiles) {
|
---|
457 | el.textContent = text;
|
---|
458 | } else {
|
---|
459 | let curIndex = 0;
|
---|
460 | let match;
|
---|
461 | fileRE.lastIndex = 0;
|
---|
462 | while (match = fileRE.exec(text)) {
|
---|
463 | const { 0: file, index } = match;
|
---|
464 | if (index != null) {
|
---|
465 | const frag = text.slice(curIndex, index);
|
---|
466 | el.appendChild(document.createTextNode(frag));
|
---|
467 | const link = document.createElement("a");
|
---|
468 | link.textContent = file;
|
---|
469 | link.className = "file-link";
|
---|
470 | link.onclick = () => {
|
---|
471 | fetch(
|
---|
472 | new URL(
|
---|
473 | `${base$1}__open-in-editor?file=${encodeURIComponent(file)}`,
|
---|
474 | import.meta.url
|
---|
475 | )
|
---|
476 | );
|
---|
477 | };
|
---|
478 | el.appendChild(link);
|
---|
479 | curIndex += frag.length + file.length;
|
---|
480 | }
|
---|
481 | }
|
---|
482 | }
|
---|
483 | }
|
---|
484 | close() {
|
---|
485 | this.parentNode?.removeChild(this);
|
---|
486 | document.removeEventListener("keydown", this.closeOnEsc);
|
---|
487 | }
|
---|
488 | }
|
---|
489 | const overlayId = "vite-error-overlay";
|
---|
490 | const { customElements } = globalThis;
|
---|
491 | if (customElements && !customElements.get(overlayId)) {
|
---|
492 | customElements.define(overlayId, ErrorOverlay);
|
---|
493 | }
|
---|
494 |
|
---|
495 | console.debug("[vite] connecting...");
|
---|
496 | const importMetaUrl = new URL(import.meta.url);
|
---|
497 | const serverHost = __SERVER_HOST__;
|
---|
498 | const socketProtocol = __HMR_PROTOCOL__ || (importMetaUrl.protocol === "https:" ? "wss" : "ws");
|
---|
499 | const hmrPort = __HMR_PORT__;
|
---|
500 | const socketHost = `${__HMR_HOSTNAME__ || importMetaUrl.hostname}:${hmrPort || importMetaUrl.port}${__HMR_BASE__}`;
|
---|
501 | const directSocketHost = __HMR_DIRECT_TARGET__;
|
---|
502 | const base = __BASE__ || "/";
|
---|
503 | let socket;
|
---|
504 | try {
|
---|
505 | let fallback;
|
---|
506 | if (!hmrPort) {
|
---|
507 | fallback = () => {
|
---|
508 | socket = setupWebSocket(socketProtocol, directSocketHost, () => {
|
---|
509 | const currentScriptHostURL = new URL(import.meta.url);
|
---|
510 | const currentScriptHost = currentScriptHostURL.host + currentScriptHostURL.pathname.replace(/@vite\/client$/, "");
|
---|
511 | console.error(
|
---|
512 | `[vite] failed to connect to websocket.
|
---|
513 | your current setup:
|
---|
514 | (browser) ${currentScriptHost} <--[HTTP]--> ${serverHost} (server)
|
---|
515 | (browser) ${socketHost} <--[WebSocket (failing)]--> ${directSocketHost} (server)
|
---|
516 | Check out your Vite / network configuration and https://vitejs.dev/config/server-options.html#server-hmr .`
|
---|
517 | );
|
---|
518 | });
|
---|
519 | socket.addEventListener(
|
---|
520 | "open",
|
---|
521 | () => {
|
---|
522 | console.info(
|
---|
523 | "[vite] Direct websocket connection fallback. Check out https://vitejs.dev/config/server-options.html#server-hmr to remove the previous connection error."
|
---|
524 | );
|
---|
525 | },
|
---|
526 | { once: true }
|
---|
527 | );
|
---|
528 | };
|
---|
529 | }
|
---|
530 | socket = setupWebSocket(socketProtocol, socketHost, fallback);
|
---|
531 | } catch (error) {
|
---|
532 | console.error(`[vite] failed to connect to websocket (${error}). `);
|
---|
533 | }
|
---|
534 | function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {
|
---|
535 | const socket2 = new WebSocket(`${protocol}://${hostAndPath}`, "vite-hmr");
|
---|
536 | let isOpened = false;
|
---|
537 | socket2.addEventListener(
|
---|
538 | "open",
|
---|
539 | () => {
|
---|
540 | isOpened = true;
|
---|
541 | notifyListeners("vite:ws:connect", { webSocket: socket2 });
|
---|
542 | },
|
---|
543 | { once: true }
|
---|
544 | );
|
---|
545 | socket2.addEventListener("message", async ({ data }) => {
|
---|
546 | handleMessage(JSON.parse(data));
|
---|
547 | });
|
---|
548 | socket2.addEventListener("close", async ({ wasClean }) => {
|
---|
549 | if (wasClean) return;
|
---|
550 | if (!isOpened && onCloseWithoutOpen) {
|
---|
551 | onCloseWithoutOpen();
|
---|
552 | return;
|
---|
553 | }
|
---|
554 | notifyListeners("vite:ws:disconnect", { webSocket: socket2 });
|
---|
555 | if (hasDocument) {
|
---|
556 | console.log(`[vite] server connection lost. Polling for restart...`);
|
---|
557 | await waitForSuccessfulPing(protocol, hostAndPath);
|
---|
558 | location.reload();
|
---|
559 | }
|
---|
560 | });
|
---|
561 | return socket2;
|
---|
562 | }
|
---|
563 | function cleanUrl(pathname) {
|
---|
564 | const url = new URL(pathname, "http://vitejs.dev");
|
---|
565 | url.searchParams.delete("direct");
|
---|
566 | return url.pathname + url.search;
|
---|
567 | }
|
---|
568 | let isFirstUpdate = true;
|
---|
569 | const outdatedLinkTags = /* @__PURE__ */ new WeakSet();
|
---|
570 | const debounceReload = (time) => {
|
---|
571 | let timer;
|
---|
572 | return () => {
|
---|
573 | if (timer) {
|
---|
574 | clearTimeout(timer);
|
---|
575 | timer = null;
|
---|
576 | }
|
---|
577 | timer = setTimeout(() => {
|
---|
578 | location.reload();
|
---|
579 | }, time);
|
---|
580 | };
|
---|
581 | };
|
---|
582 | const pageReload = debounceReload(50);
|
---|
583 | const hmrClient = new HMRClient(
|
---|
584 | console,
|
---|
585 | {
|
---|
586 | isReady: () => socket && socket.readyState === 1,
|
---|
587 | send: (message) => socket.send(message)
|
---|
588 | },
|
---|
589 | async function importUpdatedModule({
|
---|
590 | acceptedPath,
|
---|
591 | timestamp,
|
---|
592 | explicitImportRequired,
|
---|
593 | isWithinCircularImport
|
---|
594 | }) {
|
---|
595 | const [acceptedPathWithoutQuery, query] = acceptedPath.split(`?`);
|
---|
596 | const importPromise = import(
|
---|
597 | /* @vite-ignore */
|
---|
598 | base + acceptedPathWithoutQuery.slice(1) + `?${explicitImportRequired ? "import&" : ""}t=${timestamp}${query ? `&${query}` : ""}`
|
---|
599 | );
|
---|
600 | if (isWithinCircularImport) {
|
---|
601 | importPromise.catch(() => {
|
---|
602 | console.info(
|
---|
603 | `[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.`
|
---|
604 | );
|
---|
605 | pageReload();
|
---|
606 | });
|
---|
607 | }
|
---|
608 | return await importPromise;
|
---|
609 | }
|
---|
610 | );
|
---|
611 | async function handleMessage(payload) {
|
---|
612 | switch (payload.type) {
|
---|
613 | case "connected":
|
---|
614 | console.debug(`[vite] connected.`);
|
---|
615 | hmrClient.messenger.flush();
|
---|
616 | setInterval(() => {
|
---|
617 | if (socket.readyState === socket.OPEN) {
|
---|
618 | socket.send('{"type":"ping"}');
|
---|
619 | }
|
---|
620 | }, __HMR_TIMEOUT__);
|
---|
621 | break;
|
---|
622 | case "update":
|
---|
623 | notifyListeners("vite:beforeUpdate", payload);
|
---|
624 | if (hasDocument) {
|
---|
625 | if (isFirstUpdate && hasErrorOverlay()) {
|
---|
626 | location.reload();
|
---|
627 | return;
|
---|
628 | } else {
|
---|
629 | if (enableOverlay) {
|
---|
630 | clearErrorOverlay();
|
---|
631 | }
|
---|
632 | isFirstUpdate = false;
|
---|
633 | }
|
---|
634 | }
|
---|
635 | await Promise.all(
|
---|
636 | payload.updates.map(async (update) => {
|
---|
637 | if (update.type === "js-update") {
|
---|
638 | return hmrClient.queueUpdate(update);
|
---|
639 | }
|
---|
640 | const { path, timestamp } = update;
|
---|
641 | const searchUrl = cleanUrl(path);
|
---|
642 | const el = Array.from(
|
---|
643 | document.querySelectorAll("link")
|
---|
644 | ).find(
|
---|
645 | (e) => !outdatedLinkTags.has(e) && cleanUrl(e.href).includes(searchUrl)
|
---|
646 | );
|
---|
647 | if (!el) {
|
---|
648 | return;
|
---|
649 | }
|
---|
650 | const newPath = `${base}${searchUrl.slice(1)}${searchUrl.includes("?") ? "&" : "?"}t=${timestamp}`;
|
---|
651 | return new Promise((resolve) => {
|
---|
652 | const newLinkTag = el.cloneNode();
|
---|
653 | newLinkTag.href = new URL(newPath, el.href).href;
|
---|
654 | const removeOldEl = () => {
|
---|
655 | el.remove();
|
---|
656 | console.debug(`[vite] css hot updated: ${searchUrl}`);
|
---|
657 | resolve();
|
---|
658 | };
|
---|
659 | newLinkTag.addEventListener("load", removeOldEl);
|
---|
660 | newLinkTag.addEventListener("error", removeOldEl);
|
---|
661 | outdatedLinkTags.add(el);
|
---|
662 | el.after(newLinkTag);
|
---|
663 | });
|
---|
664 | })
|
---|
665 | );
|
---|
666 | notifyListeners("vite:afterUpdate", payload);
|
---|
667 | break;
|
---|
668 | case "custom": {
|
---|
669 | notifyListeners(payload.event, payload.data);
|
---|
670 | break;
|
---|
671 | }
|
---|
672 | case "full-reload":
|
---|
673 | notifyListeners("vite:beforeFullReload", payload);
|
---|
674 | if (hasDocument) {
|
---|
675 | if (payload.path && payload.path.endsWith(".html")) {
|
---|
676 | const pagePath = decodeURI(location.pathname);
|
---|
677 | const payloadPath = base + payload.path.slice(1);
|
---|
678 | if (pagePath === payloadPath || payload.path === "/index.html" || pagePath.endsWith("/") && pagePath + "index.html" === payloadPath) {
|
---|
679 | pageReload();
|
---|
680 | }
|
---|
681 | return;
|
---|
682 | } else {
|
---|
683 | pageReload();
|
---|
684 | }
|
---|
685 | }
|
---|
686 | break;
|
---|
687 | case "prune":
|
---|
688 | notifyListeners("vite:beforePrune", payload);
|
---|
689 | await hmrClient.prunePaths(payload.paths);
|
---|
690 | break;
|
---|
691 | case "error": {
|
---|
692 | notifyListeners("vite:error", payload);
|
---|
693 | if (hasDocument) {
|
---|
694 | const err = payload.err;
|
---|
695 | if (enableOverlay) {
|
---|
696 | createErrorOverlay(err);
|
---|
697 | } else {
|
---|
698 | console.error(
|
---|
699 | `[vite] Internal Server Error
|
---|
700 | ${err.message}
|
---|
701 | ${err.stack}`
|
---|
702 | );
|
---|
703 | }
|
---|
704 | }
|
---|
705 | break;
|
---|
706 | }
|
---|
707 | default: {
|
---|
708 | const check = payload;
|
---|
709 | return check;
|
---|
710 | }
|
---|
711 | }
|
---|
712 | }
|
---|
713 | function notifyListeners(event, data) {
|
---|
714 | hmrClient.notifyListeners(event, data);
|
---|
715 | }
|
---|
716 | const enableOverlay = __HMR_ENABLE_OVERLAY__;
|
---|
717 | const hasDocument = "document" in globalThis;
|
---|
718 | function createErrorOverlay(err) {
|
---|
719 | clearErrorOverlay();
|
---|
720 | document.body.appendChild(new ErrorOverlay(err));
|
---|
721 | }
|
---|
722 | function clearErrorOverlay() {
|
---|
723 | document.querySelectorAll(overlayId).forEach((n) => n.close());
|
---|
724 | }
|
---|
725 | function hasErrorOverlay() {
|
---|
726 | return document.querySelectorAll(overlayId).length;
|
---|
727 | }
|
---|
728 | async function waitForSuccessfulPing(socketProtocol2, hostAndPath, ms = 1e3) {
|
---|
729 | const pingHostProtocol = socketProtocol2 === "wss" ? "https" : "http";
|
---|
730 | const ping = async () => {
|
---|
731 | try {
|
---|
732 | await fetch(`${pingHostProtocol}://${hostAndPath}`, {
|
---|
733 | mode: "no-cors",
|
---|
734 | headers: {
|
---|
735 | // Custom headers won't be included in a request with no-cors so (ab)use one of the
|
---|
736 | // safelisted headers to identify the ping request
|
---|
737 | Accept: "text/x-vite-ping"
|
---|
738 | }
|
---|
739 | });
|
---|
740 | return true;
|
---|
741 | } catch {
|
---|
742 | }
|
---|
743 | return false;
|
---|
744 | };
|
---|
745 | if (await ping()) {
|
---|
746 | return;
|
---|
747 | }
|
---|
748 | await wait(ms);
|
---|
749 | while (true) {
|
---|
750 | if (document.visibilityState === "visible") {
|
---|
751 | if (await ping()) {
|
---|
752 | break;
|
---|
753 | }
|
---|
754 | await wait(ms);
|
---|
755 | } else {
|
---|
756 | await waitForWindowShow();
|
---|
757 | }
|
---|
758 | }
|
---|
759 | }
|
---|
760 | function wait(ms) {
|
---|
761 | return new Promise((resolve) => setTimeout(resolve, ms));
|
---|
762 | }
|
---|
763 | function waitForWindowShow() {
|
---|
764 | return new Promise((resolve) => {
|
---|
765 | const onChange = async () => {
|
---|
766 | if (document.visibilityState === "visible") {
|
---|
767 | resolve();
|
---|
768 | document.removeEventListener("visibilitychange", onChange);
|
---|
769 | }
|
---|
770 | };
|
---|
771 | document.addEventListener("visibilitychange", onChange);
|
---|
772 | });
|
---|
773 | }
|
---|
774 | const sheetsMap = /* @__PURE__ */ new Map();
|
---|
775 | if ("document" in globalThis) {
|
---|
776 | document.querySelectorAll("style[data-vite-dev-id]").forEach((el) => {
|
---|
777 | sheetsMap.set(el.getAttribute("data-vite-dev-id"), el);
|
---|
778 | });
|
---|
779 | }
|
---|
780 | const cspNonce = "document" in globalThis ? document.querySelector("meta[property=csp-nonce]")?.nonce : void 0;
|
---|
781 | let lastInsertedStyle;
|
---|
782 | function updateStyle(id, content) {
|
---|
783 | let style = sheetsMap.get(id);
|
---|
784 | if (!style) {
|
---|
785 | style = document.createElement("style");
|
---|
786 | style.setAttribute("type", "text/css");
|
---|
787 | style.setAttribute("data-vite-dev-id", id);
|
---|
788 | style.textContent = content;
|
---|
789 | if (cspNonce) {
|
---|
790 | style.setAttribute("nonce", cspNonce);
|
---|
791 | }
|
---|
792 | if (!lastInsertedStyle) {
|
---|
793 | document.head.appendChild(style);
|
---|
794 | setTimeout(() => {
|
---|
795 | lastInsertedStyle = void 0;
|
---|
796 | }, 0);
|
---|
797 | } else {
|
---|
798 | lastInsertedStyle.insertAdjacentElement("afterend", style);
|
---|
799 | }
|
---|
800 | lastInsertedStyle = style;
|
---|
801 | } else {
|
---|
802 | style.textContent = content;
|
---|
803 | }
|
---|
804 | sheetsMap.set(id, style);
|
---|
805 | }
|
---|
806 | function removeStyle(id) {
|
---|
807 | const style = sheetsMap.get(id);
|
---|
808 | if (style) {
|
---|
809 | document.head.removeChild(style);
|
---|
810 | sheetsMap.delete(id);
|
---|
811 | }
|
---|
812 | }
|
---|
813 | function createHotContext(ownerPath) {
|
---|
814 | return new HMRContext(hmrClient, ownerPath);
|
---|
815 | }
|
---|
816 | function injectQuery(url, queryToInject) {
|
---|
817 | if (url[0] !== "." && url[0] !== "/") {
|
---|
818 | return url;
|
---|
819 | }
|
---|
820 | const pathname = url.replace(/[?#].*$/, "");
|
---|
821 | const { search, hash } = new URL(url, "http://vitejs.dev");
|
---|
822 | return `${pathname}?${queryToInject}${search ? `&` + search.slice(1) : ""}${hash || ""}`;
|
---|
823 | }
|
---|
824 |
|
---|
825 | export { ErrorOverlay, createHotContext, injectQuery, removeStyle, updateStyle };
|
---|