@lwrjs/loader 0.10.0-alpha.2 → 0.10.0-alpha.20
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/build/assets/prod/lwr-error-shim.js +2 -1
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.js +636 -256
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.min.js +6 -2
- package/build/assets/prod/lwr-loader-shim-legacy.js +150 -55
- package/build/assets/prod/lwr-loader-shim.bundle.js +583 -259
- package/build/assets/prod/lwr-loader-shim.bundle.min.js +6 -2
- package/build/assets/prod/lwr-loader-shim.js +149 -55
- package/build/bundle/prod/lwr/esmLoader/esmLoader.js +2 -1
- package/build/cjs/index.cjs +1 -1
- package/build/cjs/modules/lwr/esmLoader/importResolver.cjs +17 -0
- package/build/cjs/modules/lwr/esmLoader/importResolverLegacy.cjs +17 -0
- package/build/cjs/modules/lwr/loader/constants/constants.cjs +1 -1
- package/build/cjs/modules/lwr/loader/errors/reportError.cjs +1 -0
- package/build/cjs/modules/lwr/loader/hooks/moduleInvalidation.cjs +1 -0
- package/build/cjs/modules/lwr/loader/hooks/resolveAndLoadHook.cjs +3 -1
- package/build/cjs/modules/lwr/loader/moduleRegistry/importMetadataResolver.cjs +2 -0
- package/build/cjs/modules/lwr/loader/moduleRegistry/moduleRegistry.cjs +2 -0
- package/build/cjs/modules/lwr/loaderLegacy/constants/constants.cjs +1 -1
- package/build/cjs/modules/lwr/loaderLegacy/errors/reportError.cjs +1 -0
- package/build/cjs/modules/lwr/loaderLegacy/hooks/moduleInvalidation.cjs +1 -0
- package/build/cjs/modules/lwr/loaderLegacy/hooks/resolveAndLoadHook.cjs +3 -1
- package/build/cjs/modules/lwr/loaderLegacy/importMap/importMapResolver.cjs +1 -0
- package/build/cjs/modules/lwr/loaderLegacy/importResolver/importResolver.cjs +17 -0
- package/build/cjs/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.cjs +3 -0
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/modules/lwr/esmLoader/esmLoader.js +45 -15
- package/build/modules/lwr/loader/loader.js +433 -203
- package/build/modules/lwr/loaderLegacy/loaderLegacy.js +485 -200
- package/package.json +16 -9
|
@@ -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.10.0-alpha.
|
|
7
|
+
/* LWR Module Loader v0.10.0-alpha.20 */
|
|
8
8
|
const templateRegex = /\{([0-9]+)\}/g;
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
10
|
function templateString(template, args) {
|
|
@@ -18,17 +18,26 @@ function generateErrorMessage(errorInfo, args) {
|
|
|
18
18
|
const message = Array.isArray(args) ? templateString(errorInfo.message, args) : errorInfo.message;
|
|
19
19
|
return `LWR${errorInfo.code}: ${message}`;
|
|
20
20
|
}
|
|
21
|
+
|
|
21
22
|
class LoaderError extends Error {
|
|
22
23
|
constructor(errorInfo, errorArgs) {
|
|
23
24
|
super();
|
|
24
25
|
this.message = generateErrorMessage(errorInfo, errorArgs);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
28
|
+
|
|
27
29
|
function invariant(condition, errorInfo) {
|
|
28
30
|
if (!condition) {
|
|
29
31
|
throw new LoaderError(errorInfo);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
32
41
|
const MISSING_NAME = Object.freeze({
|
|
33
42
|
code: 3000,
|
|
34
43
|
message: 'A module name is required.',
|
|
@@ -119,6 +128,7 @@ const BAD_IMPORT_METADATA = Object.freeze({
|
|
|
119
128
|
level: 0,
|
|
120
129
|
message: 'Invalid import metadata: {0} {1}',
|
|
121
130
|
});
|
|
131
|
+
|
|
122
132
|
/* importMap errors */
|
|
123
133
|
Object.freeze({
|
|
124
134
|
code: 3011,
|
|
@@ -128,7 +138,9 @@ Object.freeze({
|
|
|
128
138
|
|
|
129
139
|
/* eslint-disable lwr/no-unguarded-apis */
|
|
130
140
|
const hasDocument = typeof document !== 'undefined';
|
|
141
|
+
|
|
131
142
|
const hasSetTimeout = typeof setTimeout === 'function';
|
|
143
|
+
|
|
132
144
|
const hasConsole = typeof console !== 'undefined';
|
|
133
145
|
/* eslint-enable lwr/no-unguarded-apis */
|
|
134
146
|
|
|
@@ -136,7 +148,7 @@ function getBaseUrl() {
|
|
|
136
148
|
let baseUrl = undefined;
|
|
137
149
|
if (hasDocument) {
|
|
138
150
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
139
|
-
const baseEl = document.querySelector('base[href]');
|
|
151
|
+
const baseEl = document.querySelector('base[href]') ;
|
|
140
152
|
baseUrl = baseEl && baseEl.href;
|
|
141
153
|
}
|
|
142
154
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
@@ -148,8 +160,10 @@ function getBaseUrl() {
|
|
|
148
160
|
baseUrl = baseUrl.slice(0, lastSepIndex + 1);
|
|
149
161
|
}
|
|
150
162
|
}
|
|
163
|
+
|
|
151
164
|
return baseUrl;
|
|
152
165
|
}
|
|
166
|
+
|
|
153
167
|
/**
|
|
154
168
|
* Check if a string is a URL based on Common Internet Scheme Syntax
|
|
155
169
|
* https://www.ietf.org/rfc/rfc1738.txt
|
|
@@ -176,24 +190,26 @@ function getBaseUrl() {
|
|
|
176
190
|
function isUrl(url) {
|
|
177
191
|
return url.indexOf('://') !== -1;
|
|
178
192
|
}
|
|
193
|
+
|
|
179
194
|
// Borrowed and adapted from https://github.com/systemjs/systemjs/blob/master/src/common.js
|
|
180
195
|
// Resolves the first path segment relative to the second/parent URL
|
|
181
196
|
// eg: resolveIfNotPlainOrUrl('../test', 'http://www.site.com/one/two') => 'http://www.site.com/test'
|
|
182
197
|
// eg: resolveIfNotPlainOrUrl('./x/y/z', 'https://my.com/segment')).toBe('https://my.com/x/y/z')
|
|
183
198
|
function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
184
199
|
const backslashRegEx = /\\/g;
|
|
185
|
-
if (relUrl.indexOf('\\') !== -1)
|
|
186
|
-
relUrl = relUrl.replace(backslashRegEx, '/');
|
|
200
|
+
if (relUrl.indexOf('\\') !== -1) relUrl = relUrl.replace(backslashRegEx, '/');
|
|
187
201
|
// protocol-relative
|
|
188
202
|
if (relUrl[0] === '/' && relUrl[1] === '/') {
|
|
189
203
|
return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl;
|
|
190
204
|
}
|
|
191
205
|
// relative-url
|
|
192
|
-
else if (
|
|
193
|
-
(relUrl[
|
|
194
|
-
(relUrl[1] === '
|
|
195
|
-
|
|
196
|
-
|
|
206
|
+
else if (
|
|
207
|
+
(relUrl[0] === '.' &&
|
|
208
|
+
(relUrl[1] === '/' ||
|
|
209
|
+
(relUrl[1] === '.' && (relUrl[2] === '/' || (relUrl.length === 2 && (relUrl += '/')))) ||
|
|
210
|
+
(relUrl.length === 1 && (relUrl += '/')))) ||
|
|
211
|
+
relUrl[0] === '/'
|
|
212
|
+
) {
|
|
197
213
|
const parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1);
|
|
198
214
|
let pathname;
|
|
199
215
|
if (parentUrl[parentProtocol.length + 1] === '/') {
|
|
@@ -201,21 +217,23 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
201
217
|
if (parentProtocol !== 'file:') {
|
|
202
218
|
pathname = parentUrl.slice(parentProtocol.length + 2);
|
|
203
219
|
pathname = pathname.slice(pathname.indexOf('/') + 1);
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
220
|
+
} else {
|
|
206
221
|
pathname = parentUrl.slice(8);
|
|
207
222
|
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
223
|
+
} else {
|
|
210
224
|
// resolving to :/ so pathname is the /... part
|
|
211
|
-
pathname = parentUrl.slice(
|
|
225
|
+
pathname = parentUrl.slice(
|
|
226
|
+
parentProtocol.length + (parentUrl[parentProtocol.length] === '/' ? 1 : 0),
|
|
227
|
+
);
|
|
212
228
|
}
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
|
|
230
|
+
if (relUrl[0] === '/') return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl;
|
|
231
|
+
|
|
215
232
|
// join together and split for removal of .. and . segments
|
|
216
233
|
// looping the string instead of anything fancy for perf reasons
|
|
217
234
|
// '../../../../../z' resolved to 'x/y' is just 'z'
|
|
218
235
|
const segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl;
|
|
236
|
+
|
|
219
237
|
const output = [];
|
|
220
238
|
let segmentIndex = -1;
|
|
221
239
|
for (let i = 0; i < segmented.length; i++) {
|
|
@@ -226,6 +244,7 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
226
244
|
segmentIndex = -1;
|
|
227
245
|
}
|
|
228
246
|
}
|
|
247
|
+
|
|
229
248
|
// new segment - check if it is relative
|
|
230
249
|
else if (segmented[i] === '.') {
|
|
231
250
|
// ../ segment
|
|
@@ -236,8 +255,7 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
236
255
|
// ./ segment
|
|
237
256
|
else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
|
|
238
257
|
i += 1;
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
258
|
+
} else {
|
|
241
259
|
// the start of a new segment as below
|
|
242
260
|
segmentIndex = i;
|
|
243
261
|
}
|
|
@@ -248,13 +266,14 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
248
266
|
}
|
|
249
267
|
}
|
|
250
268
|
// finish reading out the last segment
|
|
251
|
-
if (segmentIndex !== -1)
|
|
252
|
-
output.push(segmented.slice(segmentIndex));
|
|
269
|
+
if (segmentIndex !== -1) output.push(segmented.slice(segmentIndex));
|
|
253
270
|
return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('');
|
|
254
271
|
}
|
|
255
272
|
}
|
|
273
|
+
|
|
256
274
|
function resolveUrl(relUrl, parentUrl) {
|
|
257
|
-
const resolvedUrl =
|
|
275
|
+
const resolvedUrl =
|
|
276
|
+
resolveIfNotPlainOrUrl(relUrl, parentUrl) ||
|
|
258
277
|
(isUrl(relUrl) ? relUrl : resolveIfNotPlainOrUrl('./' + relUrl, parentUrl));
|
|
259
278
|
return resolvedUrl;
|
|
260
279
|
}
|
|
@@ -267,6 +286,7 @@ function createScript(url) {
|
|
|
267
286
|
script.src = url;
|
|
268
287
|
return script;
|
|
269
288
|
}
|
|
289
|
+
|
|
270
290
|
let lastWindowError$1, lastWindowErrorUrl;
|
|
271
291
|
function loadModuleDef(url) {
|
|
272
292
|
return new Promise(function (resolve, reject) {
|
|
@@ -280,8 +300,7 @@ function loadModuleDef(url) {
|
|
|
280
300
|
document.head.removeChild(script);
|
|
281
301
|
if (lastWindowErrorUrl === url) {
|
|
282
302
|
reject(lastWindowError$1);
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
303
|
+
} else {
|
|
285
304
|
resolve();
|
|
286
305
|
}
|
|
287
306
|
});
|
|
@@ -290,6 +309,7 @@ function loadModuleDef(url) {
|
|
|
290
309
|
}
|
|
291
310
|
});
|
|
292
311
|
}
|
|
312
|
+
|
|
293
313
|
if (hasDocument) {
|
|
294
314
|
// When a script is executed, runtime errors are on the global/window scope which are NOT caught by the script's onerror handler.
|
|
295
315
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
@@ -313,44 +333,53 @@ const MAPPINGS_ERROR = `${LOADER_PREFIX}mappings.error`;
|
|
|
313
333
|
|
|
314
334
|
/* spec based import map resolver */
|
|
315
335
|
class ImportMetadataResolver {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
336
|
+
// Default to empty mappings
|
|
337
|
+
__init() {this.importURICache = new Map();}
|
|
338
|
+
__init2() {this.pendingURICache = new Map();}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
__init3() {this.loadMappingHooks = [];}
|
|
342
|
+
|
|
343
|
+
constructor(config, invalidationCallback) {ImportMetadataResolver.prototype.__init.call(this);ImportMetadataResolver.prototype.__init2.call(this);ImportMetadataResolver.prototype.__init3.call(this);
|
|
321
344
|
this.config = config;
|
|
322
345
|
this.invalidationCallback = invalidationCallback;
|
|
323
346
|
}
|
|
347
|
+
|
|
324
348
|
addLoadMappingHook(hook) {
|
|
325
349
|
this.loadMappingHooks.push(hook);
|
|
326
350
|
}
|
|
351
|
+
|
|
327
352
|
getMappingEndpoint() {
|
|
328
353
|
return this.config.endpoints && this.config.endpoints.uris
|
|
329
354
|
? this.config.endpoints.uris.mapping
|
|
330
355
|
: undefined;
|
|
331
356
|
}
|
|
357
|
+
|
|
332
358
|
getModifiersAsUrlParams() {
|
|
333
359
|
const modifiers = this.config.endpoints ? this.config.endpoints.modifiers : undefined;
|
|
360
|
+
|
|
334
361
|
if (!modifiers) {
|
|
335
362
|
// No modifiers return an empty string to append to the URL
|
|
336
363
|
return '';
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
364
|
+
} else {
|
|
339
365
|
const qs = Object.keys(modifiers)
|
|
340
366
|
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(modifiers[key])}`)
|
|
341
367
|
.join('&');
|
|
342
368
|
return `?${qs}`;
|
|
343
369
|
}
|
|
344
370
|
}
|
|
371
|
+
|
|
345
372
|
buildMappingUrl(specifier) {
|
|
346
373
|
const mappingEndpoint = this.getMappingEndpoint();
|
|
347
374
|
const specifiers = encodeURIComponent(specifier);
|
|
348
375
|
const modifiers = this.getModifiersAsUrlParams();
|
|
349
376
|
return `${mappingEndpoint}${specifiers}${modifiers}`;
|
|
350
377
|
}
|
|
378
|
+
|
|
351
379
|
getBaseUrl() {
|
|
352
380
|
return this.config.baseUrl;
|
|
353
381
|
}
|
|
382
|
+
|
|
354
383
|
registerImportMappings(newImportMetadata, rootSpecifiers) {
|
|
355
384
|
if (!rootSpecifiers || rootSpecifiers.length === 0) {
|
|
356
385
|
const imports = newImportMetadata ? JSON.stringify(newImportMetadata) : 'undefined';
|
|
@@ -372,8 +401,7 @@ class ImportMetadataResolver {
|
|
|
372
401
|
const existing = this.importURICache.get(specifier);
|
|
373
402
|
if (!existing) {
|
|
374
403
|
this.saveImportURIRecord(specifier, uri, indexValue, rootSpecifiers.includes(specifier));
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
404
|
+
} else {
|
|
377
405
|
const identity = indexValue || uri;
|
|
378
406
|
const existingIdentity = existing.identity || existing.uri;
|
|
379
407
|
if (existingIdentity !== identity) {
|
|
@@ -387,22 +415,24 @@ class ImportMetadataResolver {
|
|
|
387
415
|
});
|
|
388
416
|
}
|
|
389
417
|
}
|
|
418
|
+
|
|
390
419
|
// Get URL from the local cache or return undefiend
|
|
391
|
-
|
|
420
|
+
getURI(specifier) {
|
|
392
421
|
return this.importURICache.has(specifier)
|
|
393
422
|
? resolveUrl(this.importURICache.get(specifier).uri, this.getBaseUrl())
|
|
394
423
|
: undefined;
|
|
395
424
|
}
|
|
425
|
+
|
|
396
426
|
resolveLocal(specifier) {
|
|
397
427
|
const uri = this.getURI(specifier);
|
|
398
428
|
if (uri) {
|
|
399
429
|
return uri;
|
|
400
|
-
}
|
|
401
|
-
else if (isUrl(specifier) || specifier.startsWith('/')) {
|
|
430
|
+
} else if (isUrl(specifier) || specifier.startsWith('/')) {
|
|
402
431
|
return specifier;
|
|
403
432
|
}
|
|
404
433
|
return undefined;
|
|
405
434
|
}
|
|
435
|
+
|
|
406
436
|
/**
|
|
407
437
|
* Resolves a the URI for a specified module. It will return the value in this order:
|
|
408
438
|
*
|
|
@@ -417,15 +447,14 @@ class ImportMetadataResolver {
|
|
|
417
447
|
let uri = this.getURI(specifier);
|
|
418
448
|
if (uri) {
|
|
419
449
|
return uri;
|
|
420
|
-
}
|
|
421
|
-
else if (isUrl(specifier) || specifier.startsWith('/')) {
|
|
450
|
+
} else if (isUrl(specifier) || specifier.startsWith('/')) {
|
|
422
451
|
return specifier;
|
|
423
|
-
}
|
|
424
|
-
else {
|
|
452
|
+
} else {
|
|
425
453
|
const pending = this.pendingURICache.get(specifier);
|
|
426
454
|
if (pending) {
|
|
427
455
|
return pending;
|
|
428
456
|
}
|
|
457
|
+
|
|
429
458
|
this.config.profiler.logOperationStart({ id: MAPPINGS_FETCH, specifier });
|
|
430
459
|
const fetchMappingService = this.hasMappingHooks()
|
|
431
460
|
? this.evaluateMappingHooks
|
|
@@ -433,33 +462,37 @@ class ImportMetadataResolver {
|
|
|
433
462
|
const promise = fetchMappingService
|
|
434
463
|
.bind(this)(specifier)
|
|
435
464
|
.then((importMetadata) => {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
465
|
+
if (!importMetadata || !importMetadata.imports) {
|
|
466
|
+
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
467
|
+
}
|
|
468
|
+
this.registerImportMappings(importMetadata, [specifier]);
|
|
469
|
+
uri = this.getURI(specifier);
|
|
470
|
+
if (!uri) {
|
|
471
|
+
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
this.config.profiler.logOperationEnd({ id: MAPPINGS_FETCH, specifier });
|
|
475
|
+
return uri;
|
|
476
|
+
})
|
|
447
477
|
.finally(() => {
|
|
448
|
-
|
|
449
|
-
|
|
478
|
+
this.pendingURICache.delete(specifier);
|
|
479
|
+
});
|
|
480
|
+
|
|
450
481
|
this.pendingURICache.set(specifier, promise);
|
|
451
482
|
return promise;
|
|
452
483
|
}
|
|
453
484
|
}
|
|
454
|
-
|
|
485
|
+
|
|
486
|
+
hasMappingHooks() {
|
|
455
487
|
return this.loadMappingHooks.length > 0;
|
|
456
488
|
}
|
|
489
|
+
|
|
457
490
|
/**
|
|
458
491
|
* Evaluates mapping hooks. Returns first match. If all hooks return null call the mapping service.
|
|
459
492
|
* @param specifier Request module identifier
|
|
460
493
|
* @returns Import Metadata from the module root
|
|
461
494
|
*/
|
|
462
|
-
|
|
495
|
+
async evaluateMappingHooks(specifier) {
|
|
463
496
|
// Check with any registered loadMappingHooks
|
|
464
497
|
const loadMappingHooks = this.loadMappingHooks;
|
|
465
498
|
if (loadMappingHooks.length) {
|
|
@@ -474,13 +507,16 @@ class ImportMetadataResolver {
|
|
|
474
507
|
}
|
|
475
508
|
}
|
|
476
509
|
}
|
|
510
|
+
|
|
477
511
|
// If we still do not have a match call the mapping service
|
|
478
512
|
return this.fetchNewMappings(specifier);
|
|
479
513
|
}
|
|
480
|
-
|
|
514
|
+
|
|
515
|
+
async fetchNewMappings(specifier) {
|
|
481
516
|
if (typeof globalThis.fetch !== 'function') {
|
|
482
517
|
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
483
518
|
}
|
|
519
|
+
|
|
484
520
|
// TODO For module invalidation with bundles it is recommended we have to send back all loaded root specified
|
|
485
521
|
// to ensure we detect all conflicts.
|
|
486
522
|
const uri = resolveUrl(this.buildMappingUrl(specifier), this.getBaseUrl());
|
|
@@ -492,21 +528,21 @@ class ImportMetadataResolver {
|
|
|
492
528
|
return res
|
|
493
529
|
.json()
|
|
494
530
|
.then((ret) => {
|
|
495
|
-
|
|
496
|
-
|
|
531
|
+
return ret ;
|
|
532
|
+
})
|
|
497
533
|
.catch((err) => {
|
|
498
|
-
|
|
499
|
-
|
|
534
|
+
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
535
|
+
});
|
|
500
536
|
});
|
|
501
537
|
}
|
|
502
|
-
|
|
538
|
+
|
|
539
|
+
saveImportURIRecord(specifier, uri, identity, isRoot) {
|
|
503
540
|
if (!identity || uri === identity) {
|
|
504
541
|
this.importURICache.set(specifier, {
|
|
505
542
|
uri,
|
|
506
543
|
isRoot: isRoot,
|
|
507
544
|
});
|
|
508
|
-
}
|
|
509
|
-
else {
|
|
545
|
+
} else {
|
|
510
546
|
this.importURICache.set(specifier, {
|
|
511
547
|
uri,
|
|
512
548
|
identity,
|
|
@@ -519,11 +555,13 @@ class ImportMetadataResolver {
|
|
|
519
555
|
function reportError(error) {
|
|
520
556
|
// TODO eventually this should be configurable instrumentation to send this somewhere
|
|
521
557
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
522
|
-
if (hasConsole)
|
|
523
|
-
console.error(error);
|
|
558
|
+
if (hasConsole) console.error(error);
|
|
524
559
|
}
|
|
525
560
|
|
|
526
|
-
function evaluateHandleStaleModuleHooks(
|
|
561
|
+
function evaluateHandleStaleModuleHooks(
|
|
562
|
+
handleStaleModuleHooks,
|
|
563
|
+
hookArgs,
|
|
564
|
+
) {
|
|
527
565
|
const { name, oldUrl, newUrl } = hookArgs;
|
|
528
566
|
// keep evaluating hooks if return value is null
|
|
529
567
|
for (let i = 0; i < handleStaleModuleHooks.length; i++) {
|
|
@@ -533,39 +571,82 @@ function evaluateHandleStaleModuleHooks(handleStaleModuleHooks, hookArgs) {
|
|
|
533
571
|
if (hookResult !== null) {
|
|
534
572
|
break;
|
|
535
573
|
}
|
|
536
|
-
}
|
|
537
|
-
catch (e) {
|
|
574
|
+
} catch (e) {
|
|
538
575
|
reportError(new LoaderError(STALE_HOOK_ERROR));
|
|
539
576
|
}
|
|
540
577
|
}
|
|
541
578
|
}
|
|
542
579
|
|
|
543
|
-
const MODULE_LOAD_TIMEOUT_TIMER =
|
|
580
|
+
const MODULE_LOAD_TIMEOUT_TIMER = 60 * 1000; // 1m
|
|
581
|
+
|
|
582
|
+
/*!
|
|
583
|
+
* Copyright (C) 2023 salesforce.com, inc.
|
|
584
|
+
*/
|
|
585
|
+
// @ts-ignore: Prevent cannot find name 'trustedTypes' error.
|
|
586
|
+
const SUPPORTS_TRUSTED_TYPES = typeof trustedTypes !== 'undefined';
|
|
587
|
+
function createTrustedTypesPolicy(name, options) {
|
|
588
|
+
// @ts-ignore: Prevent cannot find name 'trustedTypes' error.
|
|
589
|
+
return trustedTypes.createPolicy(name, options);
|
|
590
|
+
}
|
|
591
|
+
function createFallbackPolicy(_name, options) {
|
|
592
|
+
return options;
|
|
593
|
+
}
|
|
594
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
|
|
595
|
+
const createPolicy = SUPPORTS_TRUSTED_TYPES ? createTrustedTypesPolicy : createFallbackPolicy;
|
|
596
|
+
const policyOptions = {
|
|
597
|
+
createHTML(value) {
|
|
598
|
+
return value;
|
|
599
|
+
},
|
|
600
|
+
createScript(value) {
|
|
601
|
+
return value;
|
|
602
|
+
},
|
|
603
|
+
createScriptURL(value) {
|
|
604
|
+
return value;
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
const trusted = createPolicy('trusted', policyOptions);
|
|
608
|
+
/*! version: 0.19.4 */
|
|
544
609
|
|
|
545
610
|
/* global console,process */
|
|
611
|
+
|
|
612
|
+
|
|
546
613
|
let lastWindowError;
|
|
547
614
|
if (hasDocument) {
|
|
548
615
|
globalThis.addEventListener('error', (evt) => {
|
|
549
616
|
lastWindowError = evt.error;
|
|
550
617
|
});
|
|
551
618
|
}
|
|
619
|
+
|
|
552
620
|
if (process.env.NODE_ENV !== 'production') {
|
|
553
621
|
if (!hasSetTimeout && hasConsole) {
|
|
554
622
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
555
623
|
console.warn('setTimeout API is not available, watchdog timer on load hook will not be set');
|
|
556
624
|
}
|
|
557
625
|
}
|
|
626
|
+
|
|
558
627
|
function isCustomResponse(response) {
|
|
559
|
-
return (
|
|
560
|
-
|
|
628
|
+
return (
|
|
629
|
+
Object.prototype.hasOwnProperty.call(response, 'data') &&
|
|
630
|
+
!Object.prototype.hasOwnProperty.call(response, 'blob')
|
|
631
|
+
);
|
|
561
632
|
}
|
|
562
|
-
function isFetchResponse(
|
|
633
|
+
function isFetchResponse(
|
|
634
|
+
response,
|
|
635
|
+
) {
|
|
563
636
|
// if it quacks like a duck...
|
|
564
|
-
return typeof response.blob === 'function';
|
|
637
|
+
return typeof (response ).blob === 'function';
|
|
565
638
|
}
|
|
566
|
-
|
|
567
|
-
|
|
639
|
+
|
|
640
|
+
function isResponseAPromise(
|
|
641
|
+
response
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
,
|
|
646
|
+
) {
|
|
647
|
+
return !!(response && (response ).then);
|
|
568
648
|
}
|
|
649
|
+
|
|
569
650
|
async function evaluateLoadHookResponse(response, id) {
|
|
570
651
|
return Promise.resolve().then(async () => {
|
|
571
652
|
if (!response.status) {
|
|
@@ -574,36 +655,41 @@ async function evaluateLoadHookResponse(response, id) {
|
|
|
574
655
|
if (response.status !== 200) {
|
|
575
656
|
throw new LoaderError(HTTP_FAIL_LOAD, [id, `${response.status}`]);
|
|
576
657
|
}
|
|
658
|
+
|
|
577
659
|
const isResponse = isFetchResponse(response);
|
|
578
660
|
let code;
|
|
579
661
|
if (isCustomResponse(response)) {
|
|
580
662
|
code = response.data;
|
|
581
|
-
}
|
|
582
|
-
else if (isResponse) {
|
|
663
|
+
} else if (isResponse) {
|
|
583
664
|
// handle fetch response
|
|
584
|
-
code = await response.text();
|
|
585
|
-
}
|
|
586
|
-
else {
|
|
665
|
+
code = await (response ).text();
|
|
666
|
+
} else {
|
|
587
667
|
throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
|
|
588
668
|
}
|
|
669
|
+
|
|
589
670
|
if (!code) {
|
|
590
671
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
591
672
|
}
|
|
673
|
+
|
|
592
674
|
code = `${code}\n//# sourceURL=${id}`; // append sourceURL for debugging
|
|
593
675
|
try {
|
|
594
676
|
// TODO eval source maps for debugging
|
|
595
|
-
eval(code);
|
|
596
|
-
}
|
|
597
|
-
catch (e) {
|
|
677
|
+
eval(trusted.createScript(code));
|
|
678
|
+
} catch (e) {
|
|
598
679
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
599
680
|
}
|
|
681
|
+
|
|
600
682
|
if (lastWindowError) {
|
|
601
683
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
602
684
|
}
|
|
603
685
|
return true;
|
|
604
686
|
});
|
|
605
687
|
}
|
|
606
|
-
|
|
688
|
+
|
|
689
|
+
async function evaluateLoadHook(
|
|
690
|
+
id,
|
|
691
|
+
hookPromise,
|
|
692
|
+
) {
|
|
607
693
|
if (!hasSetTimeout) {
|
|
608
694
|
return hookPromise;
|
|
609
695
|
}
|
|
@@ -615,45 +701,91 @@ async function evaluateLoadHook(id, hookPromise) {
|
|
|
615
701
|
}, MODULE_LOAD_TIMEOUT_TIMER);
|
|
616
702
|
hookPromise
|
|
617
703
|
.then((response) => {
|
|
618
|
-
|
|
619
|
-
|
|
704
|
+
resolve(response);
|
|
705
|
+
})
|
|
620
706
|
.catch(() => {
|
|
621
|
-
|
|
622
|
-
|
|
707
|
+
reject(new LoaderError(FAIL_HOOK_LOAD, [id]));
|
|
708
|
+
})
|
|
623
709
|
.finally(() => {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
710
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
711
|
+
clearTimeout(timer);
|
|
712
|
+
});
|
|
627
713
|
});
|
|
628
714
|
}
|
|
629
715
|
|
|
630
716
|
/* global console,process */
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
631
762
|
class ModuleRegistry {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
// The evaluated module registry where the module identifier (name or URL?) is the key
|
|
636
|
-
this.moduleRegistry = new Map();
|
|
637
|
-
// Aliases of modules in the registry
|
|
638
|
-
this.aliases = new Map();
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
constructor(config) {ModuleRegistry.prototype.__init.call(this);ModuleRegistry.prototype.__init2.call(this);ModuleRegistry.prototype.__init3.call(this);
|
|
639
766
|
this.profiler = config.profiler;
|
|
640
|
-
this.resolver = new ImportMetadataResolver(
|
|
767
|
+
this.resolver = new ImportMetadataResolver(
|
|
768
|
+
config,
|
|
769
|
+
this.importMetadataInvalidationCallback.bind(this),
|
|
770
|
+
);
|
|
641
771
|
}
|
|
772
|
+
|
|
642
773
|
async load(id, importer) {
|
|
643
774
|
const resolvedId = await this.resolve(id, importer);
|
|
644
775
|
const moduleRecord = this.getModuleRecord(resolvedId, id);
|
|
645
776
|
if (moduleRecord.evaluated) {
|
|
646
777
|
return moduleRecord.module;
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
778
|
+
} else {
|
|
649
779
|
if (!moduleRecord.evaluationPromise) {
|
|
650
780
|
moduleRecord.evaluationPromise = this.topLevelEvaluation(moduleRecord);
|
|
651
781
|
}
|
|
652
782
|
return moduleRecord.evaluationPromise;
|
|
653
783
|
}
|
|
654
784
|
}
|
|
785
|
+
|
|
655
786
|
async resolve(id, importer) {
|
|
656
787
|
const parentUrl = this.resolver.getBaseUrl(); // only support baseUrl for now
|
|
788
|
+
|
|
657
789
|
let resolved;
|
|
658
790
|
let aliasedId = id;
|
|
659
791
|
const resolveHooks = this.resolveHook;
|
|
@@ -666,6 +798,7 @@ class ModuleRegistry {
|
|
|
666
798
|
// eslint-disable-next-line no-await-in-loop
|
|
667
799
|
result = isResponseAPromise(response) ? await response : response;
|
|
668
800
|
}
|
|
801
|
+
|
|
669
802
|
// if result is not null, attempt resolution
|
|
670
803
|
if (result !== null) {
|
|
671
804
|
if (typeof result === 'string') {
|
|
@@ -676,6 +809,7 @@ class ModuleRegistry {
|
|
|
676
809
|
aliasedId = result; // the next hook will receive the new id
|
|
677
810
|
continue;
|
|
678
811
|
}
|
|
812
|
+
|
|
679
813
|
resolved =
|
|
680
814
|
result && result.url && (resolveIfNotPlainOrUrl(result.url, parentUrl) || result.url);
|
|
681
815
|
if (!resolved) {
|
|
@@ -685,27 +819,32 @@ class ModuleRegistry {
|
|
|
685
819
|
break;
|
|
686
820
|
}
|
|
687
821
|
}
|
|
822
|
+
|
|
688
823
|
if (aliasedId !== id) {
|
|
689
824
|
// resolved module id is the aliased module if it has already been defined
|
|
690
825
|
if (!resolved && this.namedDefineRegistry.has(aliasedId)) {
|
|
691
826
|
return aliasedId;
|
|
692
|
-
}
|
|
693
|
-
else {
|
|
827
|
+
} else {
|
|
694
828
|
id = aliasedId;
|
|
695
829
|
}
|
|
696
830
|
}
|
|
697
831
|
}
|
|
832
|
+
|
|
698
833
|
if (!resolved) {
|
|
699
834
|
const resolvedOrPlain = resolveIfNotPlainOrUrl(id, parentUrl) || id;
|
|
835
|
+
|
|
700
836
|
// if module registry already has named module the resolved id is the plain id
|
|
701
837
|
if (this.moduleRegistry.has(resolvedOrPlain)) {
|
|
702
838
|
return resolvedOrPlain;
|
|
703
839
|
}
|
|
840
|
+
|
|
704
841
|
const resolvedUrl = this.resolver.resolveLocal(resolvedOrPlain);
|
|
705
842
|
if (resolvedUrl) {
|
|
706
843
|
// return the plain id if it is already defined && the resolvedUrl is NOT already in the module registry
|
|
707
|
-
if (
|
|
708
|
-
this.namedDefineRegistry.
|
|
844
|
+
if (
|
|
845
|
+
this.namedDefineRegistry.has(resolvedOrPlain) &&
|
|
846
|
+
this.namedDefineRegistry.get(resolvedOrPlain).defined
|
|
847
|
+
) {
|
|
709
848
|
const record = this.moduleRegistry.get(resolvedUrl);
|
|
710
849
|
if (!record || !this.aliases.has(resolvedOrPlain)) {
|
|
711
850
|
return resolvedOrPlain;
|
|
@@ -713,13 +852,13 @@ class ModuleRegistry {
|
|
|
713
852
|
}
|
|
714
853
|
return resolvedUrl;
|
|
715
854
|
}
|
|
855
|
+
|
|
716
856
|
if (this.namedDefineRegistry.has(resolvedOrPlain)) {
|
|
717
857
|
return resolvedOrPlain;
|
|
718
858
|
}
|
|
719
859
|
try {
|
|
720
860
|
resolved = await this.resolver.resolve(resolvedOrPlain);
|
|
721
|
-
}
|
|
722
|
-
catch (e) {
|
|
861
|
+
} catch (e) {
|
|
723
862
|
// defer to error handling below for unresolved
|
|
724
863
|
}
|
|
725
864
|
}
|
|
@@ -727,6 +866,7 @@ class ModuleRegistry {
|
|
|
727
866
|
if (this.namedDefineRegistry.has(id)) {
|
|
728
867
|
return id;
|
|
729
868
|
}
|
|
869
|
+
|
|
730
870
|
throw new LoaderError(UNRESOLVED, [id]);
|
|
731
871
|
}
|
|
732
872
|
if (importer && isUrl(resolved)) {
|
|
@@ -734,9 +874,11 @@ class ModuleRegistry {
|
|
|
734
874
|
}
|
|
735
875
|
return resolved;
|
|
736
876
|
}
|
|
877
|
+
|
|
737
878
|
has(id) {
|
|
738
879
|
return this.moduleRegistry.has(id);
|
|
739
880
|
}
|
|
881
|
+
|
|
740
882
|
define(name, dependencies, exporter) {
|
|
741
883
|
const mod = this.namedDefineRegistry.get(name);
|
|
742
884
|
// Don't allow redefining a module.
|
|
@@ -748,6 +890,7 @@ class ModuleRegistry {
|
|
|
748
890
|
this.lastDefine = mod;
|
|
749
891
|
return;
|
|
750
892
|
}
|
|
893
|
+
|
|
751
894
|
const moduleDef = {
|
|
752
895
|
name,
|
|
753
896
|
dependencies,
|
|
@@ -758,10 +901,12 @@ class ModuleRegistry {
|
|
|
758
901
|
// if module is "external", resolve the external promise to notify any dependees
|
|
759
902
|
mod.external.resolveExternal(moduleDef);
|
|
760
903
|
}
|
|
904
|
+
|
|
761
905
|
this.profiler.logOperationStart({ id: MODULE_DEFINE, specifier: name });
|
|
762
906
|
this.namedDefineRegistry.set(name, moduleDef);
|
|
763
907
|
this.lastDefine = moduleDef;
|
|
764
908
|
}
|
|
909
|
+
|
|
765
910
|
/**
|
|
766
911
|
* Marks modules as "externally" loaded/provided, so that the loader does not attempt to fetch them.
|
|
767
912
|
*
|
|
@@ -774,6 +919,7 @@ class ModuleRegistry {
|
|
|
774
919
|
let timer;
|
|
775
920
|
const moduleDefPromise = new Promise((resolve, reject) => {
|
|
776
921
|
resolveExternal = resolve;
|
|
922
|
+
|
|
777
923
|
// watch the external for timeout
|
|
778
924
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
779
925
|
timer = setTimeout(() => {
|
|
@@ -791,24 +937,39 @@ class ModuleRegistry {
|
|
|
791
937
|
moduleDefPromise,
|
|
792
938
|
},
|
|
793
939
|
};
|
|
794
|
-
this.namedDefineRegistry.set(id, moduleDef);
|
|
795
|
-
}
|
|
796
|
-
else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
940
|
+
this.namedDefineRegistry.set(id, moduleDef );
|
|
941
|
+
} else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
797
942
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
798
943
|
console.warn(MODULE_ALREADY_LOADED.message, id);
|
|
799
944
|
}
|
|
800
945
|
});
|
|
801
946
|
}
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
// A registry for named AMD defines containing the *metadata* of AMD module
|
|
951
|
+
__init() {this.namedDefineRegistry = new Map();}
|
|
952
|
+
|
|
953
|
+
// The evaluated module registry where the module identifier (name or URL?) is the key
|
|
954
|
+
__init2() {this.moduleRegistry = new Map();}
|
|
955
|
+
|
|
956
|
+
// Aliases of modules in the registry
|
|
957
|
+
__init3() {this.aliases = new Map();}
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
|
|
802
961
|
getImportMetadataResolver() {
|
|
803
962
|
return this.resolver;
|
|
804
963
|
}
|
|
964
|
+
|
|
805
965
|
// Returns an existing module record by the resolvedId or aliased id
|
|
806
|
-
|
|
966
|
+
getExistingModuleRecord(resolvedId, aliasId) {
|
|
807
967
|
const moduleRecord = this.moduleRegistry.get(resolvedId);
|
|
808
968
|
if (moduleRecord) {
|
|
809
969
|
this.storeModuleAlias(aliasId, resolvedId);
|
|
810
970
|
return moduleRecord;
|
|
811
971
|
}
|
|
972
|
+
|
|
812
973
|
// Check if this is a known alias
|
|
813
974
|
if (resolvedId !== aliasId) {
|
|
814
975
|
const alias = this.aliases.get(aliasId);
|
|
@@ -821,13 +982,15 @@ class ModuleRegistry {
|
|
|
821
982
|
}
|
|
822
983
|
return moduleRecord;
|
|
823
984
|
}
|
|
824
|
-
|
|
985
|
+
|
|
986
|
+
getModuleRecord(resolvedId, id) {
|
|
825
987
|
// Look for an existing record
|
|
826
988
|
const existingRecord = this.getExistingModuleRecord(resolvedId, id);
|
|
827
989
|
if (existingRecord) {
|
|
828
990
|
// return existing
|
|
829
991
|
return existingRecord;
|
|
830
992
|
}
|
|
993
|
+
|
|
831
994
|
// Create a new Module Record
|
|
832
995
|
const instantiation = this.getModuleDef(resolvedId, id);
|
|
833
996
|
const dependencyRecords = instantiation.then((moduleDef) => {
|
|
@@ -835,15 +998,17 @@ class ModuleRegistry {
|
|
|
835
998
|
// get dep and filter out exports
|
|
836
999
|
const filtered = dependencies
|
|
837
1000
|
.map((dep) => {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
.filter((depRecord) => depRecord !== undefined);
|
|
1001
|
+
if (dep === 'exports') {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
invariant(dep !== 'require', NO_AMD_REQUIRE);
|
|
1005
|
+
return this.getModuleDependencyRecord.call(this, dep);
|
|
1006
|
+
})
|
|
1007
|
+
.filter((depRecord) => depRecord !== undefined) ;
|
|
1008
|
+
|
|
845
1009
|
return Promise.all(filtered);
|
|
846
1010
|
});
|
|
1011
|
+
|
|
847
1012
|
const newModuleRecord = {
|
|
848
1013
|
id: resolvedId,
|
|
849
1014
|
module: Object.create(null),
|
|
@@ -852,16 +1017,17 @@ class ModuleRegistry {
|
|
|
852
1017
|
evaluated: false,
|
|
853
1018
|
evaluationPromise: null,
|
|
854
1019
|
};
|
|
1020
|
+
|
|
855
1021
|
this.moduleRegistry.set(resolvedId, newModuleRecord);
|
|
856
1022
|
this.storeModuleAlias(id, resolvedId);
|
|
857
1023
|
return newModuleRecord;
|
|
858
1024
|
}
|
|
859
|
-
|
|
1025
|
+
|
|
1026
|
+
storeModuleAlias(aliasId, resolvedId) {
|
|
860
1027
|
if (aliasId !== resolvedId) {
|
|
861
1028
|
if (!this.aliases.has(aliasId)) {
|
|
862
1029
|
this.aliases.set(aliasId, resolvedId);
|
|
863
|
-
}
|
|
864
|
-
else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
1030
|
+
} else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
865
1031
|
// Warn the user if they were not aliasing to the resolvedId
|
|
866
1032
|
const currentResolvedId = this.aliases.get(aliasId);
|
|
867
1033
|
if (currentResolvedId !== resolvedId) {
|
|
@@ -871,17 +1037,23 @@ class ModuleRegistry {
|
|
|
871
1037
|
}
|
|
872
1038
|
}
|
|
873
1039
|
}
|
|
874
|
-
|
|
1040
|
+
|
|
1041
|
+
async getModuleDependencyRecord(dependency) {
|
|
875
1042
|
const resolvedDepId = await this.resolve(dependency);
|
|
876
1043
|
return this.getModuleRecord(resolvedDepId, dependency);
|
|
877
1044
|
}
|
|
1045
|
+
|
|
878
1046
|
// execute the "top-level code" (the code outside of functions) of a module
|
|
879
|
-
|
|
1047
|
+
async topLevelEvaluation(moduleRecord) {
|
|
880
1048
|
await this.instantiateAll(moduleRecord, {});
|
|
881
1049
|
return this.evaluateModule(moduleRecord, {});
|
|
882
1050
|
}
|
|
1051
|
+
|
|
883
1052
|
// Returns a promise when a module and all of it's dependencies have finished instantiation
|
|
884
|
-
|
|
1053
|
+
async instantiateAll(
|
|
1054
|
+
moduleRecord,
|
|
1055
|
+
instantiatedMap,
|
|
1056
|
+
) {
|
|
885
1057
|
if (!instantiatedMap[moduleRecord.id]) {
|
|
886
1058
|
instantiatedMap[moduleRecord.id] = true;
|
|
887
1059
|
const dependencyModuleRecords = await moduleRecord.dependencyRecords;
|
|
@@ -894,46 +1066,61 @@ class ModuleRegistry {
|
|
|
894
1066
|
}
|
|
895
1067
|
}
|
|
896
1068
|
}
|
|
897
|
-
|
|
1069
|
+
|
|
1070
|
+
async evaluateModule(
|
|
1071
|
+
moduleRecord,
|
|
1072
|
+
evaluationMap,
|
|
1073
|
+
) {
|
|
898
1074
|
const dependencyModuleRecords = await moduleRecord.dependencyRecords;
|
|
899
1075
|
if (dependencyModuleRecords.length > 0) {
|
|
900
1076
|
evaluationMap[moduleRecord.id] = true;
|
|
901
1077
|
// evaluate dependencies first
|
|
902
1078
|
await this.evaluateModuleDependencies(dependencyModuleRecords, evaluationMap);
|
|
903
1079
|
}
|
|
1080
|
+
|
|
904
1081
|
const { exporter, dependencies } = await moduleRecord.instantiation;
|
|
905
1082
|
// The exports object automatically gets filled in by the exporter evaluation
|
|
906
1083
|
const exports = {};
|
|
907
|
-
const depsMapped = await Promise.all(
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1084
|
+
const depsMapped = await Promise.all(
|
|
1085
|
+
dependencies.map(async (dep) => {
|
|
1086
|
+
if (dep === 'exports') {
|
|
1087
|
+
return exports;
|
|
1088
|
+
}
|
|
1089
|
+
const resolvedDepId = await this.resolve(dep);
|
|
1090
|
+
|
|
1091
|
+
const moduleRecord = this.moduleRegistry.get(resolvedDepId) ;
|
|
1092
|
+
if (!moduleRecord) {
|
|
1093
|
+
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const module = moduleRecord.module;
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Circular dependencies are handled properly when named exports are used,
|
|
1100
|
+
* however, for default exports there is a bug: https://github.com/rollup/rollup/issues/3384
|
|
1101
|
+
*
|
|
1102
|
+
* The workaround below applies for circular dependencies (!moduleRecord.evaluated)
|
|
1103
|
+
*/
|
|
1104
|
+
if (!moduleRecord.evaluated) {
|
|
1105
|
+
return this.getCircularDependencyWrapper(module);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (module) {
|
|
1109
|
+
return module.__defaultInterop ? module.default : module;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
914
1112
|
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
* Circular dependencies are handled properly when named exports are used,
|
|
919
|
-
* however, for default exports there is a bug: https://github.com/rollup/rollup/issues/3384
|
|
920
|
-
*
|
|
921
|
-
* The workaround below applies for circular dependencies (!moduleRecord.evaluated)
|
|
922
|
-
*/
|
|
923
|
-
if (!moduleRecord.evaluated) {
|
|
924
|
-
return this.getCircularDependencyWrapper(module);
|
|
925
|
-
}
|
|
926
|
-
if (module) {
|
|
927
|
-
return module.__defaultInterop ? module.default : module;
|
|
928
|
-
}
|
|
929
|
-
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
930
|
-
}));
|
|
1113
|
+
}),
|
|
1114
|
+
);
|
|
1115
|
+
|
|
931
1116
|
// W-10029836 - In the case where we could be instantiating multiple graphs at the same time lets make sure the module have not already been evaluated
|
|
932
1117
|
if (moduleRecord.evaluated) {
|
|
933
1118
|
return moduleRecord.module;
|
|
934
1119
|
}
|
|
1120
|
+
|
|
935
1121
|
// evaluates the module function
|
|
936
1122
|
let moduleDefault = exporter(...depsMapped);
|
|
1123
|
+
|
|
937
1124
|
// value is returned from exporter, then we are not using named exports
|
|
938
1125
|
if (moduleDefault !== undefined) {
|
|
939
1126
|
moduleDefault = { default: moduleDefault };
|
|
@@ -949,7 +1136,9 @@ class ModuleRegistry {
|
|
|
949
1136
|
Object.defineProperty(exports, '__useDefault', { value: true });
|
|
950
1137
|
}
|
|
951
1138
|
}
|
|
1139
|
+
|
|
952
1140
|
const moduleExports = moduleDefault || exports;
|
|
1141
|
+
|
|
953
1142
|
// update the module record
|
|
954
1143
|
// copy over enumerable public methods to module
|
|
955
1144
|
for (const key in moduleExports) {
|
|
@@ -963,6 +1152,7 @@ class ModuleRegistry {
|
|
|
963
1152
|
},
|
|
964
1153
|
});
|
|
965
1154
|
}
|
|
1155
|
+
|
|
966
1156
|
// copy non-enumerable to module
|
|
967
1157
|
if (moduleExports.__useDefault) {
|
|
968
1158
|
Object.defineProperty(moduleRecord.module, '__useDefault', { value: true });
|
|
@@ -973,27 +1163,36 @@ class ModuleRegistry {
|
|
|
973
1163
|
if (moduleExports.__esModule) {
|
|
974
1164
|
Object.defineProperty(moduleRecord.module, '__esModule', { value: true });
|
|
975
1165
|
}
|
|
1166
|
+
|
|
976
1167
|
moduleRecord.evaluated = true;
|
|
977
1168
|
Object.freeze(moduleRecord.module);
|
|
978
1169
|
return moduleRecord.module;
|
|
979
1170
|
}
|
|
1171
|
+
|
|
980
1172
|
// Determines if named exports module has only default export
|
|
981
|
-
|
|
982
|
-
return (
|
|
1173
|
+
isNamedExportDefaultOnly(exports) {
|
|
1174
|
+
return (
|
|
1175
|
+
exports !== undefined &&
|
|
983
1176
|
Object.getOwnPropertyNames(exports).length === 2 &&
|
|
984
1177
|
Object.prototype.hasOwnProperty.call(exports, 'default') &&
|
|
985
|
-
Object.prototype.hasOwnProperty.call(exports, '__esModule')
|
|
1178
|
+
Object.prototype.hasOwnProperty.call(exports, '__esModule')
|
|
1179
|
+
);
|
|
986
1180
|
}
|
|
1181
|
+
|
|
987
1182
|
// Wrap the dependency in a function that can be called and detected by __circular__ property.
|
|
988
1183
|
// The LWC engine checks for __circular__ to detect circular dependencies.
|
|
989
|
-
|
|
1184
|
+
getCircularDependencyWrapper(module) {
|
|
990
1185
|
const tmp = () => {
|
|
991
1186
|
return module.__useDefault || module.__defaultInterop ? module.default : module;
|
|
992
1187
|
};
|
|
993
1188
|
tmp.__circular__ = true;
|
|
994
1189
|
return tmp;
|
|
995
1190
|
}
|
|
996
|
-
|
|
1191
|
+
|
|
1192
|
+
async evaluateModuleDependencies(
|
|
1193
|
+
dependencyModuleRecords,
|
|
1194
|
+
evaluationMap,
|
|
1195
|
+
) {
|
|
997
1196
|
for (let i = 0; i < dependencyModuleRecords.length; i++) {
|
|
998
1197
|
const depRecord = dependencyModuleRecords[i];
|
|
999
1198
|
if (!depRecord.evaluated && !evaluationMap[depRecord.id]) {
|
|
@@ -1003,15 +1202,17 @@ class ModuleRegistry {
|
|
|
1003
1202
|
}
|
|
1004
1203
|
}
|
|
1005
1204
|
}
|
|
1006
|
-
|
|
1205
|
+
|
|
1206
|
+
async getModuleDef(resolvedId, originalId) {
|
|
1007
1207
|
// reset lastDefine
|
|
1008
1208
|
this.lastDefine = undefined;
|
|
1209
|
+
|
|
1009
1210
|
// the module name can be the resolved ID or the original ID if neither are URL's.
|
|
1010
1211
|
const moduleName = !isUrl(resolvedId)
|
|
1011
1212
|
? resolvedId
|
|
1012
1213
|
: originalId !== resolvedId
|
|
1013
|
-
|
|
1014
|
-
|
|
1214
|
+
? originalId
|
|
1215
|
+
: undefined;
|
|
1015
1216
|
let moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
|
|
1016
1217
|
if (moduleDef && moduleDef.external) {
|
|
1017
1218
|
return moduleDef.external.moduleDefPromise;
|
|
@@ -1024,67 +1225,75 @@ class ModuleRegistry {
|
|
|
1024
1225
|
this.profiler.logOperationStart({ id: MODULE_FETCH, specifier });
|
|
1025
1226
|
return Promise.resolve()
|
|
1026
1227
|
.then(async () => {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1228
|
+
const loadHooks = this.loadHook;
|
|
1229
|
+
if (loadHooks) {
|
|
1230
|
+
for (let i = 0; i < loadHooks.length; i++) {
|
|
1231
|
+
const loadHook = loadHooks[i];
|
|
1232
|
+
const response = loadHook(resolvedId, parentUrl);
|
|
1233
|
+
const result = (
|
|
1234
|
+
isResponseAPromise(response)
|
|
1235
|
+
? // eslint-disable-next-line no-await-in-loop
|
|
1236
|
+
await evaluateLoadHook(resolvedId, response)
|
|
1237
|
+
: response
|
|
1238
|
+
) ;
|
|
1239
|
+
if (result === undefined) {
|
|
1240
|
+
throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
|
|
1241
|
+
}
|
|
1242
|
+
if (result && result !== null) {
|
|
1243
|
+
return evaluateLoadHookResponse(result, resolvedId);
|
|
1244
|
+
}
|
|
1041
1245
|
}
|
|
1042
1246
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
})
|
|
1247
|
+
return false;
|
|
1248
|
+
})
|
|
1046
1249
|
.then((result) => {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1250
|
+
if (result !== true && hasDocument) {
|
|
1251
|
+
return loadModuleDef(resolvedId);
|
|
1252
|
+
}
|
|
1253
|
+
})
|
|
1051
1254
|
.then(() => {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
moduleDef
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1255
|
+
// Attempt to retrieve the module definition by name first
|
|
1256
|
+
moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
|
|
1257
|
+
|
|
1258
|
+
// Fallback to the last loader.define call
|
|
1259
|
+
if (!moduleDef) {
|
|
1260
|
+
moduleDef = this.lastDefine;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// This should not happen
|
|
1264
|
+
if (!moduleDef) {
|
|
1265
|
+
throw new LoaderError(FAIL_INSTANTIATE, [resolvedId]);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
this.profiler.logOperationEnd({ id: MODULE_FETCH, specifier });
|
|
1269
|
+
return moduleDef;
|
|
1270
|
+
})
|
|
1065
1271
|
.catch((e) => {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1272
|
+
this.profiler.logOperationStart({ id: MODULE_ERROR, specifier });
|
|
1273
|
+
throw e;
|
|
1274
|
+
});
|
|
1069
1275
|
}
|
|
1276
|
+
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
|
|
1070
1280
|
addLoaderPlugin(hooks) {
|
|
1071
1281
|
if (typeof hooks !== 'object') {
|
|
1072
1282
|
throw new LoaderError(INVALID_HOOK);
|
|
1073
1283
|
}
|
|
1074
1284
|
const { loadModule: loadHook, resolveModule: resolveHook, loadMapping } = hooks;
|
|
1285
|
+
|
|
1075
1286
|
if (resolveHook) {
|
|
1076
1287
|
if (this.resolveHook) {
|
|
1077
1288
|
this.resolveHook.push(resolveHook);
|
|
1078
|
-
}
|
|
1079
|
-
else {
|
|
1289
|
+
} else {
|
|
1080
1290
|
this.resolveHook = [resolveHook];
|
|
1081
1291
|
}
|
|
1082
1292
|
}
|
|
1083
1293
|
if (loadHook) {
|
|
1084
1294
|
if (this.loadHook) {
|
|
1085
1295
|
this.loadHook.push(loadHook);
|
|
1086
|
-
}
|
|
1087
|
-
else {
|
|
1296
|
+
} else {
|
|
1088
1297
|
this.loadHook = [loadHook];
|
|
1089
1298
|
}
|
|
1090
1299
|
}
|
|
@@ -1092,7 +1301,8 @@ class ModuleRegistry {
|
|
|
1092
1301
|
this.resolver.addLoadMappingHook(loadMapping);
|
|
1093
1302
|
}
|
|
1094
1303
|
}
|
|
1095
|
-
|
|
1304
|
+
|
|
1305
|
+
importMetadataInvalidationCallback({ name, oldUrl, newUrl }) {
|
|
1096
1306
|
const handleStaleModuleHooks = this.handleStaleModuleHook;
|
|
1097
1307
|
if (handleStaleModuleHooks) {
|
|
1098
1308
|
evaluateHandleStaleModuleHooks(handleStaleModuleHooks, {
|
|
@@ -1100,19 +1310,19 @@ class ModuleRegistry {
|
|
|
1100
1310
|
oldUrl,
|
|
1101
1311
|
newUrl,
|
|
1102
1312
|
});
|
|
1103
|
-
}
|
|
1104
|
-
else {
|
|
1313
|
+
} else {
|
|
1105
1314
|
if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
1106
1315
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
1107
1316
|
console.warn(`stale module detected ${name}, current URL:${oldUrl}, new URL:${newUrl}`);
|
|
1108
1317
|
}
|
|
1109
1318
|
}
|
|
1110
1319
|
}
|
|
1320
|
+
|
|
1321
|
+
|
|
1111
1322
|
registerHandleStaleModuleHook(handleStaleModule) {
|
|
1112
1323
|
if (this.handleStaleModuleHook) {
|
|
1113
1324
|
this.handleStaleModuleHook.push(handleStaleModule);
|
|
1114
|
-
}
|
|
1115
|
-
else {
|
|
1325
|
+
} else {
|
|
1116
1326
|
this.handleStaleModuleHook = [handleStaleModule];
|
|
1117
1327
|
}
|
|
1118
1328
|
}
|
|
@@ -1122,15 +1332,21 @@ class ModuleRegistry {
|
|
|
1122
1332
|
* The LWR loader is inspired and borrows from the algorithms and native browser principles of https://github.com/systemjs/systemjs
|
|
1123
1333
|
*/
|
|
1124
1334
|
class Loader {
|
|
1335
|
+
|
|
1336
|
+
|
|
1337
|
+
|
|
1125
1338
|
constructor(config) {
|
|
1126
1339
|
let baseUrl = config.baseUrl;
|
|
1127
1340
|
const mappingEndpoint = config.endpoints ? config.endpoints.uris.mapping : undefined;
|
|
1128
1341
|
let profiler = config.profiler;
|
|
1342
|
+
|
|
1129
1343
|
if (!mappingEndpoint) {
|
|
1130
1344
|
throw new LoaderError(NO_MAPPING_URL);
|
|
1131
1345
|
}
|
|
1346
|
+
|
|
1132
1347
|
// add a trailing slash, if it does not exist
|
|
1133
1348
|
config.endpoints.uris.mapping = mappingEndpoint.replace(/\/?$/, '/');
|
|
1349
|
+
|
|
1134
1350
|
if (baseUrl) {
|
|
1135
1351
|
// add a trailing slash, if it does not exist
|
|
1136
1352
|
baseUrl = baseUrl.replace(/\/?$/, '/');
|
|
@@ -1141,6 +1357,7 @@ class Loader {
|
|
|
1141
1357
|
if (!baseUrl) {
|
|
1142
1358
|
throw new LoaderError(NO_BASE_URL);
|
|
1143
1359
|
}
|
|
1360
|
+
|
|
1144
1361
|
if (!profiler) {
|
|
1145
1362
|
// default noop profiler
|
|
1146
1363
|
profiler = {
|
|
@@ -1152,7 +1369,9 @@ class Loader {
|
|
|
1152
1369
|
},
|
|
1153
1370
|
};
|
|
1154
1371
|
}
|
|
1372
|
+
|
|
1155
1373
|
this.registry = new ModuleRegistry(Object.freeze({ endpoints: config.endpoints, baseUrl, profiler }));
|
|
1374
|
+
|
|
1156
1375
|
// TODO: W-10539691 - temp workaround for LWR-Java -- remove once appId is implemented there
|
|
1157
1376
|
if (config.appMetadata && !config.appMetadata.appId) {
|
|
1158
1377
|
// Parse the appId from the bootstrapModule
|
|
@@ -1161,6 +1380,7 @@ class Loader {
|
|
|
1161
1380
|
const appId = match && match[1];
|
|
1162
1381
|
config.appMetadata.appId = appId;
|
|
1163
1382
|
}
|
|
1383
|
+
|
|
1164
1384
|
// TODO: https://github.com/salesforce-experience-platform-emu/lwr/issues/1087
|
|
1165
1385
|
this.services = Object.freeze({
|
|
1166
1386
|
addLoaderPlugin: this.registry.addLoaderPlugin.bind(this.registry),
|
|
@@ -1168,6 +1388,7 @@ class Loader {
|
|
|
1168
1388
|
appMetadata: config.appMetadata,
|
|
1169
1389
|
});
|
|
1170
1390
|
}
|
|
1391
|
+
|
|
1171
1392
|
/**
|
|
1172
1393
|
* Defines/registers a single named AMD module definition.
|
|
1173
1394
|
*
|
|
@@ -1180,14 +1401,18 @@ class Loader {
|
|
|
1180
1401
|
invariant(typeof name === 'string', MISSING_NAME);
|
|
1181
1402
|
let ctor = execute;
|
|
1182
1403
|
let deps = dependencies;
|
|
1404
|
+
|
|
1183
1405
|
// Convert no dependencies form `define('name', function(){}, {});` to: `define('name', [], function(){}, {})`
|
|
1184
1406
|
if (typeof deps === 'function') {
|
|
1185
1407
|
ctor = dependencies;
|
|
1186
1408
|
deps = [];
|
|
1187
1409
|
}
|
|
1410
|
+
|
|
1188
1411
|
invariant(Array.isArray(deps), INVALID_DEPS);
|
|
1189
|
-
|
|
1412
|
+
|
|
1413
|
+
this.registry.define(name, deps, ctor );
|
|
1190
1414
|
}
|
|
1415
|
+
|
|
1191
1416
|
/**
|
|
1192
1417
|
* Retrieves/loads a module, returning it from the registry if it exists and fetching it if it doesn't.
|
|
1193
1418
|
*
|
|
@@ -1199,6 +1424,7 @@ class Loader {
|
|
|
1199
1424
|
async load(id, importer) {
|
|
1200
1425
|
return this.registry.load(id, importer);
|
|
1201
1426
|
}
|
|
1427
|
+
|
|
1202
1428
|
/**
|
|
1203
1429
|
* Checks if a Module exists in the registry. Note, returns false even if the ModuleDefinition exists but the Module has not been instantiated yet (executed).
|
|
1204
1430
|
*
|
|
@@ -1208,6 +1434,7 @@ class Loader {
|
|
|
1208
1434
|
has(id) {
|
|
1209
1435
|
return this.registry.has(id);
|
|
1210
1436
|
}
|
|
1437
|
+
|
|
1211
1438
|
/**
|
|
1212
1439
|
* Resolves the module identifier or URL. Returns the module identifier if the moduleDefinition exists, or the full resolved URL if a URL is given.
|
|
1213
1440
|
*
|
|
@@ -1219,9 +1446,11 @@ class Loader {
|
|
|
1219
1446
|
async resolve(id, importer) {
|
|
1220
1447
|
return this.registry.resolve(id, importer);
|
|
1221
1448
|
}
|
|
1449
|
+
|
|
1222
1450
|
async registerImportMappings(mappings, rootSpecifiers) {
|
|
1223
1451
|
this.registry.getImportMetadataResolver().registerImportMappings(mappings, rootSpecifiers);
|
|
1224
1452
|
}
|
|
1453
|
+
|
|
1225
1454
|
/**
|
|
1226
1455
|
* Marks modules as "externally" loaded/provided (e.g. preloaded), so that the loader does not attempt to load them.
|
|
1227
1456
|
*
|
|
@@ -1233,3 +1462,4 @@ class Loader {
|
|
|
1233
1462
|
}
|
|
1234
1463
|
|
|
1235
1464
|
export { Loader };
|
|
1465
|
+
//# sourceMappingURL=loader.js.map
|