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