@lwrjs/loader 0.13.0-alpha.2 → 0.13.0-alpha.21

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.
Files changed (119) hide show
  1. package/build/assets/prod/lwr-error-shim.js +2 -2
  2. package/build/assets/prod/lwr-loader-shim-legacy.bundle.js +34 -29
  3. package/build/assets/prod/lwr-loader-shim-legacy.bundle.min.js +3 -3
  4. package/build/assets/prod/lwr-loader-shim-legacy.js +21 -16
  5. package/build/assets/prod/lwr-loader-shim.bundle.js +45 -23
  6. package/build/assets/prod/lwr-loader-shim.bundle.min.js +3 -3
  7. package/build/assets/prod/lwr-loader-shim.js +27 -12
  8. package/build/bundle/prod/lwr/esmLoader/esmLoader.js +1 -1
  9. package/build/cjs/index.cjs +28 -1
  10. package/build/cjs/modules/lwr/esmLoader/esmLoader.cjs +2 -2
  11. package/build/cjs/modules/lwr/esmLoader/importResolver.cjs +0 -17
  12. package/build/cjs/modules/lwr/esmLoader/importResolverLegacy.cjs +1 -18
  13. package/build/cjs/modules/lwr/loader/errors/messages.cjs +7 -1
  14. package/build/cjs/modules/lwr/loader/errors/reportError.cjs +1 -2
  15. package/build/cjs/modules/lwr/loader/hooks/moduleInvalidation.cjs +2 -3
  16. package/build/cjs/modules/lwr/loader/hooks/resolveAndLoadHook.cjs +3 -4
  17. package/build/cjs/modules/lwr/loader/moduleRegistry/importMetadataResolver.cjs +7 -6
  18. package/build/cjs/modules/lwr/loader/moduleRegistry/moduleRegistry.cjs +8 -10
  19. package/build/cjs/modules/lwr/loader/moduleRegistry/scriptLoad.cjs +2 -2
  20. package/build/cjs/modules/lwr/loader/utils/url.cjs +1 -1
  21. package/build/cjs/modules/lwr/loaderLegacy/errors/messages.cjs +1 -1
  22. package/build/cjs/modules/lwr/loaderLegacy/errors/reportError.cjs +1 -2
  23. package/build/cjs/modules/lwr/loaderLegacy/hooks/moduleInvalidation.cjs +2 -3
  24. package/build/cjs/modules/lwr/loaderLegacy/hooks/resolveAndLoadHook.cjs +3 -4
  25. package/build/cjs/modules/lwr/loaderLegacy/importMap/dom.cjs +4 -4
  26. package/build/cjs/modules/lwr/loaderLegacy/importMap/importMap.cjs +2 -2
  27. package/build/cjs/modules/lwr/loaderLegacy/importMap/importMapResolver.cjs +1 -2
  28. package/build/cjs/modules/lwr/loaderLegacy/importMap/utils.cjs +1 -1
  29. package/build/cjs/modules/lwr/loaderLegacy/importResolver/importResolver.cjs +0 -17
  30. package/build/cjs/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.cjs +7 -10
  31. package/build/cjs/modules/lwr/loaderLegacy/moduleRegistry/scriptLoad.cjs +2 -2
  32. package/build/cjs/modules/lwr/loaderLegacy/utils/url.cjs +1 -1
  33. package/build/cjs/package.d.cjs +0 -0
  34. package/build/cjs/types.cjs +5 -0
  35. package/build/error-shim/index.d.ts +2 -0
  36. package/build/error-shim/index.js +17 -0
  37. package/build/index.d.ts +1 -1
  38. package/build/index.js +28 -1
  39. package/build/modules/lwr/esmLoader/esmLoader.d.ts +6 -0
  40. package/build/modules/lwr/esmLoader/esmLoader.js +2 -2
  41. package/build/modules/lwr/esmLoader/importResolver.d.ts +17 -0
  42. package/build/modules/lwr/esmLoader/importResolver.js +47 -0
  43. package/build/modules/lwr/esmLoader/importResolverLegacy.d.ts +16 -0
  44. package/build/modules/lwr/esmLoader/importResolverLegacy.js +18 -0
  45. package/build/modules/lwr/loader/constants/constants.d.ts +2 -0
  46. package/build/modules/lwr/loader/constants/constants.js +2 -0
  47. package/build/modules/lwr/loader/errors/messages.d.ts +33 -0
  48. package/build/modules/lwr/loader/errors/messages.js +128 -0
  49. package/build/modules/lwr/loader/errors/reportError.d.ts +4 -0
  50. package/build/modules/lwr/loader/errors/reportError.js +9 -0
  51. package/build/modules/lwr/loader/errors/utils.d.ts +2 -0
  52. package/build/modules/lwr/loader/errors/utils.js +8 -0
  53. package/build/modules/lwr/loader/hooks/moduleInvalidation.d.ts +3 -0
  54. package/build/modules/lwr/loader/hooks/moduleInvalidation.js +19 -0
  55. package/build/modules/lwr/loader/hooks/resolveAndLoadHook.d.ts +7 -0
  56. package/build/modules/lwr/loader/hooks/resolveAndLoadHook.js +94 -0
  57. package/build/modules/lwr/loader/loader.d.ts +53 -0
  58. package/build/modules/lwr/loader/loader.js +18 -11
  59. package/build/modules/lwr/loader/moduleRegistry/importMetadataResolver.d.ts +44 -0
  60. package/build/modules/lwr/loader/moduleRegistry/importMetadataResolver.js +211 -0
  61. package/build/modules/lwr/loader/moduleRegistry/moduleRegistry.d.ts +47 -0
  62. package/build/modules/lwr/loader/moduleRegistry/moduleRegistry.js +530 -0
  63. package/build/modules/lwr/loader/moduleRegistry/scriptLoad.d.ts +3 -0
  64. package/build/modules/lwr/loader/moduleRegistry/scriptLoad.js +43 -0
  65. package/build/modules/lwr/loader/utils/dom.d.ts +4 -0
  66. package/build/modules/lwr/loader/utils/dom.js +6 -0
  67. package/build/modules/lwr/loader/utils/url.d.ts +28 -0
  68. package/build/modules/lwr/loader/utils/url.js +128 -0
  69. package/build/modules/lwr/loaderLegacy/constants/constants.d.ts +2 -0
  70. package/build/modules/lwr/loaderLegacy/constants/constants.js +2 -0
  71. package/build/modules/lwr/loaderLegacy/errors/messages.d.ts +30 -0
  72. package/build/modules/lwr/loaderLegacy/errors/messages.js +113 -0
  73. package/build/modules/lwr/loaderLegacy/errors/reportError.d.ts +4 -0
  74. package/build/modules/lwr/loaderLegacy/errors/reportError.js +9 -0
  75. package/build/modules/lwr/loaderLegacy/errors/utils.d.ts +2 -0
  76. package/build/modules/lwr/loaderLegacy/errors/utils.js +8 -0
  77. package/build/modules/lwr/loaderLegacy/hooks/moduleInvalidation.d.ts +3 -0
  78. package/build/modules/lwr/loaderLegacy/hooks/moduleInvalidation.js +19 -0
  79. package/build/modules/lwr/loaderLegacy/hooks/resolveAndLoadHook.d.ts +7 -0
  80. package/build/modules/lwr/loaderLegacy/hooks/resolveAndLoadHook.js +94 -0
  81. package/build/modules/lwr/loaderLegacy/importMap/dom.d.ts +10 -0
  82. package/build/modules/lwr/loaderLegacy/importMap/dom.js +63 -0
  83. package/build/modules/lwr/loaderLegacy/importMap/importMap.d.ts +22 -0
  84. package/build/modules/lwr/loaderLegacy/importMap/importMap.js +108 -0
  85. package/build/modules/lwr/loaderLegacy/importMap/importMapResolver.d.ts +8 -0
  86. package/build/modules/lwr/loaderLegacy/importMap/importMapResolver.js +11 -0
  87. package/build/modules/lwr/loaderLegacy/importMap/utils.d.ts +4 -0
  88. package/build/modules/lwr/loaderLegacy/importMap/utils.js +23 -0
  89. package/build/modules/lwr/loaderLegacy/importResolver/importResolver.d.ts +6 -0
  90. package/build/modules/lwr/loaderLegacy/importResolver/importResolver.js +2 -0
  91. package/build/modules/lwr/loaderLegacy/loaderLegacy.d.ts +57 -0
  92. package/build/modules/lwr/loaderLegacy/loaderLegacy.js +13 -13
  93. package/build/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.d.ts +53 -0
  94. package/build/modules/lwr/loaderLegacy/moduleRegistry/moduleRegistry.js +544 -0
  95. package/build/modules/lwr/loaderLegacy/moduleRegistry/scriptLoad.d.ts +3 -0
  96. package/build/modules/lwr/loaderLegacy/moduleRegistry/scriptLoad.js +43 -0
  97. package/build/modules/lwr/loaderLegacy/utils/dom.d.ts +4 -0
  98. package/build/modules/lwr/loaderLegacy/utils/dom.js +6 -0
  99. package/build/modules/lwr/loaderLegacy/utils/url.d.ts +28 -0
  100. package/build/modules/lwr/loaderLegacy/utils/url.js +128 -0
  101. package/build/shim/constants.d.ts +2 -0
  102. package/build/shim/constants.js +2 -0
  103. package/build/shim/customInit.d.ts +4 -0
  104. package/build/shim/customInit.js +29 -0
  105. package/build/shim/index.d.ts +2 -0
  106. package/build/shim/index.js +9 -0
  107. package/build/shim/loader.d.ts +3 -0
  108. package/build/shim/loader.js +27 -0
  109. package/build/shim/shim.d.ts +31 -0
  110. package/build/shim/shim.js +194 -0
  111. package/build/shim-legacy/index.d.ts +2 -0
  112. package/build/shim-legacy/index.js +9 -0
  113. package/build/shim-legacy/loaderLegacy.d.ts +3 -0
  114. package/build/shim-legacy/loaderLegacy.js +29 -0
  115. package/build/shim-legacy/shimLegacy.d.ts +31 -0
  116. package/build/shim-legacy/shimLegacy.js +188 -0
  117. package/build/types.d.ts +56 -0
  118. package/build/types.js +2 -0
  119. package/package.json +9 -10
@@ -0,0 +1,544 @@
1
+ /* global console,process */
2
+ import { invariant, NO_AMD_REQUIRE, LoaderError, FAIL_INSTANTIATE, FAILED_DEP, UNRESOLVED, INVALID_HOOK, INVALID_LOADER_SERVICE_RESPONSE, MODULE_ALREADY_LOADED, MODULE_LOAD_TIMEOUT, EXPORTER_ERROR, } from '../errors/messages.js';
3
+ import { resolveIfNotPlainOrUrl, isUrl } from '../utils/url.js';
4
+ import { hasDocument, hasConsole } from '../utils/dom.js';
5
+ import { loadModuleDef } from './scriptLoad.js';
6
+ import { evaluateLoadHookResponse, evaluateLoadHook, isResponseAPromise, } from '../hooks/resolveAndLoadHook.js';
7
+ import { evaluateHandleStaleModuleHooks } from '../hooks/moduleInvalidation.js';
8
+ import { MODULE_LOAD_TIMEOUT_TIMER } from '../constants/constants.js';
9
+ import { MODULE_DEFINE, MODULE_ERROR, MODULE_FETCH, MODULE_DYNAMIC_LOAD } from 'lwr/metrics';
10
+ export class ModuleRegistry {
11
+ constructor(config) {
12
+ // A registry for named AMD defines containing the *metadata* of AMD module
13
+ this.namedDefineRegistry = new Map();
14
+ // The evaluated module registry where the module identifier (name or URL?) is the key
15
+ this.moduleRegistry = new Map();
16
+ // Aliases of modules in the registry
17
+ this.aliases = new Map();
18
+ this.baseUrl = config.baseUrl || '';
19
+ this.profiler = config.profiler;
20
+ }
21
+ async load(id, importer) {
22
+ const metadata = importer ? { importer } : {};
23
+ this.profiler.logOperationStart({
24
+ id: MODULE_DYNAMIC_LOAD,
25
+ specifier: id,
26
+ metadata,
27
+ });
28
+ const resolvedId = await this.resolve(id, importer);
29
+ const moduleRecord = await this.getModuleRecord(resolvedId, id);
30
+ if (moduleRecord.evaluated) {
31
+ return moduleRecord.module;
32
+ }
33
+ else {
34
+ if (!moduleRecord.evaluationPromise) {
35
+ moduleRecord.evaluationPromise = this.topLevelEvaluation(moduleRecord);
36
+ }
37
+ return moduleRecord.evaluationPromise;
38
+ }
39
+ }
40
+ async resolve(id, importer) {
41
+ const parentUrl = this.baseUrl; // only support baseUrl for now
42
+ let resolved;
43
+ let aliasedId = id;
44
+ const resolveHooks = this.resolveHook;
45
+ let useImporter = true;
46
+ if (resolveHooks) {
47
+ for (let i = 0; i < resolveHooks.length; i++) {
48
+ const resolveHook = resolveHooks[i];
49
+ const response = resolveHook(aliasedId, { parentUrl });
50
+ let result;
51
+ if (response || response === null) {
52
+ // eslint-disable-next-line no-await-in-loop
53
+ result = isResponseAPromise(response) ? await response : response;
54
+ }
55
+ if (!this.isValidResolveResponse(result)) {
56
+ throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
57
+ }
58
+ // if result is not null, attempt resolution
59
+ if (result !== null) {
60
+ if (typeof result === 'string') {
61
+ if (resolveIfNotPlainOrUrl(result, parentUrl)) {
62
+ // string response can't be a URL
63
+ throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
64
+ }
65
+ aliasedId = result; // the next hook will receive the new id
66
+ continue;
67
+ }
68
+ resolved =
69
+ result && result.url && (resolveIfNotPlainOrUrl(result.url, parentUrl) || result.url);
70
+ if (!resolved) {
71
+ throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
72
+ }
73
+ // Don't process any more hooks if we have resolved
74
+ break;
75
+ }
76
+ }
77
+ if (aliasedId !== id) {
78
+ // resolved module id is the aliased module if it has already been defined
79
+ if (!resolved && this.namedDefineRegistry.has(aliasedId)) {
80
+ return aliasedId;
81
+ }
82
+ else {
83
+ id = aliasedId;
84
+ }
85
+ }
86
+ }
87
+ if (!resolved) {
88
+ const resolvedOrPlain = resolveIfNotPlainOrUrl(id, parentUrl) || id;
89
+ // if module registry already has named module the resolved id is the plain id
90
+ if (this.moduleRegistry.has(resolvedOrPlain)) {
91
+ return resolvedOrPlain;
92
+ }
93
+ if (this.resolver) {
94
+ const importDefinition = this.resolver.resolve(resolvedOrPlain, parentUrl);
95
+ resolved = importDefinition && importDefinition.uri;
96
+ useImporter = importDefinition ? !!importDefinition.defaultUri : useImporter;
97
+ // resolve to the bare specifier if conditions are met
98
+ if (this.namedDefineRegistry.has(resolvedOrPlain)) {
99
+ const namedDefineRecord = this.namedDefineRegistry.get(resolvedOrPlain);
100
+ if (namedDefineRecord.external || namedDefineRecord.defined) {
101
+ const record = this.moduleRegistry.get(resolved);
102
+ if (!record || !this.aliases.has(resolvedOrPlain)) {
103
+ return resolvedOrPlain;
104
+ }
105
+ }
106
+ }
107
+ }
108
+ else {
109
+ resolved = resolvedOrPlain;
110
+ }
111
+ }
112
+ if (!resolved || !isUrl(resolved)) {
113
+ if (this.namedDefineRegistry.has(id)) {
114
+ return id;
115
+ }
116
+ throw new LoaderError(UNRESOLVED, [id]);
117
+ }
118
+ if (useImporter && importer && isUrl(resolved)) {
119
+ resolved += `?importer=${encodeURIComponent(importer)}`;
120
+ }
121
+ return resolved;
122
+ }
123
+ has(id) {
124
+ return this.moduleRegistry.has(id);
125
+ }
126
+ define(name, dependencies, exporter, signatures) {
127
+ const mod = this.namedDefineRegistry.get(name);
128
+ // Don't allow redefining a module.
129
+ if (mod && mod.defined) {
130
+ if (process.env.NODE_ENV !== 'production' && hasConsole) {
131
+ // eslint-disable-next-line lwr/no-unguarded-apis
132
+ console.warn(`Module redefine attempted: ${name}`);
133
+ }
134
+ this.lastDefine = mod;
135
+ return;
136
+ }
137
+ const moduleDef = {
138
+ name,
139
+ dependencies,
140
+ exporter,
141
+ signatures,
142
+ defined: true,
143
+ };
144
+ if (mod && mod.external) {
145
+ // if module is "external", resolve the external promise to notify any dependencies
146
+ mod.external.resolveExternal(moduleDef);
147
+ }
148
+ this.profiler.logOperationStart({ id: MODULE_DEFINE, specifier: name });
149
+ this.namedDefineRegistry.set(name, moduleDef);
150
+ this.lastDefine = moduleDef;
151
+ // Check signatures of dependencies against those in the namedDefineRegistry
152
+ if (signatures.hashes) {
153
+ Object.entries(signatures.hashes).forEach(([dep, sig]) => {
154
+ this.checkModuleSignature(dep, sig);
155
+ });
156
+ }
157
+ }
158
+ /**
159
+ * Marks modules as "externally" loaded/provided, so that the loader does not attempt to fetch them.
160
+ *
161
+ * @param modules - list of module identifiers
162
+ */
163
+ registerExternalModules(modules) {
164
+ modules.map((id) => {
165
+ if (!this.namedDefineRegistry.has(id)) {
166
+ let resolveExternal;
167
+ let timer;
168
+ const moduleDefPromise = new Promise((resolve, reject) => {
169
+ resolveExternal = resolve;
170
+ // watch the external for timeout
171
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
172
+ timer = setTimeout(() => {
173
+ reject(new LoaderError(MODULE_LOAD_TIMEOUT, [id]));
174
+ }, MODULE_LOAD_TIMEOUT_TIMER);
175
+ }).finally(() => {
176
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
177
+ clearTimeout(timer);
178
+ });
179
+ const moduleDef = {
180
+ name: id,
181
+ defined: false,
182
+ external: {
183
+ resolveExternal,
184
+ moduleDefPromise,
185
+ },
186
+ };
187
+ this.namedDefineRegistry.set(id, moduleDef);
188
+ }
189
+ else if (process.env.NODE_ENV !== 'production' && hasConsole) {
190
+ // eslint-disable-next-line lwr/no-unguarded-apis
191
+ console.warn(MODULE_ALREADY_LOADED.message, id);
192
+ }
193
+ });
194
+ }
195
+ checkModuleSignature(name, signature) {
196
+ const moduleDef = this.namedDefineRegistry.get(name);
197
+ if (!moduleDef) {
198
+ // Placeholder module definition entry for saving known signature
199
+ const modDef = {
200
+ name,
201
+ signatures: {
202
+ ownHash: signature,
203
+ },
204
+ defined: false,
205
+ };
206
+ this.namedDefineRegistry.set(name, modDef);
207
+ return;
208
+ }
209
+ const currentSig = moduleDef.signatures ? moduleDef.signatures.ownHash : undefined;
210
+ if (currentSig && signature !== currentSig) {
211
+ const handleStaleModuleHooks = this.handleStaleModuleHook;
212
+ if (handleStaleModuleHooks) {
213
+ evaluateHandleStaleModuleHooks(handleStaleModuleHooks, {
214
+ name,
215
+ oldHash: currentSig,
216
+ newHash: signature,
217
+ });
218
+ }
219
+ else {
220
+ if (process.env.NODE_ENV !== 'production' && hasConsole) {
221
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
222
+ console.warn(`stale module detected ${name}, current sig:${currentSig}, new sig:${signature}`);
223
+ }
224
+ }
225
+ }
226
+ }
227
+ setImportResolver(resolver) {
228
+ this.resolver = resolver;
229
+ }
230
+ // Returns an existing module record by the resolvedId or aliased id
231
+ getExistingModuleRecord(resolvedId, aliasId) {
232
+ const moduleRecord = this.moduleRegistry.get(resolvedId);
233
+ if (moduleRecord) {
234
+ this.storeModuleAlias(aliasId, resolvedId);
235
+ return moduleRecord;
236
+ }
237
+ // Check if this is a known alias
238
+ if (resolvedId !== aliasId) {
239
+ const alias = this.aliases.get(aliasId);
240
+ if (alias) {
241
+ const aliasedModule = this.moduleRegistry.get(alias);
242
+ if (aliasedModule) {
243
+ return aliasedModule;
244
+ }
245
+ }
246
+ }
247
+ return moduleRecord;
248
+ }
249
+ async getModuleRecord(resolvedId, id) {
250
+ // Look for an existing record
251
+ const existingRecord = this.getExistingModuleRecord(resolvedId, id);
252
+ if (existingRecord) {
253
+ // return existing
254
+ return existingRecord;
255
+ }
256
+ // Create a new Module Record
257
+ const instantiation = this.getModuleDef(resolvedId, id);
258
+ const dependencyRecords = instantiation.then((moduleDef) => {
259
+ const dependencies = (moduleDef && moduleDef.dependencies) || [];
260
+ // get dep and filter out exports
261
+ const filtered = dependencies
262
+ .map((dep) => {
263
+ if (dep === 'exports') {
264
+ return;
265
+ }
266
+ invariant(dep !== 'require', NO_AMD_REQUIRE);
267
+ return this.getModuleDependencyRecord.call(this, dep);
268
+ })
269
+ .filter((depRecord) => depRecord !== undefined);
270
+ return Promise.all(filtered);
271
+ });
272
+ const newModuleRecord = {
273
+ id: resolvedId,
274
+ module: Object.create(null),
275
+ dependencyRecords,
276
+ instantiation,
277
+ evaluated: false,
278
+ evaluationPromise: null,
279
+ };
280
+ this.moduleRegistry.set(resolvedId, newModuleRecord);
281
+ this.storeModuleAlias(id, resolvedId);
282
+ // Wait for the dependencies to resolve the return the moduleRecord
283
+ return dependencyRecords.then(() => newModuleRecord);
284
+ }
285
+ storeModuleAlias(aliasId, resolvedId) {
286
+ if (aliasId !== resolvedId) {
287
+ if (!this.aliases.has(aliasId)) {
288
+ this.aliases.set(aliasId, resolvedId);
289
+ }
290
+ else if (hasConsole) {
291
+ // Warn the user if they were not aliasing to the resolvedId
292
+ const currentResolvedId = this.aliases.get(aliasId);
293
+ if (currentResolvedId !== resolvedId) {
294
+ if (process.env.NODE_ENV !== 'production' && hasConsole) {
295
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
296
+ console.warn(`Alias update attempt: ${aliasId}=>${currentResolvedId}, ${resolvedId}`);
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }
302
+ async getModuleDependencyRecord(dependency) {
303
+ const resolvedDepId = await this.resolve(dependency);
304
+ return this.getModuleRecord(resolvedDepId, dependency);
305
+ }
306
+ // execute the "top-level code" (the code outside of functions) of a module
307
+ async topLevelEvaluation(moduleRecord) {
308
+ await this.instantiateAll(moduleRecord, {});
309
+ return this.evaluateModule(moduleRecord, {});
310
+ }
311
+ // Returns a promise when a module and all of it's dependencies have finished instantiation
312
+ async instantiateAll(moduleRecord, instantiatedMap) {
313
+ if (!instantiatedMap[moduleRecord.id]) {
314
+ instantiatedMap[moduleRecord.id] = true;
315
+ const dependencyModuleRecords = await moduleRecord.dependencyRecords;
316
+ if (dependencyModuleRecords) {
317
+ for (let i = 0; i < dependencyModuleRecords.length; i++) {
318
+ const depRecord = dependencyModuleRecords[i];
319
+ // eslint-disable-next-line no-await-in-loop
320
+ await this.instantiateAll(depRecord, instantiatedMap);
321
+ }
322
+ }
323
+ }
324
+ }
325
+ async evaluateModule(moduleRecord, evaluationMap) {
326
+ const dependencyModuleRecords = await moduleRecord.dependencyRecords;
327
+ if (dependencyModuleRecords.length > 0) {
328
+ evaluationMap[moduleRecord.id] = true;
329
+ // evaluate dependencies first
330
+ await this.evaluateModuleDependencies(dependencyModuleRecords, evaluationMap);
331
+ }
332
+ const { exporter, dependencies } = await moduleRecord.instantiation;
333
+ // The exports object automatically gets filled in by the exporter evaluation
334
+ const exports = {};
335
+ const depsMapped = dependencies
336
+ ? await Promise.all(dependencies.map(async (dep) => {
337
+ if (dep === 'exports') {
338
+ return exports;
339
+ }
340
+ const resolvedDepId = await this.resolve(dep);
341
+ const moduleRecord = this.moduleRegistry.get(resolvedDepId);
342
+ if (!moduleRecord) {
343
+ throw new LoaderError(FAILED_DEP, [resolvedDepId]);
344
+ }
345
+ const module = moduleRecord.module;
346
+ /**
347
+ * Circular dependencies are handled properly when named exports are used,
348
+ * however, for default exports there is a bug: https://github.com/rollup/rollup/issues/3384
349
+ *
350
+ * The workaround below applies for circular dependencies (!moduleRecord.evaluated)
351
+ */
352
+ if (!moduleRecord.evaluated) {
353
+ return this.getCircularDependencyWrapper(module);
354
+ }
355
+ if (module) {
356
+ return module.__defaultInterop ? module.default : module;
357
+ }
358
+ throw new LoaderError(FAILED_DEP, [resolvedDepId]);
359
+ }))
360
+ : [];
361
+ // 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
362
+ if (moduleRecord.evaluated) {
363
+ return moduleRecord.module;
364
+ }
365
+ // evaluates the module function
366
+ let moduleDefault;
367
+ try {
368
+ moduleDefault = exporter(...depsMapped);
369
+ }
370
+ catch (e) {
371
+ throw new LoaderError(EXPORTER_ERROR, [moduleRecord.id, e.message || e]);
372
+ }
373
+ // value is returned from exporter, then we are not using named exports
374
+ if (moduleDefault !== undefined) {
375
+ moduleDefault = { default: moduleDefault };
376
+ // __defaultInterop is ONLY used to support backwards compatibility
377
+ // of importing default exports the "wrong" way (when not using named exports).
378
+ // See https://github.com/salesforce-experience-platform-emu/lwr/pull/816
379
+ Object.defineProperty(moduleDefault, '__defaultInterop', { value: true });
380
+ }
381
+ // if no return value, then we are using the exports object
382
+ else {
383
+ // handle only default export with Rollup forced named exports
384
+ if (this.isNamedExportDefaultOnly(exports)) {
385
+ Object.defineProperty(exports, '__useDefault', { value: true });
386
+ }
387
+ }
388
+ const moduleExports = moduleDefault || exports;
389
+ // update the module record
390
+ // copy over enumerable public methods to module
391
+ for (const key in moduleExports) {
392
+ Object.defineProperty(moduleRecord.module, key, {
393
+ enumerable: true,
394
+ set(value) {
395
+ moduleExports[key] = value;
396
+ },
397
+ get() {
398
+ return moduleExports[key];
399
+ },
400
+ });
401
+ }
402
+ // copy non-enumerable to module
403
+ if (moduleExports.__useDefault) {
404
+ Object.defineProperty(moduleRecord.module, '__useDefault', { value: true });
405
+ }
406
+ if (moduleExports.__defaultInterop) {
407
+ Object.defineProperty(moduleRecord.module, '__defaultInterop', { value: true });
408
+ }
409
+ if (moduleExports.__esModule) {
410
+ Object.defineProperty(moduleRecord.module, '__esModule', { value: true });
411
+ }
412
+ moduleRecord.evaluated = true;
413
+ Object.freeze(moduleRecord.module);
414
+ return moduleRecord.module;
415
+ }
416
+ // Determines if named exports module has only default export
417
+ isNamedExportDefaultOnly(exports) {
418
+ return (exports !== undefined &&
419
+ Object.getOwnPropertyNames(exports).length === 2 &&
420
+ Object.prototype.hasOwnProperty.call(exports, 'default') &&
421
+ Object.prototype.hasOwnProperty.call(exports, '__esModule'));
422
+ }
423
+ // Wrap the dependency in a function that can be called and detected by __circular__ property.
424
+ // The LWC engine checks for __circular__ to detect circular dependencies.
425
+ getCircularDependencyWrapper(module) {
426
+ const tmp = () => {
427
+ return module.__useDefault || module.__defaultInterop ? module.default : module;
428
+ };
429
+ tmp.__circular__ = true;
430
+ return tmp;
431
+ }
432
+ async evaluateModuleDependencies(dependencyModuleRecords, evaluationMap) {
433
+ for (let i = 0; i < dependencyModuleRecords.length; i++) {
434
+ const depRecord = dependencyModuleRecords[i];
435
+ if (!depRecord.evaluated && !evaluationMap[depRecord.id]) {
436
+ evaluationMap[depRecord.id] = true;
437
+ // eslint-disable-next-line no-await-in-loop
438
+ await this.evaluateModule(depRecord, evaluationMap);
439
+ }
440
+ }
441
+ }
442
+ async getModuleDef(resolvedId, originalId) {
443
+ // reset lastDefine
444
+ this.lastDefine = undefined;
445
+ // the module name can be the resolved ID or the original ID if neither are URL's.
446
+ const moduleName = !isUrl(resolvedId)
447
+ ? resolvedId
448
+ : originalId !== resolvedId
449
+ ? originalId
450
+ : undefined;
451
+ let moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
452
+ if (moduleDef && moduleDef.external) {
453
+ return moduleDef.external.moduleDefPromise;
454
+ }
455
+ if (moduleDef && moduleDef.defined) {
456
+ return moduleDef;
457
+ }
458
+ const parentUrl = this.baseUrl; // only support baseUrl for now
459
+ const specifier = moduleName || originalId;
460
+ this.profiler.logOperationStart({ id: MODULE_FETCH, specifier });
461
+ return Promise.resolve()
462
+ .then(async () => {
463
+ const loadHooks = this.loadHook;
464
+ if (loadHooks) {
465
+ for (let i = 0; i < loadHooks.length; i++) {
466
+ const loadHook = loadHooks[i];
467
+ const response = loadHook(resolvedId, parentUrl);
468
+ const result = (isResponseAPromise(response)
469
+ ? // eslint-disable-next-line no-await-in-loop
470
+ await evaluateLoadHook(resolvedId, response)
471
+ : response);
472
+ if (result === undefined) {
473
+ throw new LoaderError(INVALID_LOADER_SERVICE_RESPONSE);
474
+ }
475
+ if (result && result !== null) {
476
+ return evaluateLoadHookResponse(result, resolvedId);
477
+ }
478
+ }
479
+ }
480
+ return false;
481
+ })
482
+ .then((result) => {
483
+ if (result !== true && hasDocument) {
484
+ return loadModuleDef(resolvedId);
485
+ }
486
+ })
487
+ .then(() => {
488
+ // Attempt to retrieve the module definition by name first
489
+ moduleDef = moduleName && this.namedDefineRegistry.get(moduleName);
490
+ // Fallback to the last loader.define call
491
+ if (!moduleDef) {
492
+ moduleDef = this.lastDefine;
493
+ }
494
+ // This should not happen
495
+ if (!moduleDef) {
496
+ throw new LoaderError(FAIL_INSTANTIATE, [resolvedId]);
497
+ }
498
+ this.profiler.logOperationEnd({ id: MODULE_FETCH, specifier });
499
+ return moduleDef;
500
+ })
501
+ .catch((e) => {
502
+ // Create module error marks for all errors caused by the loader
503
+ // Note: these marks do not include errors caused by invalid server responses or loader hooks
504
+ if (!(e instanceof LoaderError)) {
505
+ this.profiler.logOperationStart({ id: MODULE_ERROR, specifier });
506
+ }
507
+ throw e;
508
+ });
509
+ }
510
+ addLoaderPlugin(hooks) {
511
+ if (typeof hooks !== 'object') {
512
+ throw new LoaderError(INVALID_HOOK);
513
+ }
514
+ const { loadModule: loadHook, resolveModule: resolveHook } = hooks;
515
+ if (resolveHook) {
516
+ if (this.resolveHook) {
517
+ this.resolveHook.push(resolveHook);
518
+ }
519
+ else {
520
+ this.resolveHook = [resolveHook];
521
+ }
522
+ }
523
+ if (loadHook) {
524
+ if (this.loadHook) {
525
+ this.loadHook.push(loadHook);
526
+ }
527
+ else {
528
+ this.loadHook = [loadHook];
529
+ }
530
+ }
531
+ }
532
+ registerHandleStaleModuleHook(handleStaleModule) {
533
+ if (this.handleStaleModuleHook) {
534
+ this.handleStaleModuleHook.push(handleStaleModule);
535
+ }
536
+ else {
537
+ this.handleStaleModuleHook = [handleStaleModule];
538
+ }
539
+ }
540
+ isValidResolveResponse(res) {
541
+ return (res === null || typeof res === 'string' || (res && typeof res.url === 'string'));
542
+ }
543
+ }
544
+ //# sourceMappingURL=moduleRegistry.js.map
@@ -0,0 +1,3 @@
1
+ declare function loadModuleDef(url: string): Promise<void>;
2
+ export { loadModuleDef };
3
+ //# sourceMappingURL=scriptLoad.d.ts.map
@@ -0,0 +1,43 @@
1
+ import { LoaderError, FAIL_LOAD } from '../errors/messages.js';
2
+ import { hasDocument } from '../utils/dom.js';
3
+ function createScript(url) {
4
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
5
+ const script = document.createElement('script');
6
+ script.async = true;
7
+ script.crossOrigin = 'anonymous';
8
+ script.src = url;
9
+ return script;
10
+ }
11
+ let lastWindowError, lastWindowErrorUrl;
12
+ function loadModuleDef(url) {
13
+ return new Promise(function (resolve, reject) {
14
+ if (hasDocument) {
15
+ /* eslint-disable lwr/no-unguarded-apis, no-undef */
16
+ const script = createScript(url);
17
+ script.addEventListener('error', () => {
18
+ reject(new LoaderError(FAIL_LOAD, [url]));
19
+ });
20
+ script.addEventListener('load', () => {
21
+ document.head.removeChild(script);
22
+ if (lastWindowErrorUrl === url) {
23
+ reject(lastWindowError);
24
+ }
25
+ else {
26
+ resolve();
27
+ }
28
+ });
29
+ document.head.appendChild(script);
30
+ /* eslint-enable lwr/no-unguarded-apis, no-undef */
31
+ }
32
+ });
33
+ }
34
+ if (hasDocument) {
35
+ // When a script is executed, runtime errors are on the global/window scope which are NOT caught by the script's onerror handler.
36
+ // eslint-disable-next-line lwr/no-unguarded-apis, no-undef
37
+ window.addEventListener('error', (evt) => {
38
+ lastWindowErrorUrl = evt.filename;
39
+ lastWindowError = evt.error;
40
+ });
41
+ }
42
+ export { loadModuleDef };
43
+ //# sourceMappingURL=scriptLoad.js.map
@@ -0,0 +1,4 @@
1
+ export declare const hasDocument: boolean;
2
+ export declare const hasSetTimeout: boolean;
3
+ export declare const hasConsole: boolean;
4
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1,6 @@
1
+ /* eslint-disable lwr/no-unguarded-apis */
2
+ export const hasDocument = typeof document !== 'undefined';
3
+ export const hasSetTimeout = typeof setTimeout === 'function';
4
+ export const hasConsole = typeof console !== 'undefined';
5
+ /* eslint-enable lwr/no-unguarded-apis */
6
+ //# sourceMappingURL=dom.js.map
@@ -0,0 +1,28 @@
1
+ export declare function getBaseUrl(): string | undefined;
2
+ /**
3
+ * Check if a string is a URL based on Common Internet Scheme Syntax
4
+ * https://www.ietf.org/rfc/rfc1738.txt
5
+ *
6
+ * URL Format:
7
+ * <scheme>:<scheme-specific-part>
8
+ * Common Internet Scheme Syntax:
9
+ * The scheme specific part starts with a double slash('//')
10
+ *
11
+ * A valid URL has a colon that is followed by a double slash.
12
+ *
13
+ * @param url - the url that is being checked
14
+ * @returns boolean
15
+ *
16
+ * @example Valid URLs
17
+ * 'https://salesforce.com'
18
+ * 'http://localhost:3000'
19
+ *
20
+ * @example Invalid URLs
21
+ * 'salesforce.com'
22
+ * 'localhost:3000'
23
+ * '@salesforce/label/type:namespace:name'
24
+ */
25
+ export declare function isUrl(url: string): boolean;
26
+ export declare function resolveIfNotPlainOrUrl(relUrl: string, parentUrl: string): string | undefined;
27
+ export declare function resolveUrl(relUrl: string, parentUrl: string): string | undefined;
28
+ //# sourceMappingURL=url.d.ts.map