@lwrjs/loader 0.17.2-alpha.9 → 0.17.2

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.
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6
6
  */
7
- /* LWR Module Loader v0.17.2-alpha.9 */
7
+ /* LWR Module Loader v0.17.2 */
8
8
  const templateRegex = /\{([0-9]+)\}/g;
9
9
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
10
  function templateString(template, args) {
@@ -538,20 +538,21 @@ class ImportMetadataResolver {
538
538
  if (!uri) {
539
539
  throw new LoaderError(UNRESOLVEABLE_MAPPING_ERROR, [specifier]);
540
540
  }
541
- return globalThis.fetch(uri).then((res) => {
542
- if (!res.ok) {
543
- this.config.profiler.logOperationStart({ id: MAPPINGS_ERROR, specifier });
544
- throw new LoaderError(UNRESOLVED, [specifier]);
545
- }
546
- return res
547
- .json()
548
- .then((ret) => {
549
- return ret ;
550
- })
551
- .catch((err) => {
541
+
542
+ return globalThis
543
+ .fetch(uri)
544
+ .then((res) => {
545
+ if (!res.ok) {
546
+ this.config.profiler.logOperationStart({ id: MAPPINGS_ERROR, specifier });
552
547
  throw new LoaderError(UNRESOLVED, [specifier]);
548
+ }
549
+ return res.json().then((ret) => {
550
+ return ret ;
553
551
  });
554
- });
552
+ })
553
+ .catch((err) => {
554
+ throw new LoaderError(UNRESOLVED, [specifier]);
555
+ });
555
556
  }
556
557
 
557
558
  saveImportURIRecord(specifier, uri, identity, isRoot) {
@@ -608,15 +609,28 @@ var MODULE_WARNING; (function (MODULE_WARNING) {
608
609
  */
609
610
  // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
610
611
  const SUPPORTS_TRUSTED_TYPES = typeof trustedTypes !== 'undefined';
611
- function createTrustedTypesPolicy(name, options) {
612
+ const trustedTypePolicyRegistry = {
613
+ __proto__: null
614
+ };
615
+ function createDuplicateSafeTrustedTypesPolicy(name, options) {
616
+ // istanbul ignore next: not testable in coverage collection
617
+ if (trustedTypePolicyRegistry[name]) {
618
+ return trustedTypePolicyRegistry[name];
619
+ }
612
620
  // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
613
- return trustedTypes.createPolicy(name, options);
621
+ // eslint-disable-next-line no-return-assign
622
+ return trustedTypePolicyRegistry[name] = trustedTypes.createPolicy(name, options);
614
623
  }
615
- function createFallbackPolicy(_name, options) {
616
- return options;
624
+ function createDuplicateSafeFallbackPolicy(name, options) {
625
+ if (trustedTypePolicyRegistry[name]) {
626
+ return trustedTypePolicyRegistry[name];
627
+ }
628
+ // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
629
+ // eslint-disable-next-line no-return-assign
630
+ return trustedTypePolicyRegistry[name] = options;
617
631
  }
618
632
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
619
- const createPolicy = SUPPORTS_TRUSTED_TYPES ? createTrustedTypesPolicy : createFallbackPolicy;
633
+ const createPolicy = SUPPORTS_TRUSTED_TYPES ? createDuplicateSafeTrustedTypesPolicy : createDuplicateSafeFallbackPolicy;
620
634
  const policyOptions = {
621
635
  createHTML(value) {
622
636
  return value;
@@ -664,7 +678,7 @@ try {
664
678
  // swallow
665
679
  }
666
680
  const trusted = createPolicy('trusted', policyOptions);
667
- /*! version: 0.23.6 */
681
+ /*! version: 0.24.6 */
668
682
 
669
683
  /* global console,process */
670
684
 
@@ -734,7 +748,7 @@ async function evaluateLoadHookResponse(response, id) {
734
748
  code = `${code}\n//# sourceURL=${id}`; // append sourceURL for debugging
735
749
  try {
736
750
  // TODO eval source maps for debugging
737
- eval(trusted.createScript(code));
751
+ eval(trusted.createScript(code) );
738
752
  } catch (e) {
739
753
  // eslint-disable-next-line lwr/no-unguarded-apis
740
754
  if (process.env.NODE_ENV !== 'production' && hasConsole) {
@@ -1144,7 +1158,25 @@ class ModuleRegistry {
1144
1158
  }
1145
1159
 
1146
1160
  async getModuleDependencyRecord(dependency) {
1147
- const resolvedDepId = await this.resolve(dependency);
1161
+ // Initially resolve the dependency to get its ID, which may be a bundle URL.
1162
+ let resolvedDepId = await this.resolve(dependency);
1163
+
1164
+ // If the resolved dependency ID is a URL, it indicates that the dependency
1165
+ // is provided by a bundle that hasn't been fully instantiated yet.
1166
+ if (isUrl(resolvedDepId)) {
1167
+ // Retrieve the module record corresponding to the bundle URL.
1168
+ const existingRecord = this.moduleRegistry.get(resolvedDepId);
1169
+
1170
+ // If a module record for the bundle exists and we haven't already created an alias for this dependency,
1171
+ // then the bundle is still pending instantiation.
1172
+ if (existingRecord && !this.aliases.has(dependency)) {
1173
+ // Wait for the bundle's instantiation promise to resolve.
1174
+ await existingRecord.instantiation;
1175
+ // After instantiation, re-resolve the dependency.
1176
+ // This should now return the final alias (the logical module ID) instead of the raw bundle URL.
1177
+ resolvedDepId = await this.resolve(dependency);
1178
+ }
1179
+ }
1148
1180
  return this.getModuleRecord(resolvedDepId, dependency);
1149
1181
  }
1150
1182
 
@@ -1368,6 +1400,10 @@ class ModuleRegistry {
1368
1400
 
1369
1401
  // Fallback to the last loader.define call
1370
1402
  if (!moduleDef) {
1403
+ this.logMessage(
1404
+ 'warning',
1405
+ `${moduleName} not found, falling back to the last loader.define call`,
1406
+ );
1371
1407
  moduleDef = this.lastDefine;
1372
1408
  }
1373
1409
 
@@ -177,19 +177,19 @@ export class ImportMetadataResolver {
177
177
  if (!uri) {
178
178
  throw new LoaderError(UNRESOLVEABLE_MAPPING_ERROR, [specifier]);
179
179
  }
180
- return globalThis.fetch(uri).then((res) => {
180
+ return globalThis
181
+ .fetch(uri)
182
+ .then((res) => {
181
183
  if (!res.ok) {
182
184
  this.config.profiler.logOperationStart({ id: MAPPINGS_ERROR, specifier });
183
185
  throw new LoaderError(UNRESOLVED, [specifier]);
184
186
  }
185
- return res
186
- .json()
187
- .then((ret) => {
187
+ return res.json().then((ret) => {
188
188
  return ret;
189
- })
190
- .catch((err) => {
191
- throw new LoaderError(UNRESOLVED, [specifier]);
192
189
  });
190
+ })
191
+ .catch((err) => {
192
+ throw new LoaderError(UNRESOLVED, [specifier]);
193
193
  });
194
194
  }
195
195
  saveImportURIRecord(specifier, uri, identity, isRoot) {
@@ -289,7 +289,23 @@ export class ModuleRegistry {
289
289
  }
290
290
  }
291
291
  async getModuleDependencyRecord(dependency) {
292
- const resolvedDepId = await this.resolve(dependency);
292
+ // Initially resolve the dependency to get its ID, which may be a bundle URL.
293
+ let resolvedDepId = await this.resolve(dependency);
294
+ // If the resolved dependency ID is a URL, it indicates that the dependency
295
+ // is provided by a bundle that hasn't been fully instantiated yet.
296
+ if (isUrl(resolvedDepId)) {
297
+ // Retrieve the module record corresponding to the bundle URL.
298
+ const existingRecord = this.moduleRegistry.get(resolvedDepId);
299
+ // If a module record for the bundle exists and we haven't already created an alias for this dependency,
300
+ // then the bundle is still pending instantiation.
301
+ if (existingRecord && !this.aliases.has(dependency)) {
302
+ // Wait for the bundle's instantiation promise to resolve.
303
+ await existingRecord.instantiation;
304
+ // After instantiation, re-resolve the dependency.
305
+ // This should now return the final alias (the logical module ID) instead of the raw bundle URL.
306
+ resolvedDepId = await this.resolve(dependency);
307
+ }
308
+ }
293
309
  return this.getModuleRecord(resolvedDepId, dependency);
294
310
  }
295
311
  // execute the "top-level code" (the code outside of functions) of a module
@@ -478,6 +494,7 @@ export class ModuleRegistry {
478
494
  moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
479
495
  // Fallback to the last loader.define call
480
496
  if (!moduleDef) {
497
+ this.logMessage('warning', `${moduleName} not found, falling back to the last loader.define call`);
481
498
  moduleDef = this.lastDefine;
482
499
  }
483
500
  // This should not happen
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6
6
  */
7
- /* LWR Legacy Module Loader v0.17.2-alpha.9 */
7
+ /* LWR Legacy Module Loader v0.17.2 */
8
8
  const templateRegex = /\{([0-9]+)\}/g;
9
9
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
10
  function templateString(template, args) {
@@ -331,15 +331,28 @@ var MODULE_WARNING; (function (MODULE_WARNING) {
331
331
  */
332
332
  // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
333
333
  const SUPPORTS_TRUSTED_TYPES = typeof trustedTypes !== 'undefined';
334
- function createTrustedTypesPolicy(name, options) {
334
+ const trustedTypePolicyRegistry = {
335
+ __proto__: null
336
+ };
337
+ function createDuplicateSafeTrustedTypesPolicy(name, options) {
338
+ // istanbul ignore next: not testable in coverage collection
339
+ if (trustedTypePolicyRegistry[name]) {
340
+ return trustedTypePolicyRegistry[name];
341
+ }
335
342
  // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
336
- return trustedTypes.createPolicy(name, options);
343
+ // eslint-disable-next-line no-return-assign
344
+ return trustedTypePolicyRegistry[name] = trustedTypes.createPolicy(name, options);
337
345
  }
338
- function createFallbackPolicy(_name, options) {
339
- return options;
346
+ function createDuplicateSafeFallbackPolicy(name, options) {
347
+ if (trustedTypePolicyRegistry[name]) {
348
+ return trustedTypePolicyRegistry[name];
349
+ }
350
+ // @ts-ignore: Prevent cannot find name 'trustedTypes' error.
351
+ // eslint-disable-next-line no-return-assign
352
+ return trustedTypePolicyRegistry[name] = options;
340
353
  }
341
354
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
342
- const createPolicy = SUPPORTS_TRUSTED_TYPES ? createTrustedTypesPolicy : createFallbackPolicy;
355
+ const createPolicy = SUPPORTS_TRUSTED_TYPES ? createDuplicateSafeTrustedTypesPolicy : createDuplicateSafeFallbackPolicy;
343
356
  const policyOptions = {
344
357
  createHTML(value) {
345
358
  return value;
@@ -387,7 +400,7 @@ try {
387
400
  // swallow
388
401
  }
389
402
  const trusted = createPolicy('trusted', policyOptions);
390
- /*! version: 0.23.6 */
403
+ /*! version: 0.24.6 */
391
404
 
392
405
  /* global console,process */
393
406
 
@@ -457,7 +470,7 @@ async function evaluateLoadHookResponse(response, id) {
457
470
  code = `${code}\n//# sourceURL=${id}`; // append sourceURL for debugging
458
471
  try {
459
472
  // TODO eval source maps for debugging
460
- eval(trusted.createScript(code));
473
+ eval(trusted.createScript(code) );
461
474
  } catch (e) {
462
475
  // eslint-disable-next-line lwr/no-unguarded-apis
463
476
  if (process.env.NODE_ENV !== 'production' && hasConsole) {
@@ -954,7 +967,23 @@ class ModuleRegistry {
954
967
  }
955
968
 
956
969
  async getModuleDependencyRecord(dependency) {
957
- const resolvedDepId = await this.resolve(dependency);
970
+ let resolvedDepId = await this.resolve(dependency);
971
+ // If the resolved dependency ID is a URL, it indicates that the dependency
972
+ // is provided by a bundle that hasn't been fully instantiated yet.
973
+ if (isUrl(resolvedDepId)) {
974
+ // Retrieve the module record corresponding to the bundle URL.
975
+ const existingRecord = this.moduleRegistry.get(resolvedDepId);
976
+
977
+ // If a module record for the bundle exists and we haven't already created an alias for this dependency,
978
+ // then the bundle is still pending instantiation.
979
+ if (existingRecord && !this.aliases.has(dependency)) {
980
+ // Wait for the bundle's instantiation promise to resolve.
981
+ await existingRecord.instantiation;
982
+ // After instantiation, re-resolve the dependency.
983
+ // This should now return the final alias (the logical module ID) instead of the raw bundle URL.
984
+ resolvedDepId = await this.resolve(dependency);
985
+ }
986
+ }
958
987
  return this.getModuleRecord(resolvedDepId, dependency);
959
988
  }
960
989
 
@@ -1179,6 +1208,10 @@ class ModuleRegistry {
1179
1208
 
1180
1209
  // Fallback to the last loader.define call
1181
1210
  if (!moduleDef) {
1211
+ this.logMessage(
1212
+ 'warning',
1213
+ `${moduleName} not found, falling back to the last loader.define call`,
1214
+ );
1182
1215
  moduleDef = this.lastDefine;
1183
1216
  }
1184
1217
 
@@ -1603,11 +1636,9 @@ class Loader {
1603
1636
  sigs = execute;
1604
1637
  }
1605
1638
 
1606
- sigs = sigs || {};
1607
-
1608
1639
  invariant(Array.isArray(deps), INVALID_DEPS);
1609
1640
 
1610
- this.registry.define(name, deps, ctor , sigs );
1641
+ this.registry.define(name, deps, ctor , (sigs || {}) );
1611
1642
  }
1612
1643
 
1613
1644
  /**
@@ -327,7 +327,22 @@ export class ModuleRegistry {
327
327
  }
328
328
  }
329
329
  async getModuleDependencyRecord(dependency) {
330
- const resolvedDepId = await this.resolve(dependency);
330
+ let resolvedDepId = await this.resolve(dependency);
331
+ // If the resolved dependency ID is a URL, it indicates that the dependency
332
+ // is provided by a bundle that hasn't been fully instantiated yet.
333
+ if (isUrl(resolvedDepId)) {
334
+ // Retrieve the module record corresponding to the bundle URL.
335
+ const existingRecord = this.moduleRegistry.get(resolvedDepId);
336
+ // If a module record for the bundle exists and we haven't already created an alias for this dependency,
337
+ // then the bundle is still pending instantiation.
338
+ if (existingRecord && !this.aliases.has(dependency)) {
339
+ // Wait for the bundle's instantiation promise to resolve.
340
+ await existingRecord.instantiation;
341
+ // After instantiation, re-resolve the dependency.
342
+ // This should now return the final alias (the logical module ID) instead of the raw bundle URL.
343
+ resolvedDepId = await this.resolve(dependency);
344
+ }
345
+ }
331
346
  return this.getModuleRecord(resolvedDepId, dependency);
332
347
  }
333
348
  // execute the "top-level code" (the code outside of functions) of a module
@@ -516,6 +531,7 @@ export class ModuleRegistry {
516
531
  moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
517
532
  // Fallback to the last loader.define call
518
533
  if (!moduleDef) {
534
+ this.logMessage('warning', `${moduleName} not found, falling back to the last loader.define call`);
519
535
  moduleDef = this.lastDefine;
520
536
  }
521
537
  // This should not happen
@@ -22,6 +22,7 @@ export default class LoaderShim {
22
22
  private tempDefine;
23
23
  private postCustomInit;
24
24
  private initApp;
25
+ private waitForBody;
25
26
  private waitForDOMContentLoaded;
26
27
  private createProfilerModule;
27
28
  private mountApp;
@@ -115,11 +115,25 @@ export default class LoaderShim {
115
115
  this.enterErrorState(e);
116
116
  }
117
117
  }
118
+ waitForBody() {
119
+ return new Promise((resolve) => {
120
+ // eslint-disable-next-line lwr/no-unguarded-apis
121
+ if (document.body) {
122
+ resolve();
123
+ }
124
+ else {
125
+ const observer = new MutationObserver(() => {
126
+ // eslint-disable-next-line lwr/no-unguarded-apis
127
+ if (document.body) {
128
+ observer.disconnect();
129
+ resolve();
130
+ }
131
+ });
132
+ observer.observe(document.documentElement, { childList: true });
133
+ }
134
+ });
135
+ }
118
136
  waitForDOMContentLoaded() {
119
- // eslint-disable-next-line lwr/no-unguarded-apis
120
- if (typeof document === undefined) {
121
- return Promise.resolve();
122
- }
123
137
  // Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
124
138
  // eslint-disable-next-line lwr/no-unguarded-apis
125
139
  if (document.readyState === 'interactive' || document.readyState === 'complete') {
@@ -161,8 +175,9 @@ export default class LoaderShim {
161
175
  loader.define(...this.defineCache[specifier]);
162
176
  }
163
177
  });
164
- // by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
165
- const { disableInitDefer } = this.config;
178
+ // by default, app initialization is gated on waiting for body to be available
179
+ // this flag uses the DOMContentLoaded event instead
180
+ const { initDeferDOM } = this.config;
166
181
  // Load the import mappings and application bootstrap module
167
182
  loader
168
183
  .registerImportMappings({ imports: importsObj, index }, [
@@ -170,9 +185,14 @@ export default class LoaderShim {
170
185
  rootComponent,
171
186
  ])
172
187
  .then(() => {
173
- if (!disableInitDefer) {
188
+ // eslint-disable-next-line lwr/no-unguarded-apis
189
+ if (typeof window === 'undefined' || typeof document === undefined) {
190
+ return Promise.resolve();
191
+ }
192
+ if (initDeferDOM) {
174
193
  return this.waitForDOMContentLoaded();
175
194
  }
195
+ return this.waitForBody();
176
196
  })
177
197
  .then(() => loader.load(bootstrapModule))
178
198
  .catch((reason) => {
@@ -22,6 +22,7 @@ export default class LoaderShim {
22
22
  private tempDefine;
23
23
  private postCustomInit;
24
24
  private initApp;
25
+ private waitForBody;
25
26
  private waitForDOMContentLoaded;
26
27
  private createProfilerModule;
27
28
  private mountApp;
@@ -114,11 +114,25 @@ export default class LoaderShim {
114
114
  this.enterErrorState(e);
115
115
  }
116
116
  }
117
+ waitForBody() {
118
+ return new Promise((resolve) => {
119
+ // eslint-disable-next-line lwr/no-unguarded-apis
120
+ if (document.body) {
121
+ resolve();
122
+ }
123
+ else {
124
+ const observer = new MutationObserver(() => {
125
+ // eslint-disable-next-line lwr/no-unguarded-apis
126
+ if (document.body) {
127
+ observer.disconnect();
128
+ resolve();
129
+ }
130
+ });
131
+ observer.observe(document.documentElement, { childList: true });
132
+ }
133
+ });
134
+ }
117
135
  waitForDOMContentLoaded() {
118
- // eslint-disable-next-line lwr/no-unguarded-apis
119
- if (typeof document === undefined) {
120
- return Promise.resolve();
121
- }
122
136
  // Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
123
137
  // eslint-disable-next-line lwr/no-unguarded-apis
124
138
  if (document.readyState === 'interactive' || document.readyState === 'complete') {
@@ -158,15 +172,21 @@ export default class LoaderShim {
158
172
  loader.define(...this.defineCache[specifier]);
159
173
  }
160
174
  });
161
- // by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
162
- const { disableInitDefer } = this.config;
175
+ // by default, app initialization is gated on waiting for body to be available
176
+ // this flag uses the DOMContentLoaded event instead
177
+ const { initDeferDOM } = this.config;
163
178
  // Load the import mappings and application bootstrap module
164
179
  loader
165
180
  .registerImportMappings(importMappings)
166
181
  .then(() => {
167
- if (!disableInitDefer) {
182
+ // eslint-disable-next-line lwr/no-unguarded-apis
183
+ if (typeof window === 'undefined' || typeof document === undefined) {
184
+ return Promise.resolve();
185
+ }
186
+ if (initDeferDOM) {
168
187
  return this.waitForDOMContentLoaded();
169
188
  }
189
+ return this.waitForBody();
170
190
  })
171
191
  .then(() => loader.load(bootstrapModule))
172
192
  .catch((reason) => {
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "version": "0.17.2-alpha.9",
8
+ "version": "0.17.2",
9
9
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
10
10
  "repository": {
11
11
  "type": "git",
@@ -60,17 +60,17 @@
60
60
  "build": "yarn build:ts && yarn build:error-shim && yarn build:shim && yarn build:loader && yarn build:shim:bundle && yarn build:shim:bundle:minify"
61
61
  },
62
62
  "devDependencies": {
63
- "@locker/trusted-types": "0.23.6",
64
- "@lwrjs/diagnostics": "0.17.2-alpha.9",
65
- "@lwrjs/types": "0.17.2-alpha.9",
63
+ "@locker/trusted-types": "0.24.6",
64
+ "@lwrjs/diagnostics": "0.17.2",
65
+ "@lwrjs/types": "0.17.2",
66
66
  "@rollup/plugin-node-resolve": "^15.2.3",
67
67
  "@rollup/plugin-sucrase": "^5.0.2",
68
68
  "@rollup/plugin-terser": "^0.4.4",
69
69
  "rollup": "^2.79.2"
70
70
  },
71
71
  "dependencies": {
72
- "@lwrjs/client-modules": "0.17.2-alpha.9",
73
- "@lwrjs/shared-utils": "0.17.2-alpha.9"
72
+ "@lwrjs/client-modules": "0.17.2",
73
+ "@lwrjs/shared-utils": "0.17.2"
74
74
  },
75
75
  "lwc": {
76
76
  "modules": [
@@ -85,10 +85,10 @@
85
85
  ]
86
86
  },
87
87
  "engines": {
88
- "node": ">=18.0.0"
88
+ "node": ">=20.0.0"
89
89
  },
90
90
  "volta": {
91
91
  "extends": "../../../package.json"
92
92
  },
93
- "gitHead": "7ede5d04a97513b9869b13e66155bc4f3920bb99"
93
+ "gitHead": "d64d8888a28da36c05e3d8d9baf51416551863a9"
94
94
  }