@jsenv/core 39.0.4 → 39.1.0

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.
@@ -1,150 +1,5 @@
1
- import { urlHotMetas } from "./import_meta_hot.js";
2
1
  import { parseSrcSet, stringifySrcSet } from "@jsenv/ast/src/html/html_src_set.js";
3
-
4
- const compareTwoUrlPaths = (url, otherUrl) => {
5
- if (url === otherUrl) {
6
- return true;
7
- }
8
- const urlObject = new URL(url);
9
- const otherUrlObject = new URL(otherUrl);
10
- if (urlObject.origin !== otherUrlObject.origin) {
11
- return false;
12
- }
13
- if (urlObject.pathname !== otherUrlObject.pathname) {
14
- return false;
15
- }
16
- return true;
17
- };
18
-
19
- const injectQuery = (url, query) => {
20
- const urlObject = new URL(url);
21
- const { searchParams } = urlObject;
22
- Object.keys(query).forEach((key) => {
23
- searchParams.set(key, query[key]);
24
- });
25
- return String(urlObject);
26
- };
27
-
28
- const reloadHtmlPage = () => {
29
- window.location.reload(true);
30
- };
31
-
32
- // This function can consider everything as hot reloadable:
33
- // - no need to check [hot-accept]and [hot-decline] attributes for instance
34
- // This is because if something should full reload, we receive "full_reload"
35
- // from server and this function is not called
36
- const getDOMNodesUsingUrl = (urlToReload) => {
37
- const nodes = [];
38
- const shouldReloadUrl = (urlCandidate) => {
39
- return compareTwoUrlPaths(urlCandidate, urlToReload);
40
- };
41
- const visitNodeAttributeAsUrl = (node, attributeName) => {
42
- let attribute = node[attributeName];
43
- if (!attribute) {
44
- return;
45
- }
46
- if (SVGAnimatedString && attribute instanceof SVGAnimatedString) {
47
- attribute = attribute.animVal;
48
- }
49
- if (!shouldReloadUrl(attribute)) {
50
- return;
51
- }
52
- nodes.push({
53
- node,
54
- reload: (hot) => {
55
- if (node.nodeName === "SCRIPT") {
56
- const copy = document.createElement("script");
57
- Array.from(node.attributes).forEach((attribute) => {
58
- copy.setAttribute(attribute.nodeName, attribute.nodeValue);
59
- });
60
- copy.src = injectQuery(node.src, { hot });
61
- if (node.parentNode) {
62
- node.parentNode.replaceChild(copy, node);
63
- } else {
64
- document.body.appendChild(copy);
65
- }
66
- } else {
67
- node[attributeName] = injectQuery(attribute, { hot });
68
- }
69
- },
70
- });
71
- };
72
- Array.from(document.querySelectorAll(`link[rel="stylesheet"]`)).forEach(
73
- (link) => {
74
- visitNodeAttributeAsUrl(link, "href");
75
- },
76
- );
77
- Array.from(document.querySelectorAll(`link[rel="icon"]`)).forEach((link) => {
78
- visitNodeAttributeAsUrl(link, "href");
79
- });
80
- Array.from(document.querySelectorAll("script")).forEach((script) => {
81
- visitNodeAttributeAsUrl(script, "src");
82
- const inlinedFromSrc = script.getAttribute("inlined-from-src");
83
- if (inlinedFromSrc) {
84
- const inlinedFromUrl = new URL(inlinedFromSrc, window.location.origin)
85
- .href;
86
- if (shouldReloadUrl(inlinedFromUrl)) {
87
- nodes.push({
88
- node: script,
89
- reload: () =>
90
- window.__supervisor__.reloadSupervisedScript(inlinedFromSrc),
91
- });
92
- }
93
- }
94
- });
95
- // There is no real need to update a.href because the resource will be fetched when clicked.
96
- // But in a scenario where the resource was already visited and is in browser cache, adding
97
- // the dynamic query param ensure the cache is invalidated
98
- Array.from(document.querySelectorAll("a")).forEach((a) => {
99
- visitNodeAttributeAsUrl(a, "href");
100
- });
101
- // About iframes:
102
- // - By default iframe itself and everything inside trigger a parent page full-reload
103
- // - Adding [hot-accept] on the iframe means parent page won't reload when iframe full/hot reload
104
- // In that case and if there is code in the iframe and parent doing post message communication:
105
- // you must put import.meta.hot.decline() for code involved in communication.
106
- // (both in parent and iframe)
107
- Array.from(document.querySelectorAll("img")).forEach((img) => {
108
- visitNodeAttributeAsUrl(img, "src");
109
- const srcset = img.srcset;
110
- if (srcset) {
111
- nodes.push({
112
- node: img,
113
- reload: (hot) => {
114
- const srcCandidates = parseSrcSet(srcset);
115
- srcCandidates.forEach((srcCandidate) => {
116
- const url = new URL(
117
- srcCandidate.specifier,
118
- `${window.location.href}`,
119
- );
120
- if (shouldReloadUrl(url)) {
121
- srcCandidate.specifier = injectQuery(url, { hot });
122
- }
123
- });
124
- img.srcset = stringifySrcSet(srcCandidates);
125
- },
126
- });
127
- }
128
- });
129
- Array.from(document.querySelectorAll("source")).forEach((source) => {
130
- visitNodeAttributeAsUrl(source, "src");
131
- });
132
- // svg image tag
133
- Array.from(document.querySelectorAll("image")).forEach((image) => {
134
- visitNodeAttributeAsUrl(image, "href");
135
- });
136
- // svg use
137
- Array.from(document.querySelectorAll("use")).forEach((use) => {
138
- visitNodeAttributeAsUrl(use, "href");
139
- });
140
- return nodes;
141
- };
142
-
143
- const reloadJsImport = async (url, hot) => {
144
- const urlWithHotSearchParam = injectQuery(url, { hot });
145
- const namespace = await import(urlWithHotSearchParam);
146
- return namespace;
147
- };
2
+ import { urlHotMetas } from "./import_meta_hot.js";
148
3
 
149
4
  const initAutoreload = ({ mainFilePath }) => {
150
5
  const reloader = {
@@ -366,4 +221,155 @@ This could be due to syntax errors or importing non-existent modules (see errors
366
221
  });
367
222
  };
368
223
 
224
+ const reloadHtmlPage = () => {
225
+ window.location.reload(true);
226
+ };
227
+ // This function can consider everything as hot reloadable:
228
+ // - no need to check [hot-accept]and [hot-decline] attributes for instance
229
+ // This is because if something should full reload, we receive "full_reload"
230
+ // from server and this function is not called
231
+ const getDOMNodesUsingUrl = (urlToReload) => {
232
+ const nodes = [];
233
+ const shouldReloadUrl = (urlCandidate) => {
234
+ return compareTwoUrlPaths(urlCandidate, urlToReload);
235
+ };
236
+ const visitNodeAttributeAsUrl = (node, attributeName) => {
237
+ let attribute = node[attributeName];
238
+ if (!attribute) {
239
+ return;
240
+ }
241
+ if (SVGAnimatedString && attribute instanceof SVGAnimatedString) {
242
+ attribute = attribute.animVal;
243
+ }
244
+ if (!shouldReloadUrl(attribute)) {
245
+ return;
246
+ }
247
+ nodes.push({
248
+ node,
249
+ reload: (hot) => {
250
+ if (node.nodeName === "SCRIPT") {
251
+ const copy = document.createElement("script");
252
+ Array.from(node.attributes).forEach((attribute) => {
253
+ copy.setAttribute(attribute.nodeName, attribute.nodeValue);
254
+ });
255
+ copy.src = injectQuery(node.src, { hot });
256
+ if (node.parentNode) {
257
+ node.parentNode.replaceChild(copy, node);
258
+ } else {
259
+ document.body.appendChild(copy);
260
+ }
261
+ } else {
262
+ node[attributeName] = injectQuery(attribute, { hot });
263
+ }
264
+ },
265
+ });
266
+ };
267
+ Array.from(document.querySelectorAll(`link[rel="stylesheet"]`)).forEach(
268
+ (link) => {
269
+ visitNodeAttributeAsUrl(link, "href");
270
+ },
271
+ );
272
+ Array.from(document.querySelectorAll(`link[rel="icon"]`)).forEach((link) => {
273
+ visitNodeAttributeAsUrl(link, "href");
274
+ });
275
+ Array.from(document.querySelectorAll("script")).forEach((script) => {
276
+ visitNodeAttributeAsUrl(script, "src");
277
+ const inlinedFromSrc = script.getAttribute("inlined-from-src");
278
+ if (inlinedFromSrc) {
279
+ const inlinedFromUrl = new URL(inlinedFromSrc, window.location.origin)
280
+ .href;
281
+ if (shouldReloadUrl(inlinedFromUrl)) {
282
+ nodes.push({
283
+ node: script,
284
+ reload: () =>
285
+ window.__supervisor__.reloadSupervisedScript(inlinedFromSrc),
286
+ });
287
+ }
288
+ }
289
+ });
290
+ // There is no real need to update a.href because the resource will be fetched when clicked.
291
+ // But in a scenario where the resource was already visited and is in browser cache, adding
292
+ // the dynamic query param ensure the cache is invalidated
293
+ Array.from(document.querySelectorAll("a")).forEach((a) => {
294
+ visitNodeAttributeAsUrl(a, "href");
295
+ });
296
+ // About iframes:
297
+ // - By default iframe itself and everything inside trigger a parent page full-reload
298
+ // - Adding [hot-accept] on the iframe means parent page won't reload when iframe full/hot reload
299
+ // In that case and if there is code in the iframe and parent doing post message communication:
300
+ // you must put import.meta.hot.decline() for code involved in communication.
301
+ // (both in parent and iframe)
302
+ Array.from(document.querySelectorAll("img")).forEach((img) => {
303
+ visitNodeAttributeAsUrl(img, "src");
304
+ const srcset = img.srcset;
305
+ if (srcset) {
306
+ nodes.push({
307
+ node: img,
308
+ reload: (hot) => {
309
+ const srcCandidates = parseSrcSet(srcset);
310
+ srcCandidates.forEach((srcCandidate) => {
311
+ const url = new URL(
312
+ srcCandidate.specifier,
313
+ `${window.location.href}`,
314
+ );
315
+ if (shouldReloadUrl(url)) {
316
+ srcCandidate.specifier = injectQuery(url, { hot });
317
+ }
318
+ });
319
+ img.srcset = stringifySrcSet(srcCandidates);
320
+ },
321
+ });
322
+ }
323
+ });
324
+ Array.from(document.querySelectorAll("source")).forEach((source) => {
325
+ visitNodeAttributeAsUrl(source, "src");
326
+ });
327
+ // svg image tag
328
+ Array.from(document.querySelectorAll("image")).forEach((image) => {
329
+ visitNodeAttributeAsUrl(image, "href");
330
+ });
331
+ // svg use
332
+ Array.from(document.querySelectorAll("use")).forEach((use) => {
333
+ visitNodeAttributeAsUrl(use, "href");
334
+ });
335
+ return nodes;
336
+ };
337
+ const reloadJsImport = async (url, hot) => {
338
+ const urlWithHotSearchParam = injectQuery(url, { hot });
339
+ const namespace = await import(urlWithHotSearchParam);
340
+ return namespace;
341
+ };
342
+ // const reloadAllCss = () => {
343
+ // const links = Array.from(document.getElementsByTagName("link"));
344
+ // links.forEach((link) => {
345
+ // if (link.rel === "stylesheet") {
346
+ // link.href = injectQuery(link.href, { hot: Date.now() });
347
+ // }
348
+ // });
349
+ // };
350
+
351
+ const compareTwoUrlPaths = (url, otherUrl) => {
352
+ if (url === otherUrl) {
353
+ return true;
354
+ }
355
+ const urlObject = new URL(url);
356
+ const otherUrlObject = new URL(otherUrl);
357
+ if (urlObject.origin !== otherUrlObject.origin) {
358
+ return false;
359
+ }
360
+ if (urlObject.pathname !== otherUrlObject.pathname) {
361
+ return false;
362
+ }
363
+ return true;
364
+ };
365
+
366
+ const injectQuery = (url, query) => {
367
+ const urlObject = new URL(url);
368
+ const { searchParams } = urlObject;
369
+ Object.keys(query).forEach((key) => {
370
+ searchParams.set(key, query[key]);
371
+ });
372
+ return String(urlObject);
373
+ };
374
+
369
375
  export { initAutoreload };