html-bundle 6.3.0 → 6.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.mjs +0 -0
- package/dist/utils.mjs +67 -10
- package/package.json +2 -2
- package/src/utils.mts +76 -16
- package/tests/bundle.test.mjs +7 -0
package/dist/bundle.mjs
CHANGED
|
File without changes
|
package/dist/utils.mjs
CHANGED
|
@@ -19,23 +19,31 @@ export function createDir(file) {
|
|
|
19
19
|
export function getBuildPath(file) {
|
|
20
20
|
return file.replace(`${bundleConfig.src}/`, `${bundleConfig.build}/`);
|
|
21
21
|
}
|
|
22
|
-
const CONNECTIONS =
|
|
22
|
+
const CONNECTIONS = new Set(); // In order to send the HMR information
|
|
23
23
|
export let serverSentEvents;
|
|
24
24
|
export async function createDefaultServer(isSecure) {
|
|
25
25
|
const router = express.Router();
|
|
26
26
|
const app = express();
|
|
27
27
|
app.use(router);
|
|
28
28
|
app.use(express.static(path.join(process.cwd(), bundleConfig.build)));
|
|
29
|
-
router.get("/hmr", (
|
|
29
|
+
router.get("/hmr", (req, reply) => {
|
|
30
30
|
reply.setHeader("Content-Type", "text/event-stream");
|
|
31
31
|
reply.setHeader("Cache-Control", "no-cache");
|
|
32
32
|
!isSecure && reply.setHeader("Connection", "keep-alive");
|
|
33
|
-
|
|
33
|
+
reply.flushHeaders();
|
|
34
|
+
CONNECTIONS.add(reply);
|
|
35
|
+
req.on("close", () => {
|
|
36
|
+
CONNECTIONS.delete(reply);
|
|
37
|
+
});
|
|
34
38
|
serverSentEvents = (data) => {
|
|
35
39
|
if (/\.(jsx?|tsx?)$/.test(data.file)) {
|
|
36
40
|
data.file = data.file.replace(".ts", ".js").replace(".jsx", ".js");
|
|
37
41
|
}
|
|
38
42
|
CONNECTIONS.forEach((rep) => {
|
|
43
|
+
if (rep.destroyed || rep.writableEnded) {
|
|
44
|
+
CONNECTIONS.delete(rep);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
39
47
|
rep.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
40
48
|
});
|
|
41
49
|
};
|
|
@@ -118,14 +126,50 @@ function getHMRCode(file, id, src) {
|
|
|
118
126
|
return `import { render, html, $, $$, setShouldSetReactivity } from "hydro-js";
|
|
119
127
|
window.isHMR = true;
|
|
120
128
|
window.lastCalled = new Map();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
window.htmlBundleHMRConnections ||= new Map();
|
|
130
|
+
window.htmlBundleHMRActiveId = "${id}";
|
|
131
|
+
let shouldReconnect = true;
|
|
132
|
+
let reconnectTimer;
|
|
133
|
+
|
|
134
|
+
for (const [hmrId, eventSource] of window.htmlBundleHMRConnections) {
|
|
135
|
+
if (hmrId !== "${id}") {
|
|
136
|
+
eventSource.close();
|
|
137
|
+
window.htmlBundleHMRConnections.delete(hmrId);
|
|
138
|
+
delete window["eventsource" + hmrId];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function closeEventSource() {
|
|
143
|
+
const eventSource = window.eventsource${id};
|
|
144
|
+
if (eventSource) {
|
|
145
|
+
eventSource.close();
|
|
146
|
+
window.htmlBundleHMRConnections.delete("${id}");
|
|
147
|
+
delete window.eventsource${id};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function connectEventSource() {
|
|
152
|
+
closeEventSource();
|
|
153
|
+
shouldReconnect = true;
|
|
154
|
+
|
|
155
|
+
const eventSource = new EventSource("/hmr");
|
|
156
|
+
window.eventsource${id} = eventSource;
|
|
157
|
+
window.htmlBundleHMRConnections.set("${id}", eventSource);
|
|
158
|
+
|
|
159
|
+
eventSource.addEventListener('error', () => {
|
|
160
|
+
eventSource.close();
|
|
161
|
+
if (window.eventsource${id} === eventSource) {
|
|
162
|
+
window.htmlBundleHMRConnections.delete("${id}");
|
|
163
|
+
delete window.eventsource${id};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (shouldReconnect && window.htmlBundleHMRActiveId === "${id}") {
|
|
167
|
+
clearTimeout(reconnectTimer);
|
|
168
|
+
reconnectTimer = setTimeout(connectEventSource, 1000);
|
|
169
|
+
}
|
|
127
170
|
});
|
|
128
|
-
|
|
171
|
+
|
|
172
|
+
eventSource.addEventListener("message", ({ data }) => {
|
|
129
173
|
if (window.lastScroll == null) {
|
|
130
174
|
window.lastScroll = window.scrollY;
|
|
131
175
|
}
|
|
@@ -231,5 +275,18 @@ function getHMRCode(file, id, src) {
|
|
|
231
275
|
}
|
|
232
276
|
});
|
|
233
277
|
}
|
|
278
|
+
|
|
279
|
+
window.addEventListener("pagehide", () => {
|
|
280
|
+
shouldReconnect = false;
|
|
281
|
+
clearTimeout(reconnectTimer);
|
|
282
|
+
if (window.htmlBundleHMRActiveId === "${id}") {
|
|
283
|
+
delete window.htmlBundleHMRActiveId;
|
|
284
|
+
}
|
|
285
|
+
closeEventSource();
|
|
286
|
+
}, { once: true });
|
|
287
|
+
|
|
288
|
+
if (!window.eventsource${id}) {
|
|
289
|
+
connectEventSource();
|
|
290
|
+
}
|
|
234
291
|
`;
|
|
235
292
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html-bundle",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.1",
|
|
4
4
|
"description": "A very simple bundler for HTML SFC",
|
|
5
5
|
"bin": "./dist/bundle.mjs",
|
|
6
6
|
"main": "./dist/bundle.mjs",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"types": "./dist/bundle.d.mts",
|
|
13
13
|
"scripts": {
|
|
14
|
-
"start": "tsc",
|
|
14
|
+
"start": "tsc && node -e \"require('fs').chmodSync('dist/bundle.mjs', 0o755)\"",
|
|
15
15
|
"test": "npm run start && node --test tests/*.test.mjs",
|
|
16
16
|
"update": "npx npm-check-updates -u && npx typesync && npm i && npm outdated"
|
|
17
17
|
},
|
package/src/utils.mts
CHANGED
|
@@ -32,28 +32,39 @@ export function getBuildPath(file: string) {
|
|
|
32
32
|
return file.replace(`${bundleConfig.src}/`, `${bundleConfig.build}/`);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const CONNECTIONS
|
|
35
|
+
const CONNECTIONS = new Set<any>(); // In order to send the HMR information
|
|
36
36
|
export let serverSentEvents:
|
|
37
37
|
| undefined
|
|
38
38
|
| (({ file, html }: { file: string; html?: string }) => void);
|
|
39
39
|
export async function createDefaultServer(
|
|
40
|
-
isSecure: boolean
|
|
40
|
+
isSecure: boolean,
|
|
41
41
|
): Promise<[Router, Server | HTTPSServer]> {
|
|
42
42
|
const router = express.Router();
|
|
43
43
|
const app = express();
|
|
44
44
|
app.use(router);
|
|
45
45
|
app.use(express.static(path.join(process.cwd(), bundleConfig.build)));
|
|
46
46
|
|
|
47
|
-
router.get("/hmr", (
|
|
47
|
+
router.get("/hmr", (req, reply) => {
|
|
48
48
|
reply.setHeader("Content-Type", "text/event-stream");
|
|
49
49
|
reply.setHeader("Cache-Control", "no-cache");
|
|
50
50
|
!isSecure && reply.setHeader("Connection", "keep-alive");
|
|
51
|
-
|
|
51
|
+
reply.flushHeaders();
|
|
52
|
+
|
|
53
|
+
CONNECTIONS.add(reply);
|
|
54
|
+
req.on("close", () => {
|
|
55
|
+
CONNECTIONS.delete(reply);
|
|
56
|
+
});
|
|
57
|
+
|
|
52
58
|
serverSentEvents = (data) => {
|
|
53
59
|
if (/\.(jsx?|tsx?)$/.test(data.file)) {
|
|
54
60
|
data.file = data.file.replace(".ts", ".js").replace(".jsx", ".js");
|
|
55
61
|
}
|
|
56
62
|
CONNECTIONS.forEach((rep) => {
|
|
63
|
+
if (rep.destroyed || rep.writableEnded) {
|
|
64
|
+
CONNECTIONS.delete(rep);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
rep.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
58
69
|
});
|
|
59
70
|
};
|
|
@@ -65,7 +76,7 @@ export async function createDefaultServer(
|
|
|
65
76
|
path.join(process.cwd(), bundleConfig.build, "index.html"),
|
|
66
77
|
{
|
|
67
78
|
encoding: "utf-8",
|
|
68
|
-
}
|
|
79
|
+
},
|
|
69
80
|
);
|
|
70
81
|
res.send(file);
|
|
71
82
|
});
|
|
@@ -82,7 +93,7 @@ export async function createDefaultServer(
|
|
|
82
93
|
bundleConfig.cert ||
|
|
83
94
|
(await readFile(path.join(process.cwd(), "localhost.pem"))),
|
|
84
95
|
},
|
|
85
|
-
app
|
|
96
|
+
app,
|
|
86
97
|
)
|
|
87
98
|
: http.createServer({}, app),
|
|
88
99
|
];
|
|
@@ -125,7 +136,7 @@ const htmlIdMap = new Map();
|
|
|
125
136
|
export function addHMRCode(
|
|
126
137
|
html: string,
|
|
127
138
|
file: string,
|
|
128
|
-
ast?: ReturnType<typeof parse | typeof parseFragment
|
|
139
|
+
ast?: ReturnType<typeof parse | typeof parseFragment>,
|
|
129
140
|
) {
|
|
130
141
|
if (!htmlIdMap.has(file)) {
|
|
131
142
|
htmlIdMap.set(file, randomText());
|
|
@@ -133,7 +144,7 @@ export function addHMRCode(
|
|
|
133
144
|
|
|
134
145
|
const script = createScript(
|
|
135
146
|
{ type: "module" },
|
|
136
|
-
getHMRCode(file, htmlIdMap.get(file), bundleConfig.src)
|
|
147
|
+
getHMRCode(file, htmlIdMap.get(file), bundleConfig.src),
|
|
137
148
|
);
|
|
138
149
|
|
|
139
150
|
let DOM;
|
|
@@ -148,7 +159,7 @@ export function addHMRCode(
|
|
|
148
159
|
|
|
149
160
|
//@ts-ignore
|
|
150
161
|
DOM.childNodes.forEach((node) =>
|
|
151
|
-
node.attrs?.push({ name: "data-hmr", value: htmlIdMap.get(file) })
|
|
162
|
+
node.attrs?.push({ name: "data-hmr", value: htmlIdMap.get(file) }),
|
|
152
163
|
);
|
|
153
164
|
|
|
154
165
|
return serialize(DOM as any);
|
|
@@ -162,14 +173,50 @@ function getHMRCode(file: string, id: string, src: string) {
|
|
|
162
173
|
return `import { render, html, $, $$, setShouldSetReactivity } from "hydro-js";
|
|
163
174
|
window.isHMR = true;
|
|
164
175
|
window.lastCalled = new Map();
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
176
|
+
window.htmlBundleHMRConnections ||= new Map();
|
|
177
|
+
window.htmlBundleHMRActiveId = "${id}";
|
|
178
|
+
let shouldReconnect = true;
|
|
179
|
+
let reconnectTimer;
|
|
180
|
+
|
|
181
|
+
for (const [hmrId, eventSource] of window.htmlBundleHMRConnections) {
|
|
182
|
+
if (hmrId !== "${id}") {
|
|
183
|
+
eventSource.close();
|
|
184
|
+
window.htmlBundleHMRConnections.delete(hmrId);
|
|
185
|
+
delete window["eventsource" + hmrId];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function closeEventSource() {
|
|
190
|
+
const eventSource = window.eventsource${id};
|
|
191
|
+
if (eventSource) {
|
|
192
|
+
eventSource.close();
|
|
193
|
+
window.htmlBundleHMRConnections.delete("${id}");
|
|
194
|
+
delete window.eventsource${id};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function connectEventSource() {
|
|
199
|
+
closeEventSource();
|
|
200
|
+
shouldReconnect = true;
|
|
201
|
+
|
|
202
|
+
const eventSource = new EventSource("/hmr");
|
|
203
|
+
window.eventsource${id} = eventSource;
|
|
204
|
+
window.htmlBundleHMRConnections.set("${id}", eventSource);
|
|
205
|
+
|
|
206
|
+
eventSource.addEventListener('error', () => {
|
|
207
|
+
eventSource.close();
|
|
208
|
+
if (window.eventsource${id} === eventSource) {
|
|
209
|
+
window.htmlBundleHMRConnections.delete("${id}");
|
|
210
|
+
delete window.eventsource${id};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (shouldReconnect && window.htmlBundleHMRActiveId === "${id}") {
|
|
214
|
+
clearTimeout(reconnectTimer);
|
|
215
|
+
reconnectTimer = setTimeout(connectEventSource, 1000);
|
|
216
|
+
}
|
|
171
217
|
});
|
|
172
|
-
|
|
218
|
+
|
|
219
|
+
eventSource.addEventListener("message", ({ data }) => {
|
|
173
220
|
if (window.lastScroll == null) {
|
|
174
221
|
window.lastScroll = window.scrollY;
|
|
175
222
|
}
|
|
@@ -275,5 +322,18 @@ function getHMRCode(file: string, id: string, src: string) {
|
|
|
275
322
|
}
|
|
276
323
|
});
|
|
277
324
|
}
|
|
325
|
+
|
|
326
|
+
window.addEventListener("pagehide", () => {
|
|
327
|
+
shouldReconnect = false;
|
|
328
|
+
clearTimeout(reconnectTimer);
|
|
329
|
+
if (window.htmlBundleHMRActiveId === "${id}") {
|
|
330
|
+
delete window.htmlBundleHMRActiveId;
|
|
331
|
+
}
|
|
332
|
+
closeEventSource();
|
|
333
|
+
}, { once: true });
|
|
334
|
+
|
|
335
|
+
if (!window.eventsource${id}) {
|
|
336
|
+
connectEventSource();
|
|
337
|
+
}
|
|
278
338
|
`;
|
|
279
339
|
}
|
package/tests/bundle.test.mjs
CHANGED
|
@@ -91,6 +91,12 @@ test("addHMRCode injects stable HMR wiring", async () => {
|
|
|
91
91
|
|
|
92
92
|
assert.match(fullDocument, /<script type="module">/);
|
|
93
93
|
assert.match(fullDocument, /new EventSource\("\/hmr"\)/);
|
|
94
|
+
assert.match(
|
|
95
|
+
fullDocument,
|
|
96
|
+
/window\.htmlBundleHMRConnections \|\|= new Map\(\)/,
|
|
97
|
+
);
|
|
98
|
+
assert.match(fullDocument, /window\.addEventListener\("pagehide"/);
|
|
99
|
+
assert.match(fullDocument, /eventSource\.close\(\)/);
|
|
94
100
|
assert.match(fullDocument, /data-hmr="[^"]+"/);
|
|
95
101
|
assert.ok(
|
|
96
102
|
fullDocument.indexOf("<head>") <
|
|
@@ -99,6 +105,7 @@ test("addHMRCode injects stable HMR wiring", async () => {
|
|
|
99
105
|
|
|
100
106
|
assert.match(fragment, /^<main data-hmr="[^"]+">Hi<\/main>/);
|
|
101
107
|
assert.match(fragment, /new EventSource\("\/hmr"\)/);
|
|
108
|
+
assert.match(fragment, /window\.htmlBundleHMRActiveId ===/);
|
|
102
109
|
});
|
|
103
110
|
|
|
104
111
|
test("getBuildPath maps src paths into the build directory", async () => {
|