@lwrjs/loader 0.6.0-alpha.7 → 0.6.0
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-loader-shim-legacy.bundle.js +326 -218
- package/build/assets/prod/lwr-loader-shim-legacy.bundle.min.js +2 -2
- package/build/assets/prod/lwr-loader-shim-legacy.js +289 -213
- package/build/assets/prod/lwr-loader-shim.bundle.js +324 -261
- package/build/assets/prod/lwr-loader-shim.bundle.min.js +2 -2
- package/build/assets/prod/lwr-loader-shim.js +289 -251
- package/build/bundle/prod/lwr/esmLoader/esmLoader.js +1 -1
- package/build/cjs/modules/lwr/esmLoader/esmLoader.cjs +9 -6
- package/build/cjs/modules/lwr/esmLoader/importResolver.cjs +24 -3
- package/build/cjs/modules/lwr/loader/constants/constants.cjs +0 -8
- package/build/cjs/modules/lwr/loader/moduleRegistry/importMetadataResolver.cjs +4 -3
- package/build/cjs/modules/lwr/loader/moduleRegistry/moduleRegistry.cjs +8 -2
- package/build/cjs/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.cjs +12 -2
- package/build/modules/lwr/esmLoader/esmLoader.js +38 -10
- package/build/modules/lwr/loader/loader.js +35 -10
- package/build/modules/lwr/loaderLegacy/loaderLegacy.js +37 -5
- package/package.json +12 -7
|
@@ -4,270 +4,308 @@
|
|
|
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
|
|
7
|
+
/* LWR Module Loader Shim v0.6.0 */
|
|
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
|
-
|
|
37
|
-
const METRIC_INIT = 'lwr.bootstrap.init';
|
|
38
|
-
const METRIC_APP = 'lwr.bootstrap.application';
|
|
39
|
-
const METRIC_ERROR = 'lwr.bootstrap.error';
|
|
15
|
+
var Phase;
|
|
40
16
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Attach a custom dispatcher
|
|
46
|
-
let customDispatcher;
|
|
47
|
-
function attachDispatcher(dispatcher) {
|
|
48
|
-
customDispatcher = dispatcher;
|
|
49
|
-
}
|
|
50
|
-
// Check if the Performance API is available
|
|
51
|
-
// e.g. JSDom (used in Jest) doesn't implement these
|
|
52
|
-
const isPerfSupported = typeof globalThis.performance !== 'undefined' && typeof globalThis.performance.mark === 'function';
|
|
53
|
-
// For marking request metrics
|
|
54
|
-
// Fallback to the Performance API if there is no custom dispatcher
|
|
55
|
-
function logOperationStart({ id, specifier }) {
|
|
56
|
-
if (customDispatcher) {
|
|
57
|
-
customDispatcher({ id, phase: Phase.Start, specifier });
|
|
58
|
-
}
|
|
59
|
-
else if (isPerfSupported) {
|
|
60
|
-
globalThis.performance.mark(id + (specifier ? `.${specifier}` : ''));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function getProfilerAPI() {
|
|
64
|
-
// Create the public Profiler API
|
|
65
|
-
return { logOperationStart: logOperationStart.bind(this) };
|
|
66
|
-
}
|
|
17
|
+
(function (Phase) {
|
|
18
|
+
Phase[Phase["Start"] = 0] = "Start";
|
|
19
|
+
Phase[Phase["End"] = 1] = "End";
|
|
20
|
+
})(Phase || (Phase = {}));
|
|
67
21
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// If autoBoot === true, there must NOT be a customInit hook
|
|
75
|
-
if (autoBoot && customInit) {
|
|
76
|
-
throw new Error('The customInit hook must not be defined when autoBoot is true');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// Process the customInit hook
|
|
80
|
-
function customInit(config, initializeApp, define, onBootstrapError) {
|
|
81
|
-
// Validate config
|
|
82
|
-
const { autoBoot, customInit } = config;
|
|
83
|
-
validatePreInit(autoBoot, customInit);
|
|
84
|
-
// Set up arguments and call the customInit hook, if available
|
|
85
|
-
if (customInit) {
|
|
86
|
-
const lwr = {
|
|
87
|
-
initializeApp,
|
|
88
|
-
define,
|
|
89
|
-
onBootstrapError,
|
|
90
|
-
attachDispatcher,
|
|
91
|
-
};
|
|
92
|
-
customInit(lwr, config);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
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
|
|
95
28
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const tempDefine = this.tempDefine.bind(this);
|
|
113
|
-
global.LWR.define = tempDefine;
|
|
114
|
-
this.bootReady = this.config.autoBoot;
|
|
115
|
-
// Start watchdog timer
|
|
116
|
-
if (hasSetTimeout) {
|
|
117
|
-
this.watchdogTimerId = this.startWatchdogTimer();
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
customInit(Object.freeze(this.config), this.postCustomInit.bind(this), tempDefine, (e) => {
|
|
121
|
-
this.errorHandler = e;
|
|
122
|
-
});
|
|
123
|
-
// Mark "bootstrap init" here so:
|
|
124
|
-
// - a custom dispatcher set in customInit receives the log
|
|
125
|
-
// - the customInit duration is excluded from the "bootstrap init" duration
|
|
126
|
-
this.profiler.logOperationStart({ id: METRIC_INIT });
|
|
127
|
-
}
|
|
128
|
-
catch (e) {
|
|
129
|
-
this.enterErrorState(e);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Return true if the app can be initialized
|
|
133
|
-
canInit() {
|
|
134
|
-
// Initialize the app if:
|
|
135
|
-
// - bootReady: autoBoot is on OR customInit has finished
|
|
136
|
-
// - all required modules are defined
|
|
137
|
-
const allDefined = this.config.requiredModules.every((m) => this.orderedDefs.includes(m));
|
|
138
|
-
return this.bootReady && allDefined;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Create a temporary LWR.define() function which captures all
|
|
142
|
-
* calls that occur BEFORE the full loader module is available
|
|
143
|
-
*
|
|
144
|
-
* Each call to LWR.define() is stored in 2 ways:
|
|
145
|
-
* - in a map as [moduleName, arguments] pairs
|
|
146
|
-
* - each moduleName is pushed onto an array, to preserve
|
|
147
|
-
* the order in which the modules were defined
|
|
148
|
-
*/
|
|
149
|
-
tempDefine(...args) {
|
|
150
|
-
// Cache the incoming module
|
|
151
|
-
const moduleName = args[0];
|
|
152
|
-
this.defineCache[moduleName] = args;
|
|
153
|
-
this.orderedDefs.push(moduleName);
|
|
154
|
-
if (this.canInit()) {
|
|
155
|
-
if (hasSetTimeout) {
|
|
156
|
-
// requiredModules are defined, clear watchdog timer
|
|
157
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
158
|
-
clearTimeout(this.watchdogTimerId);
|
|
159
|
-
}
|
|
160
|
-
this.initApp();
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Called by the customInit hook via lwr.initializeApp()
|
|
164
|
-
postCustomInit() {
|
|
165
|
-
this.bootReady = true;
|
|
166
|
-
if (this.canInit()) {
|
|
167
|
-
this.initApp();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
// Create the loader and initialize the application
|
|
171
|
-
initApp() {
|
|
172
|
-
try {
|
|
173
|
-
const loaderConfig = {
|
|
174
|
-
endpoints: this.config.endpoints,
|
|
175
|
-
baseUrl: this.config.baseUrl,
|
|
176
|
-
profiler: this.profiler,
|
|
177
|
-
};
|
|
178
|
-
const loader = createLoader(this.loaderModule, this.defineCache[this.loaderModule], loaderConfig, this.config.preloadModules);
|
|
179
|
-
this.mountApp(loader);
|
|
180
|
-
}
|
|
181
|
-
catch (e) {
|
|
182
|
-
this.enterErrorState(e);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
waitForDOMContentLoaded() {
|
|
186
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
187
|
-
if (typeof document === undefined) {
|
|
188
|
-
return Promise.resolve();
|
|
189
|
-
}
|
|
190
|
-
// Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
|
|
191
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
192
|
-
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
193
|
-
return Promise.resolve();
|
|
194
|
-
}
|
|
195
|
-
return new Promise((resolve) => {
|
|
196
|
-
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
197
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
198
|
-
resolve();
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
// Set up the application globals, import map, root custom element...
|
|
203
|
-
mountApp(loader) {
|
|
204
|
-
const { bootstrapModule, rootComponent, rootComponents, endpoints, imports, index } = this.config;
|
|
205
|
-
// Set global LWR.define to loader.define
|
|
206
|
-
this.global.LWR = Object.freeze({
|
|
207
|
-
define: loader.define.bind(loader),
|
|
208
|
-
rootComponent,
|
|
209
|
-
rootComponents,
|
|
210
|
-
endpoints,
|
|
211
|
-
imports: imports || {},
|
|
212
|
-
index: index || {},
|
|
213
|
-
});
|
|
214
|
-
// Redefine all modules in the temporary cache
|
|
215
|
-
this.orderedDefs.forEach((specifier) => {
|
|
216
|
-
if (specifier !== this.loaderModule) {
|
|
217
|
-
loader.define(...this.defineCache[specifier]);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
// by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
|
|
221
|
-
const { disableInitDefer } = this.config;
|
|
222
|
-
// Load the import mappings and application bootstrap module
|
|
223
|
-
loader
|
|
224
|
-
.registerImportMappings({ imports, index }, [bootstrapModule, rootComponent])
|
|
225
|
-
.then(() => {
|
|
226
|
-
if (!disableInitDefer) {
|
|
227
|
-
return this.waitForDOMContentLoaded();
|
|
228
|
-
}
|
|
229
|
-
})
|
|
230
|
-
.then(() => {
|
|
231
|
-
this.profiler.logOperationStart({ id: METRIC_APP });
|
|
232
|
-
})
|
|
233
|
-
.then(() => loader.load(bootstrapModule))
|
|
234
|
-
.catch((reason) => {
|
|
235
|
-
this.enterErrorState(new Error(`Application ${rootComponent} could not be loaded: ${reason}`));
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
// Trigger bootstrap error state, and call error handler if registered
|
|
239
|
-
enterErrorState(error) {
|
|
240
|
-
this.profiler.logOperationStart({ id: METRIC_ERROR });
|
|
241
|
-
if (this.errorHandler) {
|
|
242
|
-
this.errorHandler(error);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
if (hasConsole) {
|
|
246
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
247
|
-
console.error(`An error occurred during LWR bootstrap. ${error.message}`, error.stack);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// eslint-disable-next-line no-undef, lwr/no-unguarded-apis
|
|
252
|
-
startWatchdogTimer() {
|
|
253
|
-
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
254
|
-
return setTimeout(() => {
|
|
255
|
-
this.enterErrorState(new Error('Failed to load required modules - timed out'));
|
|
256
|
-
}, REQUIRED_MODULES_TIMEOUT);
|
|
257
|
-
}
|
|
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}` : ''));
|
|
258
45
|
}
|
|
46
|
+
} // For measuring duration metrics
|
|
47
|
+
// Fallback to the Performance API if there is no custom dispatcher
|
|
259
48
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
49
|
+
/* istanbul ignore next */
|
|
50
|
+
|
|
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);
|
|
265
70
|
}
|
|
266
|
-
|
|
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';
|
|
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
|
+
appId: this.config.appId,
|
|
205
|
+
bootstrapModule: this.config.bootstrapModule,
|
|
206
|
+
rootComponent: this.config.rootComponent,
|
|
207
|
+
rootComponents: this.config.rootComponents,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
const loader = createLoader(this.loaderSpecifier, this.defineCache[this.loaderSpecifier], loaderConfig, this.config.preloadModules);
|
|
211
|
+
this.createProfilerModule(loader);
|
|
212
|
+
this.mountApp(loader);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
this.enterErrorState(e);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
waitForDOMContentLoaded() {
|
|
219
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
220
|
+
if (typeof document === undefined) {
|
|
221
|
+
return Promise.resolve();
|
|
222
|
+
}
|
|
223
|
+
// Resolve if document is already "ready" https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
|
|
224
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
225
|
+
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
226
|
+
return Promise.resolve();
|
|
227
|
+
}
|
|
228
|
+
return new Promise((resolve) => {
|
|
229
|
+
// eslint-disable-next-line lwr/no-unguarded-apis
|
|
230
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
231
|
+
resolve();
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
// Create a module out of the profiler
|
|
236
|
+
// Note: The profiler is also available as a module through lwc module resolution (see package.json)
|
|
237
|
+
createProfilerModule(loader) {
|
|
238
|
+
const exporter = (exports) => {
|
|
239
|
+
Object.assign(exports, { logOperationStart, logOperationEnd });
|
|
240
|
+
};
|
|
241
|
+
loader.define('lwr/profiler/v/0_6_0', ['exports'], exporter);
|
|
242
|
+
}
|
|
243
|
+
// Set up the application globals, import map, root custom element...
|
|
244
|
+
mountApp(loader) {
|
|
245
|
+
const { bootstrapModule, rootComponent, rootComponents, endpoints, imports, index } = this.config;
|
|
246
|
+
// Set global LWR.define to loader.define
|
|
247
|
+
this.global.LWR = Object.freeze({
|
|
248
|
+
define: loader.define.bind(loader),
|
|
249
|
+
rootComponent,
|
|
250
|
+
rootComponents,
|
|
251
|
+
endpoints,
|
|
252
|
+
imports: imports || {},
|
|
253
|
+
index: index || {},
|
|
254
|
+
});
|
|
255
|
+
// Redefine all modules in the temporary cache
|
|
256
|
+
this.orderedDefs.forEach((specifier) => {
|
|
257
|
+
if (specifier !== this.loaderSpecifier) {
|
|
258
|
+
loader.define(...this.defineCache[specifier]);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
// by default, app initialization is gated on waiting for document to be parsed (via DOMContentLoaded)
|
|
262
|
+
const { disableInitDefer } = this.config;
|
|
263
|
+
// Load the import mappings and application bootstrap module
|
|
264
|
+
loader
|
|
265
|
+
.registerImportMappings({ imports, index }, [bootstrapModule, rootComponent])
|
|
266
|
+
.then(() => {
|
|
267
|
+
if (!disableInitDefer) {
|
|
268
|
+
return this.waitForDOMContentLoaded();
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
.then(() => loader.load(bootstrapModule))
|
|
272
|
+
.catch((reason) => {
|
|
273
|
+
this.enterErrorState(new Error(`Application ${rootComponent} could not be loaded: ${reason}`));
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// Trigger bootstrap error state, and call error handler if registered
|
|
277
|
+
enterErrorState(error) {
|
|
278
|
+
logOperationStart({ id: BOOTSTRAP_ERROR });
|
|
279
|
+
if (this.errorHandler) {
|
|
280
|
+
this.errorHandler(error);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
if (hasConsole) {
|
|
284
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
285
|
+
console.error(`An error occurred during LWR bootstrap. ${error.message}`, error.stack);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// eslint-disable-next-line no-undef, lwr/no-unguarded-apis
|
|
290
|
+
startWatchdogTimer() {
|
|
291
|
+
// eslint-disable-next-line lwr/no-unguarded-apis, no-undef
|
|
292
|
+
return setTimeout(() => {
|
|
293
|
+
this.enterErrorState(new Error('Failed to load required modules - timed out'));
|
|
294
|
+
}, REQUIRED_MODULES_TIMEOUT);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// The loader module is ALWAYS required
|
|
299
|
+
const GLOBAL = globalThis;
|
|
300
|
+
GLOBAL.LWR.requiredModules = GLOBAL.LWR.requiredModules || [];
|
|
301
|
+
if (GLOBAL.LWR.requiredModules.indexOf('lwr/loader/v/0_6_0') < 0) {
|
|
302
|
+
GLOBAL.LWR.requiredModules.push('lwr/loader/v/0_6_0');
|
|
303
|
+
}
|
|
304
|
+
new LoaderShim(GLOBAL);
|
|
267
305
|
|
|
268
306
|
}());
|
|
269
307
|
|
|
270
|
-
LWR.define('lwr/loader/v/0_6_0
|
|
308
|
+
LWR.define('lwr/loader/v/0_6_0', ['exports'], function (exports) { 'use strict';
|
|
271
309
|
|
|
272
310
|
const templateRegex = /\{([0-9]+)\}/g;
|
|
273
311
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -564,11 +602,15 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
564
602
|
});
|
|
565
603
|
}
|
|
566
604
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const
|
|
570
|
-
const
|
|
571
|
-
const
|
|
605
|
+
// Bootstrap / shim
|
|
606
|
+
|
|
607
|
+
const LOADER_PREFIX = 'lwr.loader.';
|
|
608
|
+
const MODULE_DEFINE = `${LOADER_PREFIX}module.define`;
|
|
609
|
+
const MODULE_FETCH = `${LOADER_PREFIX}module.fetch`;
|
|
610
|
+
const MODULE_ERROR = `${LOADER_PREFIX}module.error`;
|
|
611
|
+
|
|
612
|
+
const MAPPINGS_FETCH = `${LOADER_PREFIX}mappings.fetch`;
|
|
613
|
+
const MAPPINGS_ERROR = `${LOADER_PREFIX}mappings.error`;
|
|
572
614
|
|
|
573
615
|
/* spec based import map resolver */
|
|
574
616
|
class ImportMetadataResolver {
|
|
@@ -685,7 +727,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
685
727
|
if (pending) {
|
|
686
728
|
return pending;
|
|
687
729
|
}
|
|
688
|
-
this.config.profiler.logOperationStart({ id:
|
|
730
|
+
this.config.profiler.logOperationStart({ id: MAPPINGS_FETCH, specifier });
|
|
689
731
|
const fetchMappingService = this.hasMappingHooks()
|
|
690
732
|
? this.evaluateMappingHooks
|
|
691
733
|
: this.fetchNewMappings;
|
|
@@ -700,6 +742,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
700
742
|
if (!uri) {
|
|
701
743
|
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
702
744
|
}
|
|
745
|
+
this.config.profiler.logOperationEnd({ id: MAPPINGS_FETCH, specifier });
|
|
703
746
|
return uri;
|
|
704
747
|
})
|
|
705
748
|
.finally(() => {
|
|
@@ -744,7 +787,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
744
787
|
const uri = resolveUrl(this.buildMappingUrl(specifier), this.getBaseUrl());
|
|
745
788
|
return globalThis.fetch(uri).then((res) => {
|
|
746
789
|
if (!res.ok) {
|
|
747
|
-
this.config.profiler.logOperationStart({ id:
|
|
790
|
+
this.config.profiler.logOperationStart({ id: MAPPINGS_ERROR, specifier });
|
|
748
791
|
throw new LoaderError(UNRESOLVED, [specifier]);
|
|
749
792
|
}
|
|
750
793
|
return res
|
|
@@ -798,6 +841,8 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
798
841
|
}
|
|
799
842
|
}
|
|
800
843
|
|
|
844
|
+
const MODULE_LOAD_TIMEOUT_TIMER = 300000;
|
|
845
|
+
|
|
801
846
|
let lastWindowError;
|
|
802
847
|
if (hasDocument) {
|
|
803
848
|
globalThis.addEventListener('error', (evt) => {
|
|
@@ -1012,6 +1057,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
1012
1057
|
// if module is "external", resolve the external promise to notify any dependees
|
|
1013
1058
|
mod.external.resolveExternal(moduleDef);
|
|
1014
1059
|
}
|
|
1060
|
+
this.profiler.logOperationStart({ id: MODULE_DEFINE, specifier: name });
|
|
1015
1061
|
this.namedDefineRegistry.set(name, moduleDef);
|
|
1016
1062
|
this.lastDefine = moduleDef;
|
|
1017
1063
|
}
|
|
@@ -1194,6 +1240,9 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
1194
1240
|
if (moduleExports.__defaultInterop) {
|
|
1195
1241
|
Object.defineProperty(moduleRecord.module, '__defaultInterop', { value: true });
|
|
1196
1242
|
}
|
|
1243
|
+
if (moduleExports.__esModule) {
|
|
1244
|
+
Object.defineProperty(moduleRecord.module, '__esModule', { value: true });
|
|
1245
|
+
}
|
|
1197
1246
|
moduleRecord.evaluated = true;
|
|
1198
1247
|
Object.freeze(moduleRecord.module);
|
|
1199
1248
|
return moduleRecord.module;
|
|
@@ -1242,7 +1291,7 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
1242
1291
|
}
|
|
1243
1292
|
const parentUrl = this.resolver.getBaseUrl(); // only support baseUrl for now
|
|
1244
1293
|
const specifier = moduleName || originalId;
|
|
1245
|
-
this.profiler.logOperationStart({ id:
|
|
1294
|
+
this.profiler.logOperationStart({ id: MODULE_FETCH, specifier });
|
|
1246
1295
|
return Promise.resolve()
|
|
1247
1296
|
.then(async () => {
|
|
1248
1297
|
const loadHooks = this.loadHook;
|
|
@@ -1280,10 +1329,11 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
1280
1329
|
if (!moduleDef) {
|
|
1281
1330
|
throw new LoaderError(FAIL_INSTANTIATE, [resolvedId]);
|
|
1282
1331
|
}
|
|
1332
|
+
this.profiler.logOperationEnd({ id: MODULE_FETCH, specifier });
|
|
1283
1333
|
return moduleDef;
|
|
1284
1334
|
})
|
|
1285
1335
|
.catch((e) => {
|
|
1286
|
-
this.profiler.logOperationStart({ id:
|
|
1336
|
+
this.profiler.logOperationStart({ id: MODULE_ERROR, specifier });
|
|
1287
1337
|
throw e;
|
|
1288
1338
|
});
|
|
1289
1339
|
}
|
|
@@ -1367,12 +1417,25 @@ LWR.define('lwr/loader/v/0_6_0-alpha_7', ['exports'], function (exports) { 'use
|
|
|
1367
1417
|
logOperationStart: () => {
|
|
1368
1418
|
/* noop */
|
|
1369
1419
|
},
|
|
1420
|
+
logOperationEnd: () => {
|
|
1421
|
+
/* noop */
|
|
1422
|
+
},
|
|
1370
1423
|
};
|
|
1371
1424
|
}
|
|
1372
1425
|
this.registry = new ModuleRegistry(Object.freeze({ endpoints: config.endpoints, baseUrl, profiler }));
|
|
1426
|
+
// TODO: W-10539691 - temp workaround for LWR-Java -- remove once appId is implemented there
|
|
1427
|
+
if (config.appMetadata && !config.appMetadata.appId) {
|
|
1428
|
+
// Parse the appId from the bootstrapModule
|
|
1429
|
+
// LWR-Java bootstrap module format: @lwr-bootstrap/my/app/v/0_0_1 -- my/app is the appId
|
|
1430
|
+
const match = config.appMetadata.bootstrapModule.match(/@lwr-bootstrap\/(.+)\/v\/.+/);
|
|
1431
|
+
const appId = match && match[1];
|
|
1432
|
+
config.appMetadata.appId = appId;
|
|
1433
|
+
}
|
|
1434
|
+
// TODO: https://github.com/salesforce/lwr/issues/1087
|
|
1373
1435
|
this.services = Object.freeze({
|
|
1374
1436
|
addLoaderPlugin: this.registry.addLoaderPlugin.bind(this.registry),
|
|
1375
1437
|
handleStaleModule: this.registry.registerHandleStaleModuleHook.bind(this.registry),
|
|
1438
|
+
appMetadata: config.appMetadata,
|
|
1376
1439
|
});
|
|
1377
1440
|
}
|
|
1378
1441
|
/**
|