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