@jsenv/core 39.0.5 → 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,9 +1,4 @@
1
- import {
2
- parseHtml,
3
- stringifyHtmlAst,
4
- createHtmlNode,
5
- injectHtmlNodeAsEarlyAsPossible,
6
- } from "@jsenv/ast";
1
+ import { parseHtml, injectJsenvScript, stringifyHtmlAst } from "@jsenv/ast";
7
2
  import { URL_META } from "@jsenv/url-meta";
8
3
  import { asUrlWithoutSearch } from "@jsenv/urls";
9
4
 
@@ -47,27 +42,22 @@ export const jsenvPluginRibbon = ({
47
42
  url: urlInfo.url,
48
43
  });
49
44
  const ribbonClientFileReference = urlInfo.dependencies.inject({
50
- type: "script",
45
+ type: "js_import",
51
46
  subtype: "js_module",
52
47
  expectedType: "js_module",
53
48
  specifier: ribbonClientFileUrl.href,
54
49
  });
55
- const paramsJson = JSON.stringify(
56
- { text: urlInfo.context.dev ? "DEV" : "BUILD" },
57
- null,
58
- " ",
59
- );
60
- injectHtmlNodeAsEarlyAsPossible(
61
- htmlAst,
62
- createHtmlNode({
63
- tagName: "script",
64
- type: "module",
65
- textContent: `import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}";
66
-
67
- injectRibbon(${paramsJson});`,
68
- }),
69
- "jsenv:ribbon",
70
- );
50
+ injectJsenvScript(htmlAst, {
51
+ type: "module",
52
+ src: ribbonClientFileReference.generatedSpecifier,
53
+ initCall: {
54
+ callee: "injectRibbon",
55
+ params: {
56
+ text: urlInfo.context.dev ? "DEV" : "BUILD",
57
+ },
58
+ },
59
+ pluginName: "jsenv:ribbon",
60
+ });
71
61
  return stringifyHtmlAst(htmlAst);
72
62
  },
73
63
  },
@@ -3,6 +3,8 @@
3
3
  * to provide "serverEvents" used by other plugins
4
4
  */
5
5
 
6
+ import { parseHtml, injectJsenvScript, stringifyHtmlAst } from "@jsenv/ast";
7
+
6
8
  const serverEventsClientFileUrl = new URL(
7
9
  "./client/server_events_client.js",
8
10
  import.meta.url,
@@ -13,20 +15,22 @@ export const jsenvPluginServerEventsClientInjection = ({ logs = true }) => {
13
15
  name: "jsenv:server_events_client_injection",
14
16
  appliesDuring: "*",
15
17
  transformUrlContent: {
16
- html: () => {
17
- return {
18
- scriptInjections: [
19
- {
20
- src: serverEventsClientFileUrl,
21
- setup: {
22
- name: "window.__server_events__.setup",
23
- param: {
24
- logs,
25
- },
26
- },
18
+ html: (urlInfo) => {
19
+ const htmlAst = parseHtml({
20
+ html: urlInfo.content,
21
+ url: urlInfo.url,
22
+ });
23
+ injectJsenvScript(htmlAst, {
24
+ src: serverEventsClientFileUrl,
25
+ initCall: {
26
+ callee: "window.__server_events__.setup",
27
+ params: {
28
+ logs,
27
29
  },
28
- ],
29
- };
30
+ },
31
+ pluginName: "jsenv:server_events_client_injection",
32
+ });
33
+ return stringifyHtmlAst(htmlAst);
30
34
  },
31
35
  },
32
36
  };
@@ -1,136 +0,0 @@
1
- import {
2
- parseSrcSet,
3
- stringifySrcSet,
4
- } from "@jsenv/ast/src/html/html_src_set.js";
5
-
6
- import { injectQuery, compareTwoUrlPaths } from "./url_helpers.js";
7
-
8
- export const reloadHtmlPage = () => {
9
- window.location.reload(true);
10
- };
11
-
12
- // This function can consider everything as hot reloadable:
13
- // - no need to check [hot-accept]and [hot-decline] attributes for instance
14
- // This is because if something should full reload, we receive "full_reload"
15
- // from server and this function is not called
16
- export const getDOMNodesUsingUrl = (urlToReload) => {
17
- const nodes = [];
18
- const shouldReloadUrl = (urlCandidate) => {
19
- return compareTwoUrlPaths(urlCandidate, urlToReload);
20
- };
21
- const visitNodeAttributeAsUrl = (node, attributeName) => {
22
- let attribute = node[attributeName];
23
- if (!attribute) {
24
- return;
25
- }
26
- if (SVGAnimatedString && attribute instanceof SVGAnimatedString) {
27
- attribute = attribute.animVal;
28
- }
29
- if (!shouldReloadUrl(attribute)) {
30
- return;
31
- }
32
- nodes.push({
33
- node,
34
- reload: (hot) => {
35
- if (node.nodeName === "SCRIPT") {
36
- const copy = document.createElement("script");
37
- Array.from(node.attributes).forEach((attribute) => {
38
- copy.setAttribute(attribute.nodeName, attribute.nodeValue);
39
- });
40
- copy.src = injectQuery(node.src, { hot });
41
- if (node.parentNode) {
42
- node.parentNode.replaceChild(copy, node);
43
- } else {
44
- document.body.appendChild(copy);
45
- }
46
- } else {
47
- node[attributeName] = injectQuery(attribute, { hot });
48
- }
49
- },
50
- });
51
- };
52
- Array.from(document.querySelectorAll(`link[rel="stylesheet"]`)).forEach(
53
- (link) => {
54
- visitNodeAttributeAsUrl(link, "href");
55
- },
56
- );
57
- Array.from(document.querySelectorAll(`link[rel="icon"]`)).forEach((link) => {
58
- visitNodeAttributeAsUrl(link, "href");
59
- });
60
- Array.from(document.querySelectorAll("script")).forEach((script) => {
61
- visitNodeAttributeAsUrl(script, "src");
62
- const inlinedFromSrc = script.getAttribute("inlined-from-src");
63
- if (inlinedFromSrc) {
64
- const inlinedFromUrl = new URL(inlinedFromSrc, window.location.origin)
65
- .href;
66
- if (shouldReloadUrl(inlinedFromUrl)) {
67
- nodes.push({
68
- node: script,
69
- reload: () =>
70
- window.__supervisor__.reloadSupervisedScript(inlinedFromSrc),
71
- });
72
- }
73
- }
74
- });
75
- // There is no real need to update a.href because the resource will be fetched when clicked.
76
- // But in a scenario where the resource was already visited and is in browser cache, adding
77
- // the dynamic query param ensure the cache is invalidated
78
- Array.from(document.querySelectorAll("a")).forEach((a) => {
79
- visitNodeAttributeAsUrl(a, "href");
80
- });
81
- // About iframes:
82
- // - By default iframe itself and everything inside trigger a parent page full-reload
83
- // - Adding [hot-accept] on the iframe means parent page won't reload when iframe full/hot reload
84
- // In that case and if there is code in the iframe and parent doing post message communication:
85
- // you must put import.meta.hot.decline() for code involved in communication.
86
- // (both in parent and iframe)
87
- Array.from(document.querySelectorAll("img")).forEach((img) => {
88
- visitNodeAttributeAsUrl(img, "src");
89
- const srcset = img.srcset;
90
- if (srcset) {
91
- nodes.push({
92
- node: img,
93
- reload: (hot) => {
94
- const srcCandidates = parseSrcSet(srcset);
95
- srcCandidates.forEach((srcCandidate) => {
96
- const url = new URL(
97
- srcCandidate.specifier,
98
- `${window.location.href}`,
99
- );
100
- if (shouldReloadUrl(url)) {
101
- srcCandidate.specifier = injectQuery(url, { hot });
102
- }
103
- });
104
- img.srcset = stringifySrcSet(srcCandidates);
105
- },
106
- });
107
- }
108
- });
109
- Array.from(document.querySelectorAll("source")).forEach((source) => {
110
- visitNodeAttributeAsUrl(source, "src");
111
- });
112
- // svg image tag
113
- Array.from(document.querySelectorAll("image")).forEach((image) => {
114
- visitNodeAttributeAsUrl(image, "href");
115
- });
116
- // svg use
117
- Array.from(document.querySelectorAll("use")).forEach((use) => {
118
- visitNodeAttributeAsUrl(use, "href");
119
- });
120
- return nodes;
121
- };
122
-
123
- export const reloadJsImport = async (url, hot) => {
124
- const urlWithHotSearchParam = injectQuery(url, { hot });
125
- const namespace = await import(urlWithHotSearchParam);
126
- return namespace;
127
- };
128
-
129
- export const reloadAllCss = () => {
130
- const links = Array.from(document.getElementsByTagName("link"));
131
- links.forEach((link) => {
132
- if (link.rel === "stylesheet") {
133
- link.href = injectQuery(link.href, { hot: Date.now() });
134
- }
135
- });
136
- };
@@ -1,23 +0,0 @@
1
- export const compareTwoUrlPaths = (url, otherUrl) => {
2
- if (url === otherUrl) {
3
- return true;
4
- }
5
- const urlObject = new URL(url);
6
- const otherUrlObject = new URL(otherUrl);
7
- if (urlObject.origin !== otherUrlObject.origin) {
8
- return false;
9
- }
10
- if (urlObject.pathname !== otherUrlObject.pathname) {
11
- return false;
12
- }
13
- return true;
14
- };
15
-
16
- export const injectQuery = (url, query) => {
17
- const urlObject = new URL(url);
18
- const { searchParams } = urlObject;
19
- Object.keys(query).forEach((key) => {
20
- searchParams.set(key, query[key]);
21
- });
22
- return String(urlObject);
23
- };