@lwrjs/loader 0.10.0-alpha.0 → 0.10.0-alpha.10
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 +563 -243
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.min.js +2 -2
- package/build/assets/prod/lwr-loader-shim-legacy.js +108 -44
- package/build/assets/prod/lwr-loader-shim.bundle.js +510 -246
- package/build/assets/prod/lwr-loader-shim.bundle.min.js +2 -2
- package/build/assets/prod/lwr-loader-shim.js +107 -44
- package/build/bundle/prod/lwr/esmLoader/esmLoader.js +1 -1
- package/build/modules/lwr/esmLoader/esmLoader.js +44 -15
- package/build/modules/lwr/loader/loader.js +403 -201
- package/build/modules/lwr/loaderLegacy/loaderLegacy.js +454 -198
- package/package.json +13 -8
|
@@ -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.10.0-alpha.
|
|
7
|
+
/* LWR Legacy Module Loader v0.10.0-alpha.10 */
|
|
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.',
|
|
@@ -109,6 +118,7 @@ const FAIL_HOOK_LOAD = Object.freeze({
|
|
|
109
118
|
level: 0,
|
|
110
119
|
message: 'Error loading "{0}" from hook',
|
|
111
120
|
});
|
|
121
|
+
|
|
112
122
|
/* importMap errors */
|
|
113
123
|
const BAD_IMPORT_MAP = Object.freeze({
|
|
114
124
|
code: 3011,
|
|
@@ -118,7 +128,9 @@ const BAD_IMPORT_MAP = Object.freeze({
|
|
|
118
128
|
|
|
119
129
|
/* eslint-disable lwr/no-unguarded-apis */
|
|
120
130
|
const hasDocument = typeof document !== 'undefined';
|
|
131
|
+
|
|
121
132
|
const hasSetTimeout = typeof setTimeout === 'function';
|
|
133
|
+
|
|
122
134
|
const hasConsole = typeof console !== 'undefined';
|
|
123
135
|
/* eslint-enable lwr/no-unguarded-apis */
|
|
124
136
|
|
|
@@ -126,7 +138,7 @@ function getBaseUrl() {
|
|
|
126
138
|
let baseUrl = undefined;
|
|
127
139
|
if (hasDocument) {
|
|
128
140
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
129
|
-
const baseEl = document.querySelector('base[href]');
|
|
141
|
+
const baseEl = document.querySelector('base[href]') ;
|
|
130
142
|
baseUrl = baseEl && baseEl.href;
|
|
131
143
|
}
|
|
132
144
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
@@ -138,8 +150,10 @@ function getBaseUrl() {
|
|
|
138
150
|
baseUrl = baseUrl.slice(0, lastSepIndex + 1);
|
|
139
151
|
}
|
|
140
152
|
}
|
|
153
|
+
|
|
141
154
|
return baseUrl;
|
|
142
155
|
}
|
|
156
|
+
|
|
143
157
|
/**
|
|
144
158
|
* Check if a string is a URL based on Common Internet Scheme Syntax
|
|
145
159
|
* https://www.ietf.org/rfc/rfc1738.txt
|
|
@@ -166,24 +180,26 @@ function getBaseUrl() {
|
|
|
166
180
|
function isUrl(url) {
|
|
167
181
|
return url.indexOf('://') !== -1;
|
|
168
182
|
}
|
|
183
|
+
|
|
169
184
|
// Borrowed and adapted from https://github.com/systemjs/systemjs/blob/master/src/common.js
|
|
170
185
|
// Resolves the first path segment relative to the second/parent URL
|
|
171
186
|
// eg: resolveIfNotPlainOrUrl('../test', 'http://www.site.com/one/two') => 'http://www.site.com/test'
|
|
172
187
|
// eg: resolveIfNotPlainOrUrl('./x/y/z', 'https://my.com/segment')).toBe('https://my.com/x/y/z')
|
|
173
188
|
function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
174
189
|
const backslashRegEx = /\\/g;
|
|
175
|
-
if (relUrl.indexOf('\\') !== -1)
|
|
176
|
-
relUrl = relUrl.replace(backslashRegEx, '/');
|
|
190
|
+
if (relUrl.indexOf('\\') !== -1) relUrl = relUrl.replace(backslashRegEx, '/');
|
|
177
191
|
// protocol-relative
|
|
178
192
|
if (relUrl[0] === '/' && relUrl[1] === '/') {
|
|
179
193
|
return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl;
|
|
180
194
|
}
|
|
181
195
|
// relative-url
|
|
182
|
-
else if (
|
|
183
|
-
(relUrl[
|
|
184
|
-
(relUrl[1] === '
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
else if (
|
|
197
|
+
(relUrl[0] === '.' &&
|
|
198
|
+
(relUrl[1] === '/' ||
|
|
199
|
+
(relUrl[1] === '.' && (relUrl[2] === '/' || (relUrl.length === 2 && (relUrl += '/')))) ||
|
|
200
|
+
(relUrl.length === 1 && (relUrl += '/')))) ||
|
|
201
|
+
relUrl[0] === '/'
|
|
202
|
+
) {
|
|
187
203
|
const parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1);
|
|
188
204
|
let pathname;
|
|
189
205
|
if (parentUrl[parentProtocol.length + 1] === '/') {
|
|
@@ -191,21 +207,23 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
191
207
|
if (parentProtocol !== 'file:') {
|
|
192
208
|
pathname = parentUrl.slice(parentProtocol.length + 2);
|
|
193
209
|
pathname = pathname.slice(pathname.indexOf('/') + 1);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
210
|
+
} else {
|
|
196
211
|
pathname = parentUrl.slice(8);
|
|
197
212
|
}
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
213
|
+
} else {
|
|
200
214
|
// resolving to :/ so pathname is the /... part
|
|
201
|
-
pathname = parentUrl.slice(
|
|
215
|
+
pathname = parentUrl.slice(
|
|
216
|
+
parentProtocol.length + (parentUrl[parentProtocol.length] === '/' ? 1 : 0),
|
|
217
|
+
);
|
|
202
218
|
}
|
|
203
|
-
|
|
204
|
-
|
|
219
|
+
|
|
220
|
+
if (relUrl[0] === '/') return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl;
|
|
221
|
+
|
|
205
222
|
// join together and split for removal of .. and . segments
|
|
206
223
|
// looping the string instead of anything fancy for perf reasons
|
|
207
224
|
// '../../../../../z' resolved to 'x/y' is just 'z'
|
|
208
225
|
const segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl;
|
|
226
|
+
|
|
209
227
|
const output = [];
|
|
210
228
|
let segmentIndex = -1;
|
|
211
229
|
for (let i = 0; i < segmented.length; i++) {
|
|
@@ -216,6 +234,7 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
216
234
|
segmentIndex = -1;
|
|
217
235
|
}
|
|
218
236
|
}
|
|
237
|
+
|
|
219
238
|
// new segment - check if it is relative
|
|
220
239
|
else if (segmented[i] === '.') {
|
|
221
240
|
// ../ segment
|
|
@@ -226,8 +245,7 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
226
245
|
// ./ segment
|
|
227
246
|
else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
|
|
228
247
|
i += 1;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
248
|
+
} else {
|
|
231
249
|
// the start of a new segment as below
|
|
232
250
|
segmentIndex = i;
|
|
233
251
|
}
|
|
@@ -238,13 +256,14 @@ function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
|
|
238
256
|
}
|
|
239
257
|
}
|
|
240
258
|
// finish reading out the last segment
|
|
241
|
-
if (segmentIndex !== -1)
|
|
242
|
-
output.push(segmented.slice(segmentIndex));
|
|
259
|
+
if (segmentIndex !== -1) output.push(segmented.slice(segmentIndex));
|
|
243
260
|
return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('');
|
|
244
261
|
}
|
|
245
262
|
}
|
|
263
|
+
|
|
246
264
|
function resolveUrl(relUrl, parentUrl) {
|
|
247
|
-
const resolvedUrl =
|
|
265
|
+
const resolvedUrl =
|
|
266
|
+
resolveIfNotPlainOrUrl(relUrl, parentUrl) ||
|
|
248
267
|
(isUrl(relUrl) ? relUrl : resolveIfNotPlainOrUrl('./' + relUrl, parentUrl));
|
|
249
268
|
return resolvedUrl;
|
|
250
269
|
}
|
|
@@ -257,6 +276,7 @@ function createScript(url) {
|
|
|
257
276
|
script.src = url;
|
|
258
277
|
return script;
|
|
259
278
|
}
|
|
279
|
+
|
|
260
280
|
let lastWindowError$1, lastWindowErrorUrl;
|
|
261
281
|
function loadModuleDef(url) {
|
|
262
282
|
return new Promise(function (resolve, reject) {
|
|
@@ -270,8 +290,7 @@ function loadModuleDef(url) {
|
|
|
270
290
|
document.head.removeChild(script);
|
|
271
291
|
if (lastWindowErrorUrl === url) {
|
|
272
292
|
reject(lastWindowError$1);
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
293
|
+
} else {
|
|
275
294
|
resolve();
|
|
276
295
|
}
|
|
277
296
|
});
|
|
@@ -280,6 +299,7 @@ function loadModuleDef(url) {
|
|
|
280
299
|
}
|
|
281
300
|
});
|
|
282
301
|
}
|
|
302
|
+
|
|
283
303
|
if (hasDocument) {
|
|
284
304
|
// When a script is executed, runtime errors are on the global/window scope which are NOT caught by the script's onerror handler.
|
|
285
305
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
@@ -292,29 +312,45 @@ if (hasDocument) {
|
|
|
292
312
|
const MODULE_LOAD_TIMEOUT_TIMER = 300000;
|
|
293
313
|
|
|
294
314
|
/* global console,process */
|
|
315
|
+
|
|
316
|
+
|
|
295
317
|
let lastWindowError;
|
|
296
318
|
if (hasDocument) {
|
|
297
319
|
globalThis.addEventListener('error', (evt) => {
|
|
298
320
|
lastWindowError = evt.error;
|
|
299
321
|
});
|
|
300
322
|
}
|
|
323
|
+
|
|
301
324
|
if (process.env.NODE_ENV !== 'production') {
|
|
302
325
|
if (!hasSetTimeout && hasConsole) {
|
|
303
326
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
304
327
|
console.warn('setTimeout API is not available, watchdog timer on load hook will not be set');
|
|
305
328
|
}
|
|
306
329
|
}
|
|
330
|
+
|
|
307
331
|
function isCustomResponse(response) {
|
|
308
|
-
return (
|
|
309
|
-
|
|
332
|
+
return (
|
|
333
|
+
Object.prototype.hasOwnProperty.call(response, 'data') &&
|
|
334
|
+
!Object.prototype.hasOwnProperty.call(response, 'blob')
|
|
335
|
+
);
|
|
310
336
|
}
|
|
311
|
-
function isFetchResponse(
|
|
337
|
+
function isFetchResponse(
|
|
338
|
+
response,
|
|
339
|
+
) {
|
|
312
340
|
// if it quacks like a duck...
|
|
313
|
-
return typeof response.blob === 'function';
|
|
341
|
+
return typeof (response ).blob === 'function';
|
|
314
342
|
}
|
|
315
|
-
|
|
316
|
-
|
|
343
|
+
|
|
344
|
+
function isResponseAPromise(
|
|
345
|
+
response
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
,
|
|
350
|
+
) {
|
|
351
|
+
return !!(response && (response ).then);
|
|
317
352
|
}
|
|
353
|
+
|
|
318
354
|
async function evaluateLoadHookResponse(response, id) {
|
|
319
355
|
return Promise.resolve().then(async () => {
|
|
320
356
|
if (!response.status) {
|
|
@@ -323,36 +359,41 @@ async function evaluateLoadHookResponse(response, id) {
|
|
|
323
359
|
if (response.status !== 200) {
|
|
324
360
|
throw new LoaderError(HTTP_FAIL_LOAD, [id, `${response.status}`]);
|
|
325
361
|
}
|
|
362
|
+
|
|
326
363
|
const isResponse = isFetchResponse(response);
|
|
327
364
|
let code;
|
|
328
365
|
if (isCustomResponse(response)) {
|
|
329
366
|
code = response.data;
|
|
330
|
-
}
|
|
331
|
-
else if (isResponse) {
|
|
367
|
+
} else if (isResponse) {
|
|
332
368
|
// handle fetch response
|
|
333
|
-
code = await response.text();
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
369
|
+
code = await (response ).text();
|
|
370
|
+
} else {
|
|
336
371
|
throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
|
|
337
372
|
}
|
|
373
|
+
|
|
338
374
|
if (!code) {
|
|
339
375
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
340
376
|
}
|
|
377
|
+
|
|
341
378
|
code = `${code}\n//# sourceURL=${id}`; // append sourceURL for debugging
|
|
342
379
|
try {
|
|
343
380
|
// TODO eval source maps for debugging
|
|
344
381
|
eval(code);
|
|
345
|
-
}
|
|
346
|
-
catch (e) {
|
|
382
|
+
} catch (e) {
|
|
347
383
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
348
384
|
}
|
|
385
|
+
|
|
349
386
|
if (lastWindowError) {
|
|
350
387
|
throw new LoaderError(FAIL_LOAD, [id]);
|
|
351
388
|
}
|
|
352
389
|
return true;
|
|
353
390
|
});
|
|
354
391
|
}
|
|
355
|
-
|
|
392
|
+
|
|
393
|
+
async function evaluateLoadHook(
|
|
394
|
+
id,
|
|
395
|
+
hookPromise,
|
|
396
|
+
) {
|
|
356
397
|
if (!hasSetTimeout) {
|
|
357
398
|
return hookPromise;
|
|
358
399
|
}
|
|
@@ -364,26 +405,28 @@ async function evaluateLoadHook(id, hookPromise) {
|
|
|
364
405
|
}, MODULE_LOAD_TIMEOUT_TIMER);
|
|
365
406
|
hookPromise
|
|
366
407
|
.then((response) => {
|
|
367
|
-
|
|
368
|
-
|
|
408
|
+
resolve(response);
|
|
409
|
+
})
|
|
369
410
|
.catch(() => {
|
|
370
|
-
|
|
371
|
-
|
|
411
|
+
reject(new LoaderError(FAIL_HOOK_LOAD, [id]));
|
|
412
|
+
})
|
|
372
413
|
.finally(() => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
414
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
415
|
+
clearTimeout(timer);
|
|
416
|
+
});
|
|
376
417
|
});
|
|
377
418
|
}
|
|
378
419
|
|
|
379
420
|
function reportError(error) {
|
|
380
421
|
// TODO eventually this should be configurable instrumentation to send this somewhere
|
|
381
422
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
382
|
-
if (hasConsole)
|
|
383
|
-
console.error(error);
|
|
423
|
+
if (hasConsole) console.error(error);
|
|
384
424
|
}
|
|
385
425
|
|
|
386
|
-
function evaluateHandleStaleModuleHooks(
|
|
426
|
+
function evaluateHandleStaleModuleHooks(
|
|
427
|
+
handleStaleModuleHooks,
|
|
428
|
+
hookArgs,
|
|
429
|
+
) {
|
|
387
430
|
const { name, oldHash, newHash } = hookArgs;
|
|
388
431
|
// keep evaluating hooks if return value is null
|
|
389
432
|
for (let i = 0; i < handleStaleModuleHooks.length; i++) {
|
|
@@ -393,8 +436,7 @@ function evaluateHandleStaleModuleHooks(handleStaleModuleHooks, hookArgs) {
|
|
|
393
436
|
if (hookResult !== null) {
|
|
394
437
|
break;
|
|
395
438
|
}
|
|
396
|
-
}
|
|
397
|
-
catch (e) {
|
|
439
|
+
} catch (e) {
|
|
398
440
|
reportError(new LoaderError(STALE_HOOK_ERROR));
|
|
399
441
|
}
|
|
400
442
|
}
|
|
@@ -409,32 +451,82 @@ const MODULE_FETCH = `${LOADER_PREFIX}module.fetch`;
|
|
|
409
451
|
const MODULE_ERROR = `${LOADER_PREFIX}module.error`;
|
|
410
452
|
|
|
411
453
|
/* global console,process */
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
412
506
|
class ModuleRegistry {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
// The evaluated module registry where the module identifier (name or URL?) is the key
|
|
417
|
-
this.moduleRegistry = new Map();
|
|
418
|
-
// Aliases of modules in the registry
|
|
419
|
-
this.aliases = new Map();
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
constructor(config) {ModuleRegistry.prototype.__init.call(this);ModuleRegistry.prototype.__init2.call(this);ModuleRegistry.prototype.__init3.call(this);
|
|
420
510
|
this.baseUrl = config.baseUrl || '';
|
|
421
511
|
this.profiler = config.profiler;
|
|
422
512
|
}
|
|
513
|
+
|
|
423
514
|
async load(id, importer) {
|
|
424
515
|
const resolvedId = await this.resolve(id, importer);
|
|
425
516
|
const moduleRecord = this.getModuleRecord(resolvedId, id);
|
|
426
517
|
if (moduleRecord.evaluated) {
|
|
427
518
|
return moduleRecord.module;
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
519
|
+
} else {
|
|
430
520
|
if (!moduleRecord.evaluationPromise) {
|
|
431
521
|
moduleRecord.evaluationPromise = this.topLevelEvaluation(moduleRecord);
|
|
432
522
|
}
|
|
433
523
|
return moduleRecord.evaluationPromise;
|
|
434
524
|
}
|
|
435
525
|
}
|
|
526
|
+
|
|
436
527
|
async resolve(id, importer) {
|
|
437
528
|
const parentUrl = this.baseUrl; // only support baseUrl for now
|
|
529
|
+
|
|
438
530
|
let resolved;
|
|
439
531
|
let aliasedId = id;
|
|
440
532
|
const resolveHooks = this.resolveHook;
|
|
@@ -447,6 +539,7 @@ class ModuleRegistry {
|
|
|
447
539
|
// eslint-disable-next-line no-await-in-loop
|
|
448
540
|
result = isResponseAPromise(response) ? await response : response;
|
|
449
541
|
}
|
|
542
|
+
|
|
450
543
|
// if result is not null, attempt resolution
|
|
451
544
|
if (result !== null) {
|
|
452
545
|
if (typeof result === 'string') {
|
|
@@ -457,6 +550,7 @@ class ModuleRegistry {
|
|
|
457
550
|
aliasedId = result; // the next hook will receive the new id
|
|
458
551
|
continue;
|
|
459
552
|
}
|
|
553
|
+
|
|
460
554
|
resolved =
|
|
461
555
|
result && result.url && (resolveIfNotPlainOrUrl(result.url, parentUrl) || result.url);
|
|
462
556
|
if (!resolved) {
|
|
@@ -466,34 +560,38 @@ class ModuleRegistry {
|
|
|
466
560
|
break;
|
|
467
561
|
}
|
|
468
562
|
}
|
|
563
|
+
|
|
469
564
|
if (aliasedId !== id) {
|
|
470
565
|
// resolved module id is the aliased module if it has already been defined
|
|
471
566
|
if (!resolved && this.namedDefineRegistry.has(aliasedId)) {
|
|
472
567
|
return aliasedId;
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
568
|
+
} else {
|
|
475
569
|
id = aliasedId;
|
|
476
570
|
}
|
|
477
571
|
}
|
|
478
572
|
}
|
|
573
|
+
|
|
479
574
|
if (!resolved) {
|
|
480
575
|
const resolvedOrPlain = resolveIfNotPlainOrUrl(id, parentUrl) || id;
|
|
576
|
+
|
|
481
577
|
// if module registry already has named module the resolved id is the plain id
|
|
482
578
|
if (this.moduleRegistry.has(resolvedOrPlain)) {
|
|
483
579
|
return resolvedOrPlain;
|
|
484
580
|
}
|
|
581
|
+
|
|
485
582
|
if (this.resolver) {
|
|
486
583
|
resolved = this.resolver.resolve(resolvedOrPlain, parentUrl);
|
|
487
584
|
// return the plain id if it is already defined && the resolvedUrl is NOT already in the module registry
|
|
488
|
-
if (
|
|
489
|
-
this.namedDefineRegistry.
|
|
585
|
+
if (
|
|
586
|
+
this.namedDefineRegistry.has(resolvedOrPlain) &&
|
|
587
|
+
this.namedDefineRegistry.get(resolvedOrPlain).defined
|
|
588
|
+
) {
|
|
490
589
|
const record = this.moduleRegistry.get(resolved);
|
|
491
590
|
if (!record || !this.aliases.has(resolvedOrPlain)) {
|
|
492
591
|
return resolvedOrPlain;
|
|
493
592
|
}
|
|
494
593
|
}
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
594
|
+
} else {
|
|
497
595
|
resolved = resolvedOrPlain;
|
|
498
596
|
}
|
|
499
597
|
}
|
|
@@ -501,6 +599,7 @@ class ModuleRegistry {
|
|
|
501
599
|
if (this.namedDefineRegistry.has(id)) {
|
|
502
600
|
return id;
|
|
503
601
|
}
|
|
602
|
+
|
|
504
603
|
throw new LoaderError(UNRESOLVED, [id]);
|
|
505
604
|
}
|
|
506
605
|
if (importer && isUrl(resolved)) {
|
|
@@ -508,10 +607,17 @@ class ModuleRegistry {
|
|
|
508
607
|
}
|
|
509
608
|
return resolved;
|
|
510
609
|
}
|
|
610
|
+
|
|
511
611
|
has(id) {
|
|
512
612
|
return this.moduleRegistry.has(id);
|
|
513
613
|
}
|
|
514
|
-
|
|
614
|
+
|
|
615
|
+
define(
|
|
616
|
+
name,
|
|
617
|
+
dependencies,
|
|
618
|
+
exporter,
|
|
619
|
+
signatures,
|
|
620
|
+
) {
|
|
515
621
|
const mod = this.namedDefineRegistry.get(name);
|
|
516
622
|
// Don't allow redefining a module.
|
|
517
623
|
if (mod && mod.defined) {
|
|
@@ -522,6 +628,7 @@ class ModuleRegistry {
|
|
|
522
628
|
this.lastDefine = mod;
|
|
523
629
|
return;
|
|
524
630
|
}
|
|
631
|
+
|
|
525
632
|
const moduleDef = {
|
|
526
633
|
name,
|
|
527
634
|
dependencies,
|
|
@@ -533,9 +640,11 @@ class ModuleRegistry {
|
|
|
533
640
|
// if module is "external", resolve the external promise to notify any dependees
|
|
534
641
|
mod.external.resolveExternal(moduleDef);
|
|
535
642
|
}
|
|
643
|
+
|
|
536
644
|
this.profiler.logOperationStart({ id: MODULE_DEFINE, specifier: name });
|
|
537
645
|
this.namedDefineRegistry.set(name, moduleDef);
|
|
538
646
|
this.lastDefine = moduleDef;
|
|
647
|
+
|
|
539
648
|
// Check signatures of dependencies against those in the namedDefineRegistry
|
|
540
649
|
if (signatures.hashes) {
|
|
541
650
|
Object.entries(signatures.hashes).forEach(([dep, sig]) => {
|
|
@@ -543,6 +652,7 @@ class ModuleRegistry {
|
|
|
543
652
|
});
|
|
544
653
|
}
|
|
545
654
|
}
|
|
655
|
+
|
|
546
656
|
/**
|
|
547
657
|
* Marks modules as "externally" loaded/provided, so that the loader does not attempt to fetch them.
|
|
548
658
|
*
|
|
@@ -555,6 +665,7 @@ class ModuleRegistry {
|
|
|
555
665
|
let timer;
|
|
556
666
|
const moduleDefPromise = new Promise((resolve, reject) => {
|
|
557
667
|
resolveExternal = resolve;
|
|
668
|
+
|
|
558
669
|
// watch the external for timeout
|
|
559
670
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
560
671
|
timer = setTimeout(() => {
|
|
@@ -572,15 +683,15 @@ class ModuleRegistry {
|
|
|
572
683
|
moduleDefPromise,
|
|
573
684
|
},
|
|
574
685
|
};
|
|
575
|
-
this.namedDefineRegistry.set(id, moduleDef);
|
|
576
|
-
}
|
|
577
|
-
else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
686
|
+
this.namedDefineRegistry.set(id, moduleDef );
|
|
687
|
+
} else if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
578
688
|
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
579
689
|
console.warn(MODULE_ALREADY_LOADED.message, id);
|
|
580
690
|
}
|
|
581
691
|
});
|
|
582
692
|
}
|
|
583
|
-
|
|
693
|
+
|
|
694
|
+
checkModuleSignature(name, signature) {
|
|
584
695
|
const moduleDef = this.namedDefineRegistry.get(name);
|
|
585
696
|
if (!moduleDef) {
|
|
586
697
|
// Placeholder module definition entry for saving known signature
|
|
@@ -591,9 +702,10 @@ class ModuleRegistry {
|
|
|
591
702
|
},
|
|
592
703
|
defined: false,
|
|
593
704
|
};
|
|
594
|
-
this.namedDefineRegistry.set(name, modDef);
|
|
705
|
+
this.namedDefineRegistry.set(name, modDef );
|
|
595
706
|
return;
|
|
596
707
|
}
|
|
708
|
+
|
|
597
709
|
const currentSig = moduleDef.signatures ? moduleDef.signatures.ownHash : undefined;
|
|
598
710
|
if (currentSig && signature !== currentSig) {
|
|
599
711
|
const handleStaleModuleHooks = this.handleStaleModuleHook;
|
|
@@ -603,25 +715,43 @@ class ModuleRegistry {
|
|
|
603
715
|
oldHash: currentSig,
|
|
604
716
|
newHash: signature,
|
|
605
717
|
});
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
718
|
+
} else {
|
|
608
719
|
if (process.env.NODE_ENV !== 'production' && hasConsole) {
|
|
609
720
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
610
|
-
console.warn(
|
|
721
|
+
console.warn(
|
|
722
|
+
`stale module detected ${name}, current sig:${currentSig}, new sig:${signature}`,
|
|
723
|
+
);
|
|
611
724
|
}
|
|
612
725
|
}
|
|
613
726
|
}
|
|
614
727
|
}
|
|
728
|
+
|
|
729
|
+
|
|
615
730
|
setImportResolver(resolver) {
|
|
616
731
|
this.resolver = resolver;
|
|
617
732
|
}
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
// A registry for named AMD defines containing the *metadata* of AMD module
|
|
737
|
+
__init() {this.namedDefineRegistry = new Map();}
|
|
738
|
+
|
|
739
|
+
// The evaluated module registry where the module identifier (name or URL?) is the key
|
|
740
|
+
__init2() {this.moduleRegistry = new Map();}
|
|
741
|
+
|
|
742
|
+
// Aliases of modules in the registry
|
|
743
|
+
__init3() {this.aliases = new Map();}
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
618
747
|
// Returns an existing module record by the resolvedId or aliased id
|
|
619
|
-
|
|
748
|
+
getExistingModuleRecord(resolvedId, aliasId) {
|
|
620
749
|
const moduleRecord = this.moduleRegistry.get(resolvedId);
|
|
621
750
|
if (moduleRecord) {
|
|
622
751
|
this.storeModuleAlias(aliasId, resolvedId);
|
|
623
752
|
return moduleRecord;
|
|
624
753
|
}
|
|
754
|
+
|
|
625
755
|
// Check if this is a known alias
|
|
626
756
|
if (resolvedId !== aliasId) {
|
|
627
757
|
const alias = this.aliases.get(aliasId);
|
|
@@ -634,13 +764,15 @@ class ModuleRegistry {
|
|
|
634
764
|
}
|
|
635
765
|
return moduleRecord;
|
|
636
766
|
}
|
|
637
|
-
|
|
767
|
+
|
|
768
|
+
getModuleRecord(resolvedId, id) {
|
|
638
769
|
// Look for an existing record
|
|
639
770
|
const existingRecord = this.getExistingModuleRecord(resolvedId, id);
|
|
640
771
|
if (existingRecord) {
|
|
641
772
|
// return existing
|
|
642
773
|
return existingRecord;
|
|
643
774
|
}
|
|
775
|
+
|
|
644
776
|
// Create a new Module Record
|
|
645
777
|
const instantiation = this.getModuleDef(resolvedId, id);
|
|
646
778
|
const dependencyRecords = instantiation.then((moduleDef) => {
|
|
@@ -648,15 +780,17 @@ class ModuleRegistry {
|
|
|
648
780
|
// get dep and filter out exports
|
|
649
781
|
const filtered = dependencies
|
|
650
782
|
.map((dep) => {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
.filter((depRecord) => depRecord !== undefined);
|
|
783
|
+
if (dep === 'exports') {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
invariant(dep !== 'require', NO_AMD_REQUIRE);
|
|
787
|
+
return this.getModuleDependencyRecord.call(this, dep);
|
|
788
|
+
})
|
|
789
|
+
.filter((depRecord) => depRecord !== undefined) ;
|
|
790
|
+
|
|
658
791
|
return Promise.all(filtered);
|
|
659
792
|
});
|
|
793
|
+
|
|
660
794
|
const newModuleRecord = {
|
|
661
795
|
id: resolvedId,
|
|
662
796
|
module: Object.create(null),
|
|
@@ -669,12 +803,12 @@ class ModuleRegistry {
|
|
|
669
803
|
this.storeModuleAlias(id, resolvedId);
|
|
670
804
|
return newModuleRecord;
|
|
671
805
|
}
|
|
672
|
-
|
|
806
|
+
|
|
807
|
+
storeModuleAlias(aliasId, resolvedId) {
|
|
673
808
|
if (aliasId !== resolvedId) {
|
|
674
809
|
if (!this.aliases.has(aliasId)) {
|
|
675
810
|
this.aliases.set(aliasId, resolvedId);
|
|
676
|
-
}
|
|
677
|
-
else if (hasConsole) {
|
|
811
|
+
} else if (hasConsole) {
|
|
678
812
|
// Warn the user if they were not aliasing to the resolvedId
|
|
679
813
|
const currentResolvedId = this.aliases.get(aliasId);
|
|
680
814
|
if (currentResolvedId !== resolvedId) {
|
|
@@ -684,17 +818,23 @@ class ModuleRegistry {
|
|
|
684
818
|
}
|
|
685
819
|
}
|
|
686
820
|
}
|
|
687
|
-
|
|
821
|
+
|
|
822
|
+
async getModuleDependencyRecord(dependency) {
|
|
688
823
|
const resolvedDepId = await this.resolve(dependency);
|
|
689
824
|
return this.getModuleRecord(resolvedDepId, dependency);
|
|
690
825
|
}
|
|
826
|
+
|
|
691
827
|
// execute the "top-level code" (the code outside of functions) of a module
|
|
692
|
-
|
|
828
|
+
async topLevelEvaluation(moduleRecord) {
|
|
693
829
|
await this.instantiateAll(moduleRecord, {});
|
|
694
830
|
return this.evaluateModule(moduleRecord, {});
|
|
695
831
|
}
|
|
832
|
+
|
|
696
833
|
// Returns a promise when a module and all of it's dependencies have finished instantiation
|
|
697
|
-
|
|
834
|
+
async instantiateAll(
|
|
835
|
+
moduleRecord,
|
|
836
|
+
instantiatedMap,
|
|
837
|
+
) {
|
|
698
838
|
if (!instantiatedMap[moduleRecord.id]) {
|
|
699
839
|
instantiatedMap[moduleRecord.id] = true;
|
|
700
840
|
const dependencyModuleRecords = await moduleRecord.dependencyRecords;
|
|
@@ -707,46 +847,61 @@ class ModuleRegistry {
|
|
|
707
847
|
}
|
|
708
848
|
}
|
|
709
849
|
}
|
|
710
|
-
|
|
850
|
+
|
|
851
|
+
async evaluateModule(
|
|
852
|
+
moduleRecord,
|
|
853
|
+
evaluationMap,
|
|
854
|
+
) {
|
|
711
855
|
const dependencyModuleRecords = await moduleRecord.dependencyRecords;
|
|
712
856
|
if (dependencyModuleRecords.length > 0) {
|
|
713
857
|
evaluationMap[moduleRecord.id] = true;
|
|
714
858
|
// evaluate dependencies first
|
|
715
859
|
await this.evaluateModuleDependencies(dependencyModuleRecords, evaluationMap);
|
|
716
860
|
}
|
|
861
|
+
|
|
717
862
|
const { exporter, dependencies } = await moduleRecord.instantiation;
|
|
718
863
|
// The exports object automatically gets filled in by the exporter evaluation
|
|
719
864
|
const exports = {};
|
|
720
|
-
const depsMapped = await Promise.all(
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
865
|
+
const depsMapped = await Promise.all(
|
|
866
|
+
dependencies.map(async (dep) => {
|
|
867
|
+
if (dep === 'exports') {
|
|
868
|
+
return exports;
|
|
869
|
+
}
|
|
870
|
+
const resolvedDepId = await this.resolve(dep);
|
|
871
|
+
|
|
872
|
+
const moduleRecord = this.moduleRegistry.get(resolvedDepId) ;
|
|
873
|
+
if (!moduleRecord) {
|
|
874
|
+
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const module = moduleRecord.module;
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Circular dependencies are handled properly when named exports are used,
|
|
881
|
+
* however, for default exports there is a bug: https://github.com/rollup/rollup/issues/3384
|
|
882
|
+
*
|
|
883
|
+
* The workaround below applies for circular dependencies (!moduleRecord.evaluated)
|
|
884
|
+
*/
|
|
885
|
+
if (!moduleRecord.evaluated) {
|
|
886
|
+
return this.getCircularDependencyWrapper(module);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (module) {
|
|
890
|
+
return module.__defaultInterop ? module.default : module;
|
|
891
|
+
}
|
|
892
|
+
|
|
727
893
|
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
* Circular dependencies are handled properly when named exports are used,
|
|
732
|
-
* however, for default exports there is a bug: https://github.com/rollup/rollup/issues/3384
|
|
733
|
-
*
|
|
734
|
-
* The workaround below applies for circular dependencies (!moduleRecord.evaluated)
|
|
735
|
-
*/
|
|
736
|
-
if (!moduleRecord.evaluated) {
|
|
737
|
-
return this.getCircularDependencyWrapper(module);
|
|
738
|
-
}
|
|
739
|
-
if (module) {
|
|
740
|
-
return module.__defaultInterop ? module.default : module;
|
|
741
|
-
}
|
|
742
|
-
throw new LoaderError(FAILED_DEP, [resolvedDepId]);
|
|
743
|
-
}));
|
|
894
|
+
}),
|
|
895
|
+
);
|
|
896
|
+
|
|
744
897
|
// 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
|
|
745
898
|
if (moduleRecord.evaluated) {
|
|
746
899
|
return moduleRecord.module;
|
|
747
900
|
}
|
|
901
|
+
|
|
748
902
|
// evaluates the module function
|
|
749
903
|
let moduleDefault = exporter(...depsMapped);
|
|
904
|
+
|
|
750
905
|
// value is returned from exporter, then we are not using named exports
|
|
751
906
|
if (moduleDefault !== undefined) {
|
|
752
907
|
moduleDefault = { default: moduleDefault };
|
|
@@ -762,7 +917,9 @@ class ModuleRegistry {
|
|
|
762
917
|
Object.defineProperty(exports, '__useDefault', { value: true });
|
|
763
918
|
}
|
|
764
919
|
}
|
|
920
|
+
|
|
765
921
|
const moduleExports = moduleDefault || exports;
|
|
922
|
+
|
|
766
923
|
// update the module record
|
|
767
924
|
// copy over enumerable public methods to module
|
|
768
925
|
for (const key in moduleExports) {
|
|
@@ -776,6 +933,7 @@ class ModuleRegistry {
|
|
|
776
933
|
},
|
|
777
934
|
});
|
|
778
935
|
}
|
|
936
|
+
|
|
779
937
|
// copy non-enumerable to module
|
|
780
938
|
if (moduleExports.__useDefault) {
|
|
781
939
|
Object.defineProperty(moduleRecord.module, '__useDefault', { value: true });
|
|
@@ -786,27 +944,36 @@ class ModuleRegistry {
|
|
|
786
944
|
if (moduleExports.__esModule) {
|
|
787
945
|
Object.defineProperty(moduleRecord.module, '__esModule', { value: true });
|
|
788
946
|
}
|
|
947
|
+
|
|
789
948
|
moduleRecord.evaluated = true;
|
|
790
949
|
Object.freeze(moduleRecord.module);
|
|
791
950
|
return moduleRecord.module;
|
|
792
951
|
}
|
|
952
|
+
|
|
793
953
|
// Determines if named exports module has only default export
|
|
794
|
-
|
|
795
|
-
return (
|
|
954
|
+
isNamedExportDefaultOnly(exports) {
|
|
955
|
+
return (
|
|
956
|
+
exports !== undefined &&
|
|
796
957
|
Object.getOwnPropertyNames(exports).length === 2 &&
|
|
797
958
|
Object.prototype.hasOwnProperty.call(exports, 'default') &&
|
|
798
|
-
Object.prototype.hasOwnProperty.call(exports, '__esModule')
|
|
959
|
+
Object.prototype.hasOwnProperty.call(exports, '__esModule')
|
|
960
|
+
);
|
|
799
961
|
}
|
|
962
|
+
|
|
800
963
|
// Wrap the dependency in a function that can be called and detected by __circular__ property.
|
|
801
964
|
// The LWC engine checks for __circular__ to detect circular dependencies.
|
|
802
|
-
|
|
965
|
+
getCircularDependencyWrapper(module) {
|
|
803
966
|
const tmp = () => {
|
|
804
967
|
return module.__useDefault || module.__defaultInterop ? module.default : module;
|
|
805
968
|
};
|
|
806
969
|
tmp.__circular__ = true;
|
|
807
970
|
return tmp;
|
|
808
971
|
}
|
|
809
|
-
|
|
972
|
+
|
|
973
|
+
async evaluateModuleDependencies(
|
|
974
|
+
dependencyModuleRecords,
|
|
975
|
+
evaluationMap,
|
|
976
|
+
) {
|
|
810
977
|
for (let i = 0; i < dependencyModuleRecords.length; i++) {
|
|
811
978
|
const depRecord = dependencyModuleRecords[i];
|
|
812
979
|
if (!depRecord.evaluated && !evaluationMap[depRecord.id]) {
|
|
@@ -816,15 +983,17 @@ class ModuleRegistry {
|
|
|
816
983
|
}
|
|
817
984
|
}
|
|
818
985
|
}
|
|
819
|
-
|
|
986
|
+
|
|
987
|
+
async getModuleDef(resolvedId, originalId) {
|
|
820
988
|
// reset lastDefine
|
|
821
989
|
this.lastDefine = undefined;
|
|
990
|
+
|
|
822
991
|
// the module name can be the resolved ID or the original ID if neither are URL's.
|
|
823
992
|
const moduleName = !isUrl(resolvedId)
|
|
824
993
|
? resolvedId
|
|
825
994
|
: originalId !== resolvedId
|
|
826
|
-
|
|
827
|
-
|
|
995
|
+
? originalId
|
|
996
|
+
: undefined;
|
|
828
997
|
let moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
|
|
829
998
|
if (moduleDef && moduleDef.external) {
|
|
830
999
|
return moduleDef.external.moduleDefPromise;
|
|
@@ -837,76 +1006,84 @@ class ModuleRegistry {
|
|
|
837
1006
|
this.profiler.logOperationStart({ id: MODULE_FETCH, specifier });
|
|
838
1007
|
return Promise.resolve()
|
|
839
1008
|
.then(async () => {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1009
|
+
const loadHooks = this.loadHook;
|
|
1010
|
+
if (loadHooks) {
|
|
1011
|
+
for (let i = 0; i < loadHooks.length; i++) {
|
|
1012
|
+
const loadHook = loadHooks[i];
|
|
1013
|
+
const response = loadHook(resolvedId, parentUrl);
|
|
1014
|
+
const result = (
|
|
1015
|
+
isResponseAPromise(response)
|
|
1016
|
+
? // eslint-disable-next-line no-await-in-loop
|
|
1017
|
+
await evaluateLoadHook(resolvedId, response)
|
|
1018
|
+
: response
|
|
1019
|
+
) ;
|
|
1020
|
+
if (result === undefined) {
|
|
1021
|
+
throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
|
|
1022
|
+
}
|
|
1023
|
+
if (result && result !== null) {
|
|
1024
|
+
return evaluateLoadHookResponse(result, resolvedId);
|
|
1025
|
+
}
|
|
854
1026
|
}
|
|
855
1027
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
})
|
|
1028
|
+
return false;
|
|
1029
|
+
})
|
|
859
1030
|
.then((result) => {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1031
|
+
if (result !== true && hasDocument) {
|
|
1032
|
+
return loadModuleDef(resolvedId);
|
|
1033
|
+
}
|
|
1034
|
+
})
|
|
864
1035
|
.then(() => {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
moduleDef
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1036
|
+
// Attempt to retrieve the module definition by name first
|
|
1037
|
+
moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
|
|
1038
|
+
|
|
1039
|
+
// Fallback to the last loader.define call
|
|
1040
|
+
if (!moduleDef) {
|
|
1041
|
+
moduleDef = this.lastDefine;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// This should not happen
|
|
1045
|
+
if (!moduleDef) {
|
|
1046
|
+
throw new LoaderError(FAIL_INSTANTIATE, [resolvedId]);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
this.profiler.logOperationEnd({ id: MODULE_FETCH, specifier });
|
|
1050
|
+
return moduleDef;
|
|
1051
|
+
})
|
|
878
1052
|
.catch((e) => {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1053
|
+
this.profiler.logOperationStart({ id: MODULE_ERROR, specifier });
|
|
1054
|
+
throw e;
|
|
1055
|
+
});
|
|
882
1056
|
}
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
883
1060
|
addLoaderPlugin(hooks) {
|
|
884
1061
|
if (typeof hooks !== 'object') {
|
|
885
1062
|
throw new LoaderError(INVALID_HOOK);
|
|
886
1063
|
}
|
|
887
1064
|
const { loadModule: loadHook, resolveModule: resolveHook } = hooks;
|
|
1065
|
+
|
|
888
1066
|
if (resolveHook) {
|
|
889
1067
|
if (this.resolveHook) {
|
|
890
1068
|
this.resolveHook.push(resolveHook);
|
|
891
|
-
}
|
|
892
|
-
else {
|
|
1069
|
+
} else {
|
|
893
1070
|
this.resolveHook = [resolveHook];
|
|
894
1071
|
}
|
|
895
1072
|
}
|
|
896
1073
|
if (loadHook) {
|
|
897
1074
|
if (this.loadHook) {
|
|
898
1075
|
this.loadHook.push(loadHook);
|
|
899
|
-
}
|
|
900
|
-
else {
|
|
1076
|
+
} else {
|
|
901
1077
|
this.loadHook = [loadHook];
|
|
902
1078
|
}
|
|
903
1079
|
}
|
|
904
1080
|
}
|
|
1081
|
+
|
|
1082
|
+
|
|
905
1083
|
registerHandleStaleModuleHook(handleStaleModule) {
|
|
906
1084
|
if (this.handleStaleModuleHook) {
|
|
907
1085
|
this.handleStaleModuleHook.push(handleStaleModule);
|
|
908
|
-
}
|
|
909
|
-
else {
|
|
1086
|
+
} else {
|
|
910
1087
|
this.handleStaleModuleHook = [handleStaleModule];
|
|
911
1088
|
}
|
|
912
1089
|
}
|
|
@@ -938,6 +1115,19 @@ function targetWarning(match, target, msg) {
|
|
|
938
1115
|
*
|
|
939
1116
|
* This implementation is adapted from https://github.com/systemjs/systemjs/blob/master/src/features/import-map.js
|
|
940
1117
|
*/
|
|
1118
|
+
|
|
1119
|
+
// Spec based import map object https://github.com/WICG/import-maps
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
|
|
941
1131
|
// Resolves an import map package entry
|
|
942
1132
|
function applyPackages(id, packages, defaultUri) {
|
|
943
1133
|
const pkgName = getMatch(id, packages);
|
|
@@ -948,9 +1138,9 @@ function applyPackages(id, packages, defaultUri) {
|
|
|
948
1138
|
}
|
|
949
1139
|
if (id.length > pkgName.length && pkg[pkg.length - 1] !== '/') {
|
|
950
1140
|
targetWarning(pkgName, pkg, "should have a trailing '/'");
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
|
|
1141
|
+
} else {
|
|
1142
|
+
const isPackage =
|
|
1143
|
+
id.length > pkgName.length &&
|
|
954
1144
|
pkg[pkg.length - 1] === '/' &&
|
|
955
1145
|
pkg.lastIndexOf(pkgName) === pkg.length - pkgName.length;
|
|
956
1146
|
if (isPackage) {
|
|
@@ -959,8 +1149,7 @@ function applyPackages(id, packages, defaultUri) {
|
|
|
959
1149
|
}
|
|
960
1150
|
return pkg + id.slice(pkgName.length);
|
|
961
1151
|
}
|
|
962
|
-
}
|
|
963
|
-
else if (defaultUri) {
|
|
1152
|
+
} else if (defaultUri) {
|
|
964
1153
|
// When a specifier's URI cannot be resolved via the imports, fallback to "default".
|
|
965
1154
|
// -> https://rfcs.lwc.dev/rfcs/lwr/0000-import-metadata#json-schema
|
|
966
1155
|
// However, if `id` is already a fully resolved url,
|
|
@@ -971,8 +1160,13 @@ function applyPackages(id, packages, defaultUri) {
|
|
|
971
1160
|
}
|
|
972
1161
|
}
|
|
973
1162
|
}
|
|
1163
|
+
|
|
974
1164
|
// Resolves an entry in the import map
|
|
975
|
-
function resolveImportMapEntry(
|
|
1165
|
+
function resolveImportMapEntry(
|
|
1166
|
+
importMap,
|
|
1167
|
+
resolvedOrPlain,
|
|
1168
|
+
parentUrl,
|
|
1169
|
+
) {
|
|
976
1170
|
if (!importMap.scopes) {
|
|
977
1171
|
importMap.scopes = {};
|
|
978
1172
|
}
|
|
@@ -988,12 +1182,21 @@ function resolveImportMapEntry(importMap, resolvedOrPlain, parentUrl) {
|
|
|
988
1182
|
}
|
|
989
1183
|
scopeUrl = getMatch(scopeUrl.slice(0, scopeUrl.lastIndexOf('/')), scopes);
|
|
990
1184
|
}
|
|
991
|
-
return (
|
|
1185
|
+
return (
|
|
1186
|
+
applyPackages(resolvedOrPlain, importMap.imports, importMap.default) ||
|
|
992
1187
|
(isUrl(resolvedOrPlain) && resolvedOrPlain) ||
|
|
993
|
-
undefined
|
|
1188
|
+
undefined
|
|
1189
|
+
);
|
|
994
1190
|
}
|
|
1191
|
+
|
|
995
1192
|
// In place transformation of the ImportMap object
|
|
996
|
-
function resolveAndComposePackages(
|
|
1193
|
+
function resolveAndComposePackages(
|
|
1194
|
+
packages,
|
|
1195
|
+
outPackages,
|
|
1196
|
+
baseUrl,
|
|
1197
|
+
parentMap,
|
|
1198
|
+
parentUrl,
|
|
1199
|
+
) {
|
|
997
1200
|
for (const p in packages) {
|
|
998
1201
|
const resolvedLhs = resolveIfNotPlainOrUrl(p, baseUrl) || p;
|
|
999
1202
|
const rhs = packages[p];
|
|
@@ -1001,42 +1204,62 @@ function resolveAndComposePackages(packages, outPackages, baseUrl, parentMap, pa
|
|
|
1001
1204
|
if (typeof rhs !== 'string') {
|
|
1002
1205
|
continue;
|
|
1003
1206
|
}
|
|
1004
|
-
const mapped = resolveImportMapEntry(
|
|
1207
|
+
const mapped = resolveImportMapEntry(
|
|
1208
|
+
parentMap,
|
|
1209
|
+
resolveIfNotPlainOrUrl(rhs, baseUrl) || rhs,
|
|
1210
|
+
parentUrl,
|
|
1211
|
+
);
|
|
1005
1212
|
if (!mapped) {
|
|
1006
1213
|
targetWarning(p, rhs, 'bare specifier did not resolve');
|
|
1007
|
-
}
|
|
1008
|
-
else {
|
|
1214
|
+
} else {
|
|
1009
1215
|
outPackages[resolvedLhs] = mapped;
|
|
1010
1216
|
}
|
|
1011
1217
|
}
|
|
1012
1218
|
}
|
|
1219
|
+
|
|
1013
1220
|
// Composes a single import map object given a child and parent import map
|
|
1014
|
-
function resolveAndComposeImportMap(
|
|
1221
|
+
function resolveAndComposeImportMap(
|
|
1222
|
+
json,
|
|
1223
|
+
baseUrl,
|
|
1224
|
+
parentMap = { imports: {}, scopes: {} },
|
|
1225
|
+
) {
|
|
1015
1226
|
const outMap = {
|
|
1016
1227
|
imports: Object.assign({}, parentMap.imports),
|
|
1017
1228
|
scopes: Object.assign({}, parentMap.scopes),
|
|
1018
1229
|
default: json.default,
|
|
1019
1230
|
};
|
|
1231
|
+
|
|
1020
1232
|
if (json.imports) {
|
|
1021
1233
|
resolveAndComposePackages(json.imports, outMap.imports, baseUrl, parentMap);
|
|
1022
1234
|
}
|
|
1235
|
+
|
|
1023
1236
|
if (json.scopes) {
|
|
1024
1237
|
for (const s in json.scopes) {
|
|
1025
1238
|
const resolvedScope = resolveUrl(s, baseUrl);
|
|
1026
|
-
resolveAndComposePackages(
|
|
1239
|
+
resolveAndComposePackages(
|
|
1240
|
+
json.scopes[s],
|
|
1241
|
+
outMap.scopes[resolvedScope] || (outMap.scopes[resolvedScope] = {}),
|
|
1242
|
+
baseUrl,
|
|
1243
|
+
parentMap,
|
|
1244
|
+
resolvedScope,
|
|
1245
|
+
);
|
|
1027
1246
|
}
|
|
1028
1247
|
}
|
|
1248
|
+
|
|
1029
1249
|
if (json.default) {
|
|
1030
1250
|
outMap.default = resolveIfNotPlainOrUrl(json.default, baseUrl);
|
|
1031
1251
|
}
|
|
1252
|
+
|
|
1032
1253
|
return outMap;
|
|
1033
1254
|
}
|
|
1034
1255
|
|
|
1035
1256
|
/* spec based import map resolver */
|
|
1036
|
-
class ImportMapResolver
|
|
1257
|
+
class ImportMapResolver {
|
|
1258
|
+
|
|
1037
1259
|
constructor(importMap) {
|
|
1038
1260
|
this.importMap = importMap;
|
|
1039
1261
|
}
|
|
1262
|
+
|
|
1040
1263
|
resolve(resolvedOrPlain, parentUrl) {
|
|
1041
1264
|
return resolveImportMapEntry(this.importMap, resolvedOrPlain, parentUrl);
|
|
1042
1265
|
}
|
|
@@ -1047,26 +1270,33 @@ class ImportMapResolver {
|
|
|
1047
1270
|
*
|
|
1048
1271
|
* This implementation is adapted from https://github.com/systemjs/systemjs/blob/master/src/features/import-map.js
|
|
1049
1272
|
*/
|
|
1273
|
+
|
|
1050
1274
|
const IMPORTMAP_SCRIPT_TYPE = 'lwr-importmap';
|
|
1275
|
+
|
|
1051
1276
|
// iterates on the any <script type="${IMPORTMAP_SCRIPT_TYPE}", invoking the given callback for each
|
|
1052
|
-
function iterateDocumentImportMaps(
|
|
1277
|
+
function iterateDocumentImportMaps(
|
|
1278
|
+
callBack,
|
|
1279
|
+
extraSelector,
|
|
1280
|
+
) {
|
|
1053
1281
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
1054
1282
|
const nodeList = document.querySelectorAll(`script[type="${IMPORTMAP_SCRIPT_TYPE}"]` + extraSelector);
|
|
1055
1283
|
const filtered = Array.from(nodeList).filter((node) => {
|
|
1056
|
-
if (node.src) {
|
|
1284
|
+
if ((node ).src) {
|
|
1057
1285
|
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
1058
|
-
if (hasConsole)
|
|
1059
|
-
console.warn('LWR does not support import maps from script src');
|
|
1286
|
+
if (hasConsole) console.warn('LWR does not support import maps from script src');
|
|
1060
1287
|
return false;
|
|
1061
1288
|
}
|
|
1062
1289
|
return true;
|
|
1063
1290
|
});
|
|
1291
|
+
|
|
1064
1292
|
Array.prototype.forEach.call(filtered, callBack);
|
|
1065
1293
|
}
|
|
1294
|
+
|
|
1066
1295
|
// retrives the import map text from a <script type="${IMPORTMAP_SCRIPT_TYPE}"
|
|
1067
1296
|
async function getImportMapFromScript(script) {
|
|
1068
1297
|
return Promise.resolve(script.innerHTML);
|
|
1069
1298
|
}
|
|
1299
|
+
|
|
1070
1300
|
// get importMap from <script type="lwr-importmap">
|
|
1071
1301
|
async function evaluateImportMaps(baseUrl) {
|
|
1072
1302
|
let importMap = { imports: {}, scopes: {} };
|
|
@@ -1078,23 +1308,27 @@ async function evaluateImportMaps(baseUrl) {
|
|
|
1078
1308
|
if (!baseUrl) {
|
|
1079
1309
|
throw new LoaderError(NO_BASE_URL);
|
|
1080
1310
|
}
|
|
1311
|
+
|
|
1081
1312
|
iterateDocumentImportMaps((script) => {
|
|
1082
1313
|
importMapPromise = importMapPromise
|
|
1083
1314
|
.then(() => {
|
|
1084
|
-
|
|
1085
|
-
|
|
1315
|
+
return getImportMapFromScript(script);
|
|
1316
|
+
})
|
|
1086
1317
|
.then((importMapTxt) => {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}
|
|
1093
|
-
})
|
|
1318
|
+
try {
|
|
1319
|
+
return JSON.parse(importMapTxt);
|
|
1320
|
+
} catch (e) {
|
|
1321
|
+
throw new LoaderError(BAD_IMPORT_MAP);
|
|
1322
|
+
}
|
|
1323
|
+
})
|
|
1094
1324
|
.then((jsonImportMap) => {
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1325
|
+
importMap = resolveAndComposeImportMap(
|
|
1326
|
+
jsonImportMap,
|
|
1327
|
+
script.src || (baseUrl ),
|
|
1328
|
+
importMap,
|
|
1329
|
+
);
|
|
1330
|
+
return importMap;
|
|
1331
|
+
});
|
|
1098
1332
|
}, '');
|
|
1099
1333
|
}
|
|
1100
1334
|
return importMapPromise;
|
|
@@ -1104,6 +1338,10 @@ async function evaluateImportMaps(baseUrl) {
|
|
|
1104
1338
|
* The LWR loader is inspired and borrows from the algorithms and native browser principles of https://github.com/systemjs/systemjs
|
|
1105
1339
|
*/
|
|
1106
1340
|
class Loader {
|
|
1341
|
+
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
|
|
1107
1345
|
constructor(config) {
|
|
1108
1346
|
config = config || {};
|
|
1109
1347
|
let baseUrl = config.baseUrl;
|
|
@@ -1119,6 +1357,7 @@ class Loader {
|
|
|
1119
1357
|
throw new LoaderError(NO_BASE_URL);
|
|
1120
1358
|
}
|
|
1121
1359
|
this.baseUrl = baseUrl;
|
|
1360
|
+
|
|
1122
1361
|
if (!profiler) {
|
|
1123
1362
|
// default noop profiler
|
|
1124
1363
|
profiler = {
|
|
@@ -1130,7 +1369,9 @@ class Loader {
|
|
|
1130
1369
|
},
|
|
1131
1370
|
};
|
|
1132
1371
|
}
|
|
1372
|
+
|
|
1133
1373
|
this.registry = new ModuleRegistry({ baseUrl, profiler });
|
|
1374
|
+
|
|
1134
1375
|
// TODO: https://github.com/salesforce-experience-platform-emu/lwr/issues/1087
|
|
1135
1376
|
this.services = Object.freeze({
|
|
1136
1377
|
addLoaderPlugin: this.registry.addLoaderPlugin.bind(this.registry),
|
|
@@ -1138,6 +1379,7 @@ class Loader {
|
|
|
1138
1379
|
appMetadata: config.appMetadata,
|
|
1139
1380
|
});
|
|
1140
1381
|
}
|
|
1382
|
+
|
|
1141
1383
|
/**
|
|
1142
1384
|
* Defines/registers a single named AMD module definition.
|
|
1143
1385
|
*
|
|
@@ -1147,21 +1389,31 @@ class Loader {
|
|
|
1147
1389
|
* @param {ModuleDefinitionSignatures} signatures Object containing the module signature and the signatures of its dependencies
|
|
1148
1390
|
* @return {void}
|
|
1149
1391
|
*/
|
|
1150
|
-
define(
|
|
1392
|
+
define(
|
|
1393
|
+
name,
|
|
1394
|
+
dependencies,
|
|
1395
|
+
execute,
|
|
1396
|
+
signatures,
|
|
1397
|
+
) {
|
|
1151
1398
|
invariant(typeof name === 'string', MISSING_NAME);
|
|
1152
1399
|
let ctor = execute;
|
|
1153
1400
|
let deps = dependencies;
|
|
1154
1401
|
let sigs = signatures;
|
|
1402
|
+
|
|
1155
1403
|
// Convert no dependencies form `define('name', function(){}, {});` to: `define('name', [], function(){}, {})`
|
|
1156
1404
|
if (typeof deps === 'function') {
|
|
1157
1405
|
ctor = dependencies;
|
|
1158
1406
|
deps = [];
|
|
1159
1407
|
sigs = execute;
|
|
1160
1408
|
}
|
|
1409
|
+
|
|
1161
1410
|
sigs = sigs || {};
|
|
1411
|
+
|
|
1162
1412
|
invariant(Array.isArray(deps), INVALID_DEPS);
|
|
1163
|
-
|
|
1413
|
+
|
|
1414
|
+
this.registry.define(name, deps, ctor , sigs );
|
|
1164
1415
|
}
|
|
1416
|
+
|
|
1165
1417
|
/**
|
|
1166
1418
|
* Retrieves/loads a module, returning it from the registry if it exists and fetching it if it doesn't.
|
|
1167
1419
|
*
|
|
@@ -1173,6 +1425,7 @@ class Loader {
|
|
|
1173
1425
|
async load(id, importer) {
|
|
1174
1426
|
return this.registry.load(id, importer);
|
|
1175
1427
|
}
|
|
1428
|
+
|
|
1176
1429
|
/**
|
|
1177
1430
|
* 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).
|
|
1178
1431
|
*
|
|
@@ -1182,6 +1435,7 @@ class Loader {
|
|
|
1182
1435
|
has(id) {
|
|
1183
1436
|
return this.registry.has(id);
|
|
1184
1437
|
}
|
|
1438
|
+
|
|
1185
1439
|
/**
|
|
1186
1440
|
* Resolves the module identifier or URL. Returns the module identifier if the moduleDefinition exists, or the full resolved URL if a URL is given.
|
|
1187
1441
|
*
|
|
@@ -1193,13 +1447,14 @@ class Loader {
|
|
|
1193
1447
|
async resolve(id, importer) {
|
|
1194
1448
|
return this.registry.resolve(id, importer);
|
|
1195
1449
|
}
|
|
1450
|
+
|
|
1451
|
+
|
|
1196
1452
|
async registerImportMappings(mappings) {
|
|
1197
1453
|
let importMap;
|
|
1198
1454
|
if (!mappings) {
|
|
1199
1455
|
// If no mappings given, check for lwr-importmap on the document
|
|
1200
1456
|
importMap = await evaluateImportMaps(this.baseUrl);
|
|
1201
|
-
}
|
|
1202
|
-
else {
|
|
1457
|
+
} else {
|
|
1203
1458
|
// merge the new mappings with the base import map - note this goes against
|
|
1204
1459
|
// import maps spec if we do this after resolving any imports
|
|
1205
1460
|
importMap = resolveAndComposeImportMap(mappings, this.baseUrl, this.parentImportMap);
|
|
@@ -1210,6 +1465,7 @@ class Loader {
|
|
|
1210
1465
|
this.registry.setImportResolver(importMapResolver);
|
|
1211
1466
|
}
|
|
1212
1467
|
}
|
|
1468
|
+
|
|
1213
1469
|
/**
|
|
1214
1470
|
* Marks modules as "externally" loaded/provided (e.g. preloaded), so that the loader does not attempt to load them.
|
|
1215
1471
|
*
|