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