-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclient.js
124 lines (99 loc) · 3.15 KB
/
client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
((opt) => {
const { url, reconnectTimeout, retries } = JSON.parse(opt);
const state = {
build: null,
retry: 0,
statusPosted: false,
};
const styles = `
#esbuild-reloader-error-overlay {
z-index: 2147483647;
position: absolute;
background: #fff;
width: 100vw;
height: 100vh;
top: 0;
}
.red { color: #f00; }
pre { padding: 0 16px; font-size: 1.25em;}
h1 { margin: 0; padding: 16px; }
`;
const ensureOverlayElement = () => {
const existing = document.querySelector('#esbuild-reloader-error-overlay');
if (existing !== null) {
return existing;
}
const overlay = document.createElement('div');
overlay.id = "esbuild-reloader-error-overlay";
overlay.innerHTML = `<style>${styles}</style><div id="errors" />`;
document.body.append(overlay);
return overlay;
};
const renderErrorBody = (errors) => {
const errorsContent = errors.map(({ location, text }) => {
const positionInfo = `${location.file}:${location.line}:${location.column}`;
const sourceDecoration = `${location.line} | `;
const errorPointer = "^".repeat(location.length)
const errorPadding = " ".repeat(sourceDecoration.length + location.column);
const pathLine = `> ${positionInfo}: <span class="red">error: </span> ${text}`;
const sourceLine = `${sourceDecoration}${location.lineText}`;
const pointerLine = `<span class="red">${errorPadding}${errorPointer}</span>`;
return `<pre>${pathLine}\n${sourceLine}\n${pointerLine}</pre>`;
});
const overlay = ensureOverlayElement();
overlay.querySelector("#errors").innerHTML = `
<h1>Errors occured during the build:</h1>
${errorsContent}
`;
};
const connect = () => {
return new Promise((resolve) => {
const socket = new WebSocket(url);
socket.addEventListener('open', () => {
if (!state.statusPosted) {
console.info('[Reloader connected]');
state.statusPosted = true;
}
});
socket.addEventListener('error', () => {
socket.close();
resolve(true);
});
socket.addEventListener('message', event => {
const message = JSON.parse(event.data);
if (message.type === 'init') {
if (state.build === null) {
state.build = message.build;
} else if (build.build !== message.build) {
location.reload();
}
}
if (message.type === 'build') {
resolve(false);
location.reload();
}
if (message.type === 'error') {
renderErrorBody(message.errors);
}
});
socket.addEventListener('close', () => resolve(true));
});
};
const shouldRetry = () => (retries === 'always' || state.retry + 1 >= retries);
const wait = () => new Promise((resolve) => setTimeout(resolve, reconnectTimeout));
const loop = async () => {
let looping = true;
while(looping) {
try {
looping = await connect();
} finally {
if (shouldRetry()) {
await wait();
} else {
break;
}
}
}
};
loop();
})(__esbuild_reloader);