@jsenv/core 41.1.1 → 41.2.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.
@@ -8735,6 +8735,39 @@ const jsenvPluginCacheControl = ({
8735
8735
 
8736
8736
  const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
8737
8737
 
8738
+ const jsenvPluginCustomElementsRedefine = () => {
8739
+ const customElementsRedefineClientFileUrl = import.meta
8740
+ .resolve("../client/custom_elements_redefine/custom_elements_redefine.js");
8741
+
8742
+ return {
8743
+ name: "jsenv:custom_elements_redefine",
8744
+ appliesDuring: "dev",
8745
+ transformUrlContent: {
8746
+ html: (urlInfo) => {
8747
+ const htmlAst = parseHtml({ html: urlInfo.content, url: urlInfo.url });
8748
+ const reference = urlInfo.dependencies.inject({
8749
+ type: "script",
8750
+ subtype: "js_module",
8751
+ expectedType: "js_module",
8752
+ specifier: customElementsRedefineClientFileUrl,
8753
+ });
8754
+ injectJsenvScript(htmlAst, {
8755
+ type: "module",
8756
+ src: reference.generatedSpecifier,
8757
+ initCall: {
8758
+ callee: "allowCustomElementsRedefine",
8759
+ },
8760
+ pluginName: "jsenv:custom_elements_redefine",
8761
+ });
8762
+ const htmlModified = stringifyHtmlAst(htmlAst);
8763
+ return {
8764
+ content: htmlModified,
8765
+ };
8766
+ },
8767
+ },
8768
+ };
8769
+ };
8770
+
8738
8771
  const jsenvPluginRibbon = ({
8739
8772
  rootDirectoryUrl,
8740
8773
  htmlInclude = "/**/*.html",
@@ -9206,6 +9239,7 @@ const getCorePlugins = ({
9206
9239
  scenarioPlaceholders = true,
9207
9240
  ribbon = true,
9208
9241
  dropToOpen = true,
9242
+ customElementsRedefine = true,
9209
9243
  packageSideEffects = false,
9210
9244
  } = {}) => {
9211
9245
  if (cacheControl === true) {
@@ -9302,6 +9336,7 @@ const getCorePlugins = ({
9302
9336
  ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
9303
9337
  ...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
9304
9338
  ...(dropToOpen ? [jsenvPluginDropToOpen()] : []),
9339
+ ...(customElementsRedefine ? [jsenvPluginCustomElementsRedefine()] : []),
9305
9340
  jsenvPluginCleanHTML(),
9306
9341
  ...(packageSideEffects
9307
9342
  ? [jsenvPluginPackageSideEffects({ packageDirectory })]
@@ -0,0 +1,208 @@
1
+ /*
2
+ * https://github.com/lit/lit/issues/1844
3
+ * https://github.com/vegarringdal/custom-elements-hmr-polyfill/tree/master
4
+ */
5
+
6
+ const allowCustomElementsRedefine = ({
7
+ updateWholeDOMOnRedefine = false,
8
+ } = {}) => {
9
+ let timeoutId;
10
+ const onCustomElementChange = (
11
+ customElementName,
12
+ // customElementClass,
13
+ // options,
14
+ ) => {
15
+ if (!updateWholeDOMOnRedefine) {
16
+ return;
17
+ }
18
+ clearTimeout(timeoutId);
19
+ timeoutId = setTimeout(() => {
20
+ if (document.body) {
21
+ requestAnimationFrame(() => {
22
+ // re-render the whole DOM
23
+ // this will make less calls to connectedCallback/disconnectedCallback on replaced child node when created.
24
+ const oldBodyHtml = document.body.innerHTML;
25
+ document.body.innerHTML = "";
26
+ document.body.innerHTML = oldBodyHtml;
27
+ });
28
+ }
29
+ }, 250);
30
+ };
31
+
32
+ const customElementClassMap = new Map();
33
+ const defineOriginal = customElements.define;
34
+ customElements.define = (customElementName, customElementClass, options) => {
35
+ const registeredCustomElement = customElements.get(customElementName);
36
+ customElementClassMap.set(customElementName, customElementClass);
37
+ if (registeredCustomElement) {
38
+ onCustomElementChange();
39
+ return;
40
+ }
41
+ const CustomElementFacade = createCustomElementFacade(
42
+ customElementName,
43
+ customElementClass,
44
+ );
45
+ defineOriginal.call(
46
+ customElements,
47
+ customElementName,
48
+ CustomElementFacade,
49
+ options,
50
+ );
51
+ };
52
+
53
+ const observerSymbol = Symbol.for("observedAttributesObserver");
54
+ const createCustomElementFacade = (
55
+ customElementName,
56
+ customElementFirstClass,
57
+ ) => {
58
+ class CustomElementFacade extends customElementFirstClass {
59
+ static get observedAttributes() {
60
+ return [];
61
+ }
62
+
63
+ constructor(...args) {
64
+ const CustomElementClass = customElementClassMap.get(customElementName);
65
+
66
+ if (CustomElementClass !== customElementFirstClass) {
67
+ {
68
+ let ClassCandidate = CustomElementClass;
69
+ while (ClassCandidate) {
70
+ const nextClassCandidate = Object.getPrototypeOf(ClassCandidate);
71
+ if (!nextClassCandidate) {
72
+ break;
73
+ }
74
+ const name = nextClassCandidate.name;
75
+ if (name) {
76
+ const constructor = window[name];
77
+ if (constructor && constructor.prototype instanceof Element) {
78
+ patchProperties(
79
+ CustomElementFacade.prototype,
80
+ ClassCandidate.prototype,
81
+ );
82
+ break;
83
+ }
84
+ }
85
+ ClassCandidate = nextClassCandidate;
86
+ }
87
+ }
88
+ {
89
+ const CustomElementPrototype = CustomElementClass.prototype;
90
+ patchProperties(
91
+ CustomElementFacade.prototype,
92
+ CustomElementPrototype,
93
+ );
94
+ }
95
+ }
96
+ const customElementInstance = Reflect.construct(
97
+ CustomElementClass,
98
+ args,
99
+ CustomElementFacade,
100
+ );
101
+ // eslint-disable-next-line no-constructor-return
102
+ return customElementInstance;
103
+ }
104
+
105
+ connectedCallback(...args) {
106
+ const CustomElementClass = customElementClassMap.get(customElementName);
107
+ const CustomElementPrototype = CustomElementClass.prototype;
108
+ const observedAttributes = CustomElementClass.observedAttributes;
109
+
110
+ // call initial callback when class is created
111
+ if (observedAttributes) {
112
+ if (Array.isArray(observedAttributes)) {
113
+ observedAttributes.forEach((observedAttributeName) => {
114
+ const haveAtt = this.getAttributeNode(observedAttributeName);
115
+ if (haveAtt) {
116
+ CustomElementPrototype.attributeChangedCallback.call(
117
+ this,
118
+ observedAttributeName,
119
+ null,
120
+ this.getAttribute(observedAttributeName),
121
+ null,
122
+ );
123
+ }
124
+ });
125
+ } else {
126
+ console.warn(
127
+ `observedAttributes in ${customElementName} is not array, please fix`,
128
+ );
129
+ }
130
+ }
131
+ const mutationObserver = new MutationObserver((mutationList) => {
132
+ mutationList.forEach((mutation) => {
133
+ if (
134
+ CustomElementPrototype.attributeChangedCallback &&
135
+ observedAttributes &&
136
+ observedAttributes.includes(mutation.attributeName)
137
+ ) {
138
+ CustomElementPrototype.attributeChangedCallback.call(
139
+ this,
140
+ mutation.attributeName,
141
+ mutation.oldValue,
142
+ this.getAttribute(mutation.attributeName),
143
+ null,
144
+ );
145
+ }
146
+ });
147
+ });
148
+ this[observerSymbol] = mutationObserver;
149
+ mutationObserver.observe(this, {
150
+ childList: false,
151
+ attributes: true,
152
+ attributeOldValue: true,
153
+ subtree: false,
154
+ });
155
+
156
+ if (CustomElementPrototype.connectedCallback) {
157
+ CustomElementPrototype.connectedCallback.call(this, ...args);
158
+ }
159
+ }
160
+
161
+ disconnectedCallback(...args) {
162
+ this[observerSymbol].disconnect();
163
+ this[observerSymbol] = null;
164
+
165
+ const CustomElementClass = customElementClassMap.get(customElementName);
166
+ const CustomElementPrototype = CustomElementClass.prototype;
167
+ if (CustomElementPrototype.disconnectedCallback) {
168
+ CustomElementPrototype.disconnectedCallback.call(this, ...args);
169
+ }
170
+ }
171
+
172
+ adoptedCallback(...args) {
173
+ const CustomElementClass = customElementClassMap.get(customElementName);
174
+ const CustomElementPrototype = CustomElementClass.prototype;
175
+ if (CustomElementPrototype.adoptedCallback) {
176
+ CustomElementPrototype.adoptedCallback.call(this, ...args);
177
+ }
178
+ }
179
+ }
180
+ return CustomElementFacade;
181
+ };
182
+ const patchProperties = (into, from) => {
183
+ const ownPropertyNames = Object.getOwnPropertyNames(from);
184
+ ownPropertyNames.forEach((ownPropertyName) => {
185
+ if (PROPERTY_NAMES_TO_SKIP.includes(ownPropertyName)) {
186
+ return;
187
+ }
188
+ const propertyDescriptor = Object.getOwnPropertyDescriptor(
189
+ from,
190
+ ownPropertyName,
191
+ );
192
+ if (!propertyDescriptor) {
193
+ return;
194
+ }
195
+ if (!propertyDescriptor.configurable) {
196
+ console.warn(
197
+ "[custom-elements-redefined]",
198
+ `${ownPropertyName} is not configurable, skipping`,
199
+ );
200
+ return;
201
+ }
202
+ Object.defineProperty(into, ownPropertyName, propertyDescriptor);
203
+ });
204
+ };
205
+ const PROPERTY_NAMES_TO_SKIP = ["name", "prototype", "length"];
206
+ };
207
+
208
+ export { allowCustomElementsRedefine };
@@ -5687,6 +5687,39 @@ const jsenvPluginCacheControl = ({
5687
5687
 
5688
5688
  const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
5689
5689
 
5690
+ const jsenvPluginCustomElementsRedefine = () => {
5691
+ const customElementsRedefineClientFileUrl = import.meta
5692
+ .resolve("../client/custom_elements_redefine/custom_elements_redefine.js");
5693
+
5694
+ return {
5695
+ name: "jsenv:custom_elements_redefine",
5696
+ appliesDuring: "dev",
5697
+ transformUrlContent: {
5698
+ html: (urlInfo) => {
5699
+ const htmlAst = parseHtml({ html: urlInfo.content, url: urlInfo.url });
5700
+ const reference = urlInfo.dependencies.inject({
5701
+ type: "script",
5702
+ subtype: "js_module",
5703
+ expectedType: "js_module",
5704
+ specifier: customElementsRedefineClientFileUrl,
5705
+ });
5706
+ injectJsenvScript(htmlAst, {
5707
+ type: "module",
5708
+ src: reference.generatedSpecifier,
5709
+ initCall: {
5710
+ callee: "allowCustomElementsRedefine",
5711
+ },
5712
+ pluginName: "jsenv:custom_elements_redefine",
5713
+ });
5714
+ const htmlModified = stringifyHtmlAst(htmlAst);
5715
+ return {
5716
+ content: htmlModified,
5717
+ };
5718
+ },
5719
+ },
5720
+ };
5721
+ };
5722
+
5690
5723
  const jsenvPluginRibbon = ({
5691
5724
  rootDirectoryUrl,
5692
5725
  htmlInclude = "/**/*.html",
@@ -6158,6 +6191,7 @@ const getCorePlugins = ({
6158
6191
  scenarioPlaceholders = true,
6159
6192
  ribbon = true,
6160
6193
  dropToOpen = true,
6194
+ customElementsRedefine = true,
6161
6195
  packageSideEffects = false,
6162
6196
  } = {}) => {
6163
6197
  if (cacheControl === true) {
@@ -6254,6 +6288,7 @@ const getCorePlugins = ({
6254
6288
  ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
6255
6289
  ...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
6256
6290
  ...(dropToOpen ? [jsenvPluginDropToOpen()] : []),
6291
+ ...(customElementsRedefine ? [jsenvPluginCustomElementsRedefine()] : []),
6257
6292
  jsenvPluginCleanHTML(),
6258
6293
  ...(packageSideEffects
6259
6294
  ? [jsenvPluginPackageSideEffects({ packageDirectory })]
@@ -10150,6 +10185,7 @@ const startDevServer = async ({
10150
10185
  cacheControl = true,
10151
10186
  ribbon = true,
10152
10187
  dropToOpen = true,
10188
+ customElementsRedefine = true,
10153
10189
  // toolbar = false,
10154
10190
  onKitchenCreated = () => {},
10155
10191
  spa,
@@ -10265,6 +10301,7 @@ const startDevServer = async ({
10265
10301
  cacheControl,
10266
10302
  ribbon,
10267
10303
  dropToOpen,
10304
+ customElementsRedefine,
10268
10305
  }),
10269
10306
  ]);
10270
10307
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "41.1.1",
3
+ "version": "41.2.1",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -59,7 +59,7 @@
59
59
  "md:build": "node ./docs/build.js",
60
60
  "monorepo:node_modules_clear": "npx @jsenv/filesystem clear **/node_modules/",
61
61
  "monorepo:publish": "node ./scripts/monorepo/publish_packages.mjs",
62
- "monorepo:sync_packages_versions": "node ./scripts/monorepo/sync_packages_versions.mjs",
62
+ "monorepo:sync_versions": "node ./scripts/monorepo/sync_packages_versions.mjs",
63
63
  "monorepo:upgrade_versions": "node ./scripts/monorepo/upgrade_external_versions.mjs",
64
64
  "oto:start": "npm run start -w oto",
65
65
  "performances": "node --expose-gc ./scripts/performance/generate_performance_report.mjs --log --once",
@@ -74,12 +74,12 @@
74
74
  "test:snapshot_clear": "npx @jsenv/filesystem clear **/tests/**/side_effects/"
75
75
  },
76
76
  "dependencies": {
77
- "@jsenv/ast": "6.7.21",
78
- "@jsenv/js-module-fallback": "1.4.29",
77
+ "@jsenv/ast": "6.8.0",
78
+ "@jsenv/js-module-fallback": "1.4.30",
79
79
  "@jsenv/plugin-bundling": "2.10.9",
80
80
  "@jsenv/plugin-minification": "1.7.3",
81
- "@jsenv/plugin-supervisor": "1.8.0",
82
- "@jsenv/plugin-transpilation": "1.5.71",
81
+ "@jsenv/plugin-supervisor": "1.8.1",
82
+ "@jsenv/plugin-transpilation": "1.5.72",
83
83
  "@jsenv/server": "17.1.1",
84
84
  "@jsenv/sourcemap": "1.3.17",
85
85
  "react-table": "7.8.0"
@@ -93,6 +93,7 @@
93
93
  "@jsenv/assert": "workspace:*",
94
94
  "@jsenv/cli": "workspace:*",
95
95
  "@jsenv/core": "./",
96
+ "@jsenv/custom-elements-redefine": "workspace:*",
96
97
  "@jsenv/database-manager": "workspace:*",
97
98
  "@jsenv/eslint-config-relax": "workspace:*",
98
99
  "@jsenv/file-size-impact": "workspace:*",
@@ -90,6 +90,7 @@ export const startDevServer = async ({
90
90
  cacheControl = true,
91
91
  ribbon = true,
92
92
  dropToOpen = true,
93
+ customElementsRedefine = true,
93
94
  // toolbar = false,
94
95
  onKitchenCreated = () => {},
95
96
  spa,
@@ -206,6 +207,7 @@ export const startDevServer = async ({
206
207
  cacheControl,
207
208
  ribbon,
208
209
  dropToOpen,
210
+ customElementsRedefine,
209
211
  }),
210
212
  ]);
211
213
 
@@ -0,0 +1,34 @@
1
+ import { injectJsenvScript, parseHtml, stringifyHtmlAst } from "@jsenv/ast";
2
+
3
+ export const jsenvPluginCustomElementsRedefine = () => {
4
+ const customElementsRedefineClientFileUrl = import.meta
5
+ .resolve("@jsenv/custom-elements-redefine/src/main.js");
6
+
7
+ return {
8
+ name: "jsenv:custom_elements_redefine",
9
+ appliesDuring: "dev",
10
+ transformUrlContent: {
11
+ html: (urlInfo) => {
12
+ const htmlAst = parseHtml({ html: urlInfo.content, url: urlInfo.url });
13
+ const reference = urlInfo.dependencies.inject({
14
+ type: "script",
15
+ subtype: "js_module",
16
+ expectedType: "js_module",
17
+ specifier: customElementsRedefineClientFileUrl,
18
+ });
19
+ injectJsenvScript(htmlAst, {
20
+ type: "module",
21
+ src: reference.generatedSpecifier,
22
+ initCall: {
23
+ callee: "allowCustomElementsRedefine",
24
+ },
25
+ pluginName: "jsenv:custom_elements_redefine",
26
+ });
27
+ const htmlModified = stringifyHtmlAst(htmlAst);
28
+ return {
29
+ content: htmlModified,
30
+ };
31
+ },
32
+ },
33
+ };
34
+ };
@@ -21,6 +21,7 @@ import { jsenvPluginImportMetaCss } from "./import_meta_css/jsenv_plugin_import_
21
21
  import { jsenvPluginImportMetaHot } from "./import_meta_hot/jsenv_plugin_import_meta_hot.js";
22
22
  import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js";
23
23
  import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js";
24
+ import { jsenvPluginCustomElementsRedefine } from "./custom_elements_redefine/jsenv_plugin_custom_elements_redefine.js";
24
25
  // other
25
26
  import { jsenvPluginRibbon } from "./ribbon/jsenv_plugin_ribbon.js";
26
27
  import { jsenvPluginDropToOpen } from "./drop_to_open/jsenv_plugin_drop_to_open.js";
@@ -58,6 +59,7 @@ export const getCorePlugins = ({
58
59
  scenarioPlaceholders = true,
59
60
  ribbon = true,
60
61
  dropToOpen = true,
62
+ customElementsRedefine = true,
61
63
  packageSideEffects = false,
62
64
  } = {}) => {
63
65
  if (cacheControl === true) {
@@ -154,6 +156,7 @@ export const getCorePlugins = ({
154
156
  ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
155
157
  ...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
156
158
  ...(dropToOpen ? [jsenvPluginDropToOpen()] : []),
159
+ ...(customElementsRedefine ? [jsenvPluginCustomElementsRedefine()] : []),
157
160
  jsenvPluginCleanHTML(),
158
161
  ...(packageSideEffects
159
162
  ? [jsenvPluginPackageSideEffects({ packageDirectory })]