@lwrjs/loader 0.6.0-alpha.1 → 0.6.0-alpha.13
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/README.md +6 -4
- package/build/__tests__/shim/browser/test_server.js +2 -1
- package/build/__tests__/shim-legacy/browser/test_server.js +2 -1
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.js +36 -10
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.min.js +2 -25
- package/build/assets/prod/lwr-loader-shim-legacy.js +24 -4
- package/build/assets/prod/lwr-loader-shim.bundle.js +336 -216
- package/build/assets/prod/lwr-loader-shim.bundle.min.js +2 -25
- package/build/assets/prod/lwr-loader-shim.js +289 -210
- package/build/bundle/prod/lwr/esmLoader/esmLoader.js +1 -1
- package/build/cjs/modules/lwr/esmLoader/esmLoader.cjs +14 -5
- package/build/cjs/modules/lwr/loader/moduleRegistry/importMetadataResolver.cjs +4 -0
- package/build/cjs/modules/lwr/loader/moduleRegistry/moduleRegistry.cjs +16 -3
- package/build/cjs/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.cjs +8 -2
- package/build/modules/lwr/esmLoader/esmLoader.js +17 -7
- package/build/modules/lwr/loader/loader.js +47 -6
- package/build/modules/lwr/loaderLegacy/loaderLegacy.js +12 -6
- package/package.json +14 -8
|
@@ -4,228 +4,307 @@
|
|
|
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 Shim v0.6.0-alpha.
|
|
7
|
+
/* LWR Module Loader Shim v0.6.0-alpha.13 */
|
|
8
8
|
(function () {
|
|
9
|
-
|
|
9
|
+
'use strict';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
// Create a Loader instance
|
|
16
|
-
const exports = {};
|
|
17
|
-
definition[2].call(null, exports);
|
|
18
|
-
const { Loader } = exports;
|
|
19
|
-
const loader = new Loader(config);
|
|
20
|
-
if (externalModules && externalModules.length) {
|
|
21
|
-
loader.registerExternalModules(externalModules);
|
|
22
|
-
}
|
|
23
|
-
// Define the loader module with public API: { define, load, services }
|
|
24
|
-
const exporter = (exports) => {
|
|
25
|
-
Object.assign(exports, {
|
|
26
|
-
define: loader.define.bind(loader),
|
|
27
|
-
load: loader.load.bind(loader),
|
|
28
|
-
services: loader.services,
|
|
29
|
-
});
|
|
30
|
-
return;
|
|
31
|
-
};
|
|
32
|
-
loader.define(name, ['exports'], exporter);
|
|
33
|
-
return loader;
|
|
34
|
-
}
|
|
11
|
+
// Bootstrap / shim
|
|
12
|
+
const BOOTSTRAP_PREFIX = 'lwr.bootstrap.';
|
|
13
|
+
const BOOTSTRAP_ERROR = `${BOOTSTRAP_PREFIX}error`;
|
|
35
14
|
|
|
36
|
-
|
|
15
|
+
var Phase;
|
|
37
16
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
throw new Error('The customInit hook is required when autoBoot is false');
|
|
43
|
-
}
|
|
44
|
-
// If autoBoot === true, there must NOT be a customInit hook
|
|
45
|
-
if (autoBoot && customInit) {
|
|
46
|
-
throw new Error('The customInit hook must not be defined when autoBoot is true');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Process the customInit hook
|
|
50
|
-
function customInit(config, initializeApp, define, onBootstrapError) {
|
|
51
|
-
// Validate config
|
|
52
|
-
const { autoBoot, customInit } = config;
|
|
53
|
-
validatePreInit(autoBoot, customInit);
|
|
54
|
-
// Set up arguments and call the customInit hook, if available
|
|
55
|
-
if (customInit) {
|
|
56
|
-
const lwr = {
|
|
57
|
-
initializeApp,
|
|
58
|
-
define,
|
|
59
|
-
onBootstrapError,
|
|
60
|
-
};
|
|
61
|
-
customInit(lwr, config);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
17
|
+
(function (Phase) {
|
|
18
|
+
Phase[Phase["Start"] = 0] = "Start";
|
|
19
|
+
Phase[Phase["End"] = 1] = "End";
|
|
20
|
+
})(Phase || (Phase = {}));
|
|
64
21
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.errorHandler = e;
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
this.enterErrorState(e);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Return true if the app can be initialized
|
|
96
|
-
canInit() {
|
|
97
|
-
// Initialize the app if:
|
|
98
|
-
// - bootReady: autoBoot is on OR customInit has finished
|
|
99
|
-
// - all required modules are defined
|
|
100
|
-
const allDefined = this.config.requiredModules.every((m) => this.orderedDefs.includes(m));
|
|
101
|
-
return this.bootReady && allDefined;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Create a temporary LWR.define() function which captures all
|
|
105
|
-
* calls that occur BEFORE the full loader module is available
|
|
106
|
-
*
|
|
107
|
-
* Each call to LWR.define() is stored in 2 ways:
|
|
108
|
-
* - in a map as [moduleName, arguments] pairs
|
|
109
|
-
* - each moduleName is pushed onto an array, to preserve
|
|
110
|
-
* the order in which the modules were defined
|
|
111
|
-
*/
|
|
112
|
-
tempDefine(...args) {
|
|
113
|
-
// Cache the incoming module
|
|
114
|
-
const moduleName = args[0];
|
|
115
|
-
this.defineCache[moduleName] = args;
|
|
116
|
-
this.orderedDefs.push(moduleName);
|
|
117
|
-
if (this.canInit()) {
|
|
118
|
-
if (hasSetTimeout) {
|
|
119
|
-
// requiredModules are defined, clear watchdog timer
|
|
120
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
121
|
-
clearTimeout(this.watchdogTimerId);
|
|
122
|
-
}
|
|
123
|
-
this.initApp();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
// Called by the customInit hook via lwr.initializeApp()
|
|
127
|
-
postCustomInit() {
|
|
128
|
-
this.bootReady = true;
|
|
129
|
-
if (this.canInit()) {
|
|
130
|
-
this.initApp();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// Create the loader and initialize the application
|
|
134
|
-
initApp() {
|
|
135
|
-
try {
|
|
136
|
-
const loaderConfig = {
|
|
137
|
-
endpoints: this.config.endpoints,
|
|
138
|
-
baseUrl: this.config.baseUrl,
|
|
139
|
-
};
|
|
140
|
-
const loader = createLoader(this.loaderModule, this.defineCache[this.loaderModule], loaderConfig, this.config.preloadModules);
|
|
141
|
-
this.mountApp(loader);
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
this.enterErrorState(e);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
waitForDOMContentLoaded() {
|
|
148
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
149
|
-
if (typeof document === undefined) {
|
|
150
|
-
return Promise.resolve();
|
|
151
|
-
}
|
|
152
|
-
// Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
|
|
153
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
154
|
-
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
155
|
-
return Promise.resolve();
|
|
156
|
-
}
|
|
157
|
-
return new Promise((resolve) => {
|
|
158
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
159
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
160
|
-
resolve();
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
// Set up the application globals, import map, root custom element...
|
|
165
|
-
mountApp(loader) {
|
|
166
|
-
const { bootstrapModule, rootComponent, rootComponents, endpoints, imports, index } = this.config;
|
|
167
|
-
// Set global LWR.define to loader.define
|
|
168
|
-
this.global.LWR = Object.freeze({
|
|
169
|
-
define: loader.define.bind(loader),
|
|
170
|
-
rootComponent,
|
|
171
|
-
rootComponents,
|
|
172
|
-
endpoints,
|
|
173
|
-
imports: imports || {},
|
|
174
|
-
index: index || {},
|
|
175
|
-
});
|
|
176
|
-
// Redefine all modules in the temporary cache
|
|
177
|
-
this.orderedDefs.forEach((specifier) => {
|
|
178
|
-
if (specifier !== this.loaderModule) {
|
|
179
|
-
loader.define(...this.defineCache[specifier]);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
// by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
|
|
183
|
-
const { disableInitDefer } = this.config;
|
|
184
|
-
// Load the import mappings and application bootstrap module
|
|
185
|
-
loader
|
|
186
|
-
.registerImportMappings({ imports, index }, [bootstrapModule, rootComponent])
|
|
187
|
-
.then(() => {
|
|
188
|
-
if (!disableInitDefer) {
|
|
189
|
-
return this.waitForDOMContentLoaded();
|
|
190
|
-
}
|
|
191
|
-
})
|
|
192
|
-
.then(() => loader.load(bootstrapModule))
|
|
193
|
-
.catch((reason) => {
|
|
194
|
-
this.enterErrorState(new Error(`Application ${rootComponent} could not be loaded: ${reason}`));
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
// Trigger bootstrap error state, and call error handler if registered
|
|
198
|
-
enterErrorState(error) {
|
|
199
|
-
if (this.errorHandler) {
|
|
200
|
-
this.errorHandler(error);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
if (hasConsole) {
|
|
204
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
205
|
-
console.error(`An error occurred during LWR bootstrap. ${error.message}`, error.stack);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
// eslint-disable-next-line no-undef, lwr/no-unguarded-apis
|
|
210
|
-
startWatchdogTimer() {
|
|
211
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
212
|
-
return setTimeout(() => {
|
|
213
|
-
this.enterErrorState(new Error('Failed to load required modules - timed out'));
|
|
214
|
-
}, REQUIRED_MODULES_TIMEOUT);
|
|
215
|
-
}
|
|
22
|
+
// Attach a custom dispatcher
|
|
23
|
+
let customDispatcher;
|
|
24
|
+
function attachDispatcher(dispatcher) {
|
|
25
|
+
customDispatcher = dispatcher;
|
|
26
|
+
} // Check if the Performance API is available
|
|
27
|
+
// e.g. JSDom (used in Jest) doesn't implement these
|
|
28
|
+
|
|
29
|
+
const perf = globalThis.performance;
|
|
30
|
+
const isPerfSupported = typeof perf !== 'undefined' && typeof perf.mark === 'function' && typeof perf.clearMarks === 'function' && typeof perf.measure === 'function' && typeof perf.clearMeasures === 'function'; // For marking request metrics
|
|
31
|
+
// Fallback to the Performance API if there is no custom dispatcher
|
|
32
|
+
|
|
33
|
+
function logOperationStart({
|
|
34
|
+
id,
|
|
35
|
+
specifier
|
|
36
|
+
}) {
|
|
37
|
+
if (customDispatcher) {
|
|
38
|
+
customDispatcher({
|
|
39
|
+
id,
|
|
40
|
+
phase: Phase.Start,
|
|
41
|
+
specifier
|
|
42
|
+
});
|
|
43
|
+
} else if (isPerfSupported) {
|
|
44
|
+
perf.mark(id + (specifier ? `.${specifier}` : ''));
|
|
216
45
|
}
|
|
46
|
+
} // For measuring duration metrics
|
|
47
|
+
// Fallback to the Performance API if there is no custom dispatcher
|
|
48
|
+
|
|
49
|
+
/* istanbul ignore next */
|
|
217
50
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
51
|
+
function logOperationEnd({
|
|
52
|
+
id,
|
|
53
|
+
specifier
|
|
54
|
+
}) {
|
|
55
|
+
if (customDispatcher) {
|
|
56
|
+
customDispatcher({
|
|
57
|
+
id,
|
|
58
|
+
phase: Phase.End,
|
|
59
|
+
specifier
|
|
60
|
+
});
|
|
61
|
+
} else if (isPerfSupported) {
|
|
62
|
+
const suffix = specifier ? `.${specifier}` : '';
|
|
63
|
+
const markName = id + suffix;
|
|
64
|
+
const measureName = `${id}.duration${suffix}`;
|
|
65
|
+
perf.measure(measureName, markName); // Clear the created mark and measure to avoid filling the performance entry buffer
|
|
66
|
+
// Even if they get deleted, existing PerformanceObservers preserve copies of the entries
|
|
67
|
+
|
|
68
|
+
perf.clearMarks(markName);
|
|
69
|
+
perf.clearMeasures(measureName);
|
|
223
70
|
}
|
|
224
|
-
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createLoader(name, definition, config, externalModules) {
|
|
74
|
+
if (!definition || typeof definition[2] !== 'function') {
|
|
75
|
+
throw new Error(`Expected loader with specifier "${name}" to be a module`);
|
|
76
|
+
}
|
|
77
|
+
// Create a Loader instance
|
|
78
|
+
const exports = {};
|
|
79
|
+
definition[2].call(null, exports);
|
|
80
|
+
const { Loader } = exports;
|
|
81
|
+
const loader = new Loader(config);
|
|
82
|
+
if (externalModules && externalModules.length) {
|
|
83
|
+
loader.registerExternalModules(externalModules);
|
|
84
|
+
}
|
|
85
|
+
// Define the loader module with public API: { define, load, services }
|
|
86
|
+
const exporter = (exports) => {
|
|
87
|
+
Object.assign(exports, {
|
|
88
|
+
define: loader.define.bind(loader),
|
|
89
|
+
load: loader.load.bind(loader),
|
|
90
|
+
services: loader.services,
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
loader.define(name, ['exports'], exporter);
|
|
94
|
+
return loader;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const REQUIRED_MODULES_TIMEOUT = 300 * 1000;
|
|
98
|
+
|
|
99
|
+
// Check for errors with autoBoot and customInit
|
|
100
|
+
function validatePreInit(autoBoot, customInit) {
|
|
101
|
+
// If autoBoot === false, there must be a customInit hook
|
|
102
|
+
if (!autoBoot && !customInit) {
|
|
103
|
+
throw new Error('The customInit hook is required when autoBoot is false');
|
|
104
|
+
}
|
|
105
|
+
// If autoBoot === true, there must NOT be a customInit hook
|
|
106
|
+
if (autoBoot && customInit) {
|
|
107
|
+
throw new Error('The customInit hook must not be defined when autoBoot is true');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Process the customInit hook
|
|
111
|
+
function customInit(config, initializeApp, define, onBootstrapError) {
|
|
112
|
+
// Validate config
|
|
113
|
+
const { autoBoot, customInit } = config;
|
|
114
|
+
validatePreInit(autoBoot, customInit);
|
|
115
|
+
// Set up arguments and call the customInit hook, if available
|
|
116
|
+
if (customInit) {
|
|
117
|
+
const lwr = {
|
|
118
|
+
initializeApp,
|
|
119
|
+
define,
|
|
120
|
+
onBootstrapError,
|
|
121
|
+
attachDispatcher,
|
|
122
|
+
};
|
|
123
|
+
customInit(lwr, config);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* global document */
|
|
128
|
+
/* eslint-disable lwr/no-unguarded-apis */
|
|
129
|
+
const hasSetTimeout = typeof setTimeout === 'function';
|
|
130
|
+
const hasConsole = typeof console !== 'undefined';
|
|
131
|
+
/* eslint-enable lwr/no-unguarded-apis */
|
|
132
|
+
class LoaderShim {
|
|
133
|
+
constructor(global) {
|
|
134
|
+
this.defineCache = {};
|
|
135
|
+
this.orderedDefs = [];
|
|
136
|
+
// Parse configuration
|
|
137
|
+
this.global = global;
|
|
138
|
+
this.config = global.LWR;
|
|
139
|
+
this.loaderSpecifier = 'lwr/loader/v/0_6_0-alpha_13';
|
|
140
|
+
// Set up the temporary LWR.define function and customInit hook
|
|
141
|
+
const tempDefine = this.tempDefine.bind(this);
|
|
142
|
+
global.LWR.define = tempDefine;
|
|
143
|
+
this.bootReady = this.config.autoBoot;
|
|
144
|
+
// Start watchdog timer
|
|
145
|
+
if (hasSetTimeout) {
|
|
146
|
+
this.watchdogTimerId = this.startWatchdogTimer();
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
customInit(Object.freeze(this.config), this.postCustomInit.bind(this), tempDefine, (e) => {
|
|
150
|
+
this.errorHandler = e;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
this.enterErrorState(e);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Return true if the app can be initialized
|
|
158
|
+
canInit() {
|
|
159
|
+
// Initialize the app if:
|
|
160
|
+
// - bootReady: autoBoot is on OR customInit has finished
|
|
161
|
+
// - all required modules are defined
|
|
162
|
+
const allDefined = this.config.requiredModules.every((m) => this.orderedDefs.includes(m));
|
|
163
|
+
return this.bootReady && allDefined;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Create a temporary LWR.define() function which captures all
|
|
167
|
+
* calls that occur BEFORE the full loader module is available
|
|
168
|
+
*
|
|
169
|
+
* Each call to LWR.define() is stored in 2 ways:
|
|
170
|
+
* - in a map as [moduleName, arguments] pairs
|
|
171
|
+
* - each moduleName is pushed onto an array, to preserve
|
|
172
|
+
* the order in which the modules were defined
|
|
173
|
+
*/
|
|
174
|
+
tempDefine(...args) {
|
|
175
|
+
// Cache the incoming module
|
|
176
|
+
const moduleName = args[0];
|
|
177
|
+
this.defineCache[moduleName] = args;
|
|
178
|
+
this.orderedDefs.push(moduleName);
|
|
179
|
+
if (this.canInit()) {
|
|
180
|
+
if (hasSetTimeout) {
|
|
181
|
+
// requiredModules are defined, clear watchdog timer
|
|
182
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
183
|
+
clearTimeout(this.watchdogTimerId);
|
|
184
|
+
}
|
|
185
|
+
this.initApp();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Called by the customInit hook via lwr.initializeApp()
|
|
189
|
+
postCustomInit() {
|
|
190
|
+
this.bootReady = true;
|
|
191
|
+
if (this.canInit()) {
|
|
192
|
+
this.initApp();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Create the loader and initialize the application
|
|
196
|
+
initApp() {
|
|
197
|
+
try {
|
|
198
|
+
const loaderConfig = {
|
|
199
|
+
endpoints: this.config.endpoints,
|
|
200
|
+
baseUrl: this.config.baseUrl,
|
|
201
|
+
profiler: { logOperationStart, logOperationEnd },
|
|
202
|
+
// TODO: can be removed following https://github.com/salesforce/lwr/issues/1087
|
|
203
|
+
appMetadata: {
|
|
204
|
+
bootstrapModule: this.config.bootstrapModule,
|
|
205
|
+
rootComponent: this.config.rootComponent,
|
|
206
|
+
rootComponents: this.config.rootComponents,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
const loader = createLoader(this.loaderSpecifier, this.defineCache[this.loaderSpecifier], loaderConfig, this.config.preloadModules);
|
|
210
|
+
this.createProfilerModule(loader);
|
|
211
|
+
this.mountApp(loader);
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
this.enterErrorState(e);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
waitForDOMContentLoaded() {
|
|
218
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
219
|
+
if (typeof document === undefined) {
|
|
220
|
+
return Promise.resolve();
|
|
221
|
+
}
|
|
222
|
+
// Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
|
|
223
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
224
|
+
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
225
|
+
return Promise.resolve();
|
|
226
|
+
}
|
|
227
|
+
return new Promise((resolve) => {
|
|
228
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
229
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
230
|
+
resolve();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
// Create a module out of the profiler
|
|
235
|
+
// Note: The profiler is also available as a module through lwc module resolution (see package.json)
|
|
236
|
+
createProfilerModule(loader) {
|
|
237
|
+
const exporter = (exports) => {
|
|
238
|
+
Object.assign(exports, { logOperationStart, logOperationEnd });
|
|
239
|
+
};
|
|
240
|
+
loader.define('lwr/profiler/v/0_6_0-alpha_13', ['exports'], exporter);
|
|
241
|
+
}
|
|
242
|
+
// Set up the application globals, import map, root custom element...
|
|
243
|
+
mountApp(loader) {
|
|
244
|
+
const { bootstrapModule, rootComponent, rootComponents, endpoints, imports, index } = this.config;
|
|
245
|
+
// Set global LWR.define to loader.define
|
|
246
|
+
this.global.LWR = Object.freeze({
|
|
247
|
+
define: loader.define.bind(loader),
|
|
248
|
+
rootComponent,
|
|
249
|
+
rootComponents,
|
|
250
|
+
endpoints,
|
|
251
|
+
imports: imports || {},
|
|
252
|
+
index: index || {},
|
|
253
|
+
});
|
|
254
|
+
// Redefine all modules in the temporary cache
|
|
255
|
+
this.orderedDefs.forEach((specifier) => {
|
|
256
|
+
if (specifier !== this.loaderSpecifier) {
|
|
257
|
+
loader.define(...this.defineCache[specifier]);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
// by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
|
|
261
|
+
const { disableInitDefer } = this.config;
|
|
262
|
+
// Load the import mappings and application bootstrap module
|
|
263
|
+
loader
|
|
264
|
+
.registerImportMappings({ imports, index }, [bootstrapModule, rootComponent])
|
|
265
|
+
.then(() => {
|
|
266
|
+
if (!disableInitDefer) {
|
|
267
|
+
return this.waitForDOMContentLoaded();
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
.then(() => loader.load(bootstrapModule))
|
|
271
|
+
.catch((reason) => {
|
|
272
|
+
this.enterErrorState(new Error(`Application ${rootComponent} could not be loaded: ${reason}`));
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
// Trigger bootstrap error state, and call error handler if registered
|
|
276
|
+
enterErrorState(error) {
|
|
277
|
+
logOperationStart({ id: BOOTSTRAP_ERROR });
|
|
278
|
+
if (this.errorHandler) {
|
|
279
|
+
this.errorHandler(error);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
if (hasConsole) {
|
|
283
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
284
|
+
console.error(`An error occurred during LWR bootstrap. ${error.message}`, error.stack);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// eslint-disable-next-line no-undef, lwr/no-unguarded-apis
|
|
289
|
+
startWatchdogTimer() {
|
|
290
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
291
|
+
return setTimeout(() => {
|
|
292
|
+
this.enterErrorState(new Error('Failed to load required modules - timed out'));
|
|
293
|
+
}, REQUIRED_MODULES_TIMEOUT);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// The loader module is ALWAYS required
|
|
298
|
+
const GLOBAL = globalThis;
|
|
299
|
+
GLOBAL.LWR.requiredModules = GLOBAL.LWR.requiredModules || [];
|
|
300
|
+
if (GLOBAL.LWR.requiredModules.indexOf('lwr/loader/v/0_6_0-alpha_13') < 0) {
|
|
301
|
+
GLOBAL.LWR.requiredModules.push('lwr/loader/v/0_6_0-alpha_13');
|
|
302
|
+
}
|
|
303
|
+
new LoaderShim(GLOBAL);
|
|
225
304
|
|
|
226
305
|
}());
|
|
227
306
|
|
|
228
|
-
LWR.define('lwr/loader/v/0_6_0-
|
|
307
|
+
LWR.define('lwr/loader/v/0_6_0-alpha_13', ['exports'], function (exports) { 'use strict';
|
|
229
308
|
|
|
230
309
|
const templateRegex = /\{([0-9]+)\}/g;
|
|
231
310
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -522,6 +601,16 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
522
601
|
});
|
|
523
602
|
}
|
|
524
603
|
|
|
604
|
+
// Bootstrap / shim
|
|
605
|
+
|
|
606
|
+
const LOADER_PREFIX = 'lwr.loader.';
|
|
607
|
+
const MODULE_DEFINE = `${LOADER_PREFIX}module.define`;
|
|
608
|
+
const MODULE_FETCH = `${LOADER_PREFIX}module.fetch`;
|
|
609
|
+
const MODULE_ERROR = `${LOADER_PREFIX}module.error`; // Loader: mappings
|
|
610
|
+
|
|
611
|
+
const MAPPINGS_FETCH = `${LOADER_PREFIX}mappings.fetch`;
|
|
612
|
+
const MAPPINGS_ERROR = `${LOADER_PREFIX}mappings.error`;
|
|
613
|
+
|
|
525
614
|
/* spec based import map resolver */
|
|
526
615
|
class ImportMetadataResolver {
|
|
527
616
|
constructor(config, invalidationCallback) {
|
|
@@ -637,6 +726,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
637
726
|
if (pending) {
|
|
638
727
|
return pending;
|
|
639
728
|
}
|
|
729
|
+
this.config.profiler.logOperationStart({ id: MAPPINGS_FETCH, specifier });
|
|
640
730
|
const fetchMappingService = this.hasMappingHooks()
|
|
641
731
|
? this.evaluateMappingHooks
|
|
642
732
|
: this.fetchNewMappings;
|
|
@@ -651,6 +741,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
651
741
|
if (!uri) {
|
|
652
742
|
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
653
743
|
}
|
|
744
|
+
this.config.profiler.logOperationEnd({ id: MAPPINGS_FETCH, specifier });
|
|
654
745
|
return uri;
|
|
655
746
|
})
|
|
656
747
|
.finally(() => {
|
|
@@ -695,6 +786,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
695
786
|
const uri = resolveUrl(this.buildMappingUrl(specifier), this.getBaseUrl());
|
|
696
787
|
return globalThis.fetch(uri).then((res) => {
|
|
697
788
|
if (!res.ok) {
|
|
789
|
+
this.config.profiler.logOperationStart({ id: MAPPINGS_ERROR, specifier });
|
|
698
790
|
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
699
791
|
}
|
|
700
792
|
return res
|
|
@@ -842,6 +934,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
842
934
|
this.namedDefineRegistry = new Map();
|
|
843
935
|
// The evaluted module registry where the module identifier (name or URL?) is the key
|
|
844
936
|
this.moduleRegistry = new Map();
|
|
937
|
+
this.profiler = config.profiler;
|
|
845
938
|
this.resolver = new ImportMetadataResolver(config, this.importMetadataInvalidationCallback.bind(this));
|
|
846
939
|
}
|
|
847
940
|
async load(id, importer) {
|
|
@@ -908,10 +1001,11 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
908
1001
|
}
|
|
909
1002
|
const resolvedUrl = this.resolver.resolveLocal(resolvedOrPlain);
|
|
910
1003
|
if (resolvedUrl) {
|
|
911
|
-
// return the plain id
|
|
912
|
-
if (this.namedDefineRegistry.has(resolvedOrPlain)
|
|
1004
|
+
// return the plain id if it is already defined && the resolvedUrl is NOT already in the module registry
|
|
1005
|
+
if (this.namedDefineRegistry.has(resolvedOrPlain) &&
|
|
1006
|
+
this.namedDefineRegistry.get(resolvedOrPlain).defined) {
|
|
913
1007
|
const record = this.moduleRegistry.get(resolvedUrl);
|
|
914
|
-
if (!record || record.
|
|
1008
|
+
if (!record || !record.aliases.has(resolvedOrPlain)) {
|
|
915
1009
|
return resolvedOrPlain;
|
|
916
1010
|
}
|
|
917
1011
|
}
|
|
@@ -962,6 +1056,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
962
1056
|
// if module is "external", resolve the external promise to notify any dependees
|
|
963
1057
|
mod.external.resolveExternal(moduleDef);
|
|
964
1058
|
}
|
|
1059
|
+
this.profiler.logOperationStart({ id: MODULE_DEFINE, specifier: name });
|
|
965
1060
|
this.namedDefineRegistry.set(name, moduleDef);
|
|
966
1061
|
this.lastDefine = moduleDef;
|
|
967
1062
|
}
|
|
@@ -1012,6 +1107,10 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1012
1107
|
getModuleRecord(resolvedId, id) {
|
|
1013
1108
|
let moduleRecord = this.moduleRegistry.get(resolvedId);
|
|
1014
1109
|
if (moduleRecord) {
|
|
1110
|
+
// Make sure the original id is in the alias set
|
|
1111
|
+
if (!moduleRecord.aliases.has(id)) {
|
|
1112
|
+
moduleRecord.aliases.add(id);
|
|
1113
|
+
}
|
|
1015
1114
|
return moduleRecord;
|
|
1016
1115
|
}
|
|
1017
1116
|
const instantiation = this.getModuleDef(resolvedId, id);
|
|
@@ -1031,7 +1130,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1031
1130
|
});
|
|
1032
1131
|
moduleRecord = {
|
|
1033
1132
|
id: resolvedId,
|
|
1034
|
-
|
|
1133
|
+
aliases: new Set([id]),
|
|
1035
1134
|
module: Object.create(null),
|
|
1036
1135
|
dependencyRecords,
|
|
1037
1136
|
instantiation,
|
|
@@ -1140,6 +1239,9 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1140
1239
|
if (moduleExports.__defaultInterop) {
|
|
1141
1240
|
Object.defineProperty(moduleRecord.module, '__defaultInterop', { value: true });
|
|
1142
1241
|
}
|
|
1242
|
+
if (moduleExports.__esModule) {
|
|
1243
|
+
Object.defineProperty(moduleRecord.module, '__esModule', { value: true });
|
|
1244
|
+
}
|
|
1143
1245
|
moduleRecord.evaluated = true;
|
|
1144
1246
|
Object.freeze(moduleRecord.module);
|
|
1145
1247
|
return moduleRecord.module;
|
|
@@ -1187,6 +1289,8 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1187
1289
|
return moduleDef;
|
|
1188
1290
|
}
|
|
1189
1291
|
const parentUrl = this.resolver.getBaseUrl(); // only support baseUrl for now
|
|
1292
|
+
const specifier = moduleName || originalId;
|
|
1293
|
+
this.profiler.logOperationStart({ id: MODULE_FETCH, specifier });
|
|
1190
1294
|
return Promise.resolve()
|
|
1191
1295
|
.then(async () => {
|
|
1192
1296
|
const loadHooks = this.loadHook;
|
|
@@ -1224,9 +1328,11 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1224
1328
|
if (!moduleDef) {
|
|
1225
1329
|
throw new LoaderError(FAIL_INSTANTIATE, [resolvedId]);
|
|
1226
1330
|
}
|
|
1331
|
+
this.profiler.logOperationEnd({ id: MODULE_FETCH, specifier });
|
|
1227
1332
|
return moduleDef;
|
|
1228
1333
|
})
|
|
1229
1334
|
.catch((e) => {
|
|
1335
|
+
this.profiler.logOperationStart({ id: MODULE_ERROR, specifier });
|
|
1230
1336
|
throw e;
|
|
1231
1337
|
});
|
|
1232
1338
|
}
|
|
@@ -1288,6 +1394,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1288
1394
|
constructor(config) {
|
|
1289
1395
|
let baseUrl = config.baseUrl;
|
|
1290
1396
|
const mappingEndpoint = config.endpoints ? config.endpoints.uris.mapping : undefined;
|
|
1397
|
+
let profiler = config.profiler;
|
|
1291
1398
|
if (!mappingEndpoint) {
|
|
1292
1399
|
throw new LoaderError(NO_MAPPING_URL);
|
|
1293
1400
|
}
|
|
@@ -1303,10 +1410,23 @@ LWR.define('lwr/loader/v/0_6_0-alpha_1', ['exports'], function (exports) { 'use
|
|
|
1303
1410
|
if (!baseUrl) {
|
|
1304
1411
|
throw new LoaderError(NO_BASE_URL);
|
|
1305
1412
|
}
|
|
1306
|
-
|
|
1413
|
+
if (!profiler) {
|
|
1414
|
+
// default noop profiler
|
|
1415
|
+
profiler = {
|
|
1416
|
+
logOperationStart: () => {
|
|
1417
|
+
/* noop */
|
|
1418
|
+
},
|
|
1419
|
+
logOperationEnd: () => {
|
|
1420
|
+
/* noop */
|
|
1421
|
+
},
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
this.registry = new ModuleRegistry(Object.freeze({ endpoints: config.endpoints, baseUrl, profiler }));
|
|
1425
|
+
// TODO: https://github.com/salesforce/lwr/issues/1087
|
|
1307
1426
|
this.services = Object.freeze({
|
|
1308
1427
|
addLoaderPlugin: this.registry.addLoaderPlugin.bind(this.registry),
|
|
1309
1428
|
handleStaleModule: this.registry.registerHandleStaleModuleHook.bind(this.registry),
|
|
1429
|
+
appMetadata: config.appMetadata,
|
|
1310
1430
|
});
|
|
1311
1431
|
}
|
|
1312
1432
|
/**
|