@lwrjs/view-registry 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.
- package/build/cjs/index.cjs +18 -11
- package/build/cjs/linkers/legacy_view_bootstrap.cjs +32 -10
- package/build/cjs/linkers/preload-utils.cjs +6 -3
- package/build/cjs/linkers/utils.cjs +7 -0
- package/build/cjs/linkers/view_bootstrap.cjs +25 -10
- package/build/cjs/utils.cjs +47 -7
- package/build/cjs/view-handler.cjs +9 -1
- package/build/es/index.js +25 -11
- package/build/es/linkers/legacy_view_bootstrap.js +38 -13
- package/build/es/linkers/preload-utils.d.ts +2 -1
- package/build/es/linkers/preload-utils.js +8 -5
- package/build/es/linkers/utils.d.ts +2 -1
- package/build/es/linkers/utils.js +7 -1
- package/build/es/linkers/view_bootstrap.js +28 -11
- package/build/es/utils.d.ts +13 -1
- package/build/es/utils.js +53 -7
- package/build/es/view-handler.js +12 -1
- package/package.json +11 -8
package/build/cjs/index.cjs
CHANGED
|
@@ -57,7 +57,7 @@ var LwrViewRegistry = class {
|
|
|
57
57
|
observer.onAssetSourceChange(({payload}) => this.onAssetSourceChange(payload));
|
|
58
58
|
}
|
|
59
59
|
async onModuleDefinitionChange(moduleDefinition) {
|
|
60
|
-
if (
|
|
60
|
+
if ((0, import_shared_utils.isLocalDev)()) {
|
|
61
61
|
this.viewDefinitions.clear();
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
@@ -80,7 +80,7 @@ var LwrViewRegistry = class {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
async onViewSourceChange(compiledView) {
|
|
83
|
-
if (
|
|
83
|
+
if ((0, import_shared_utils.isLocalDev)()) {
|
|
84
84
|
this.viewDefinitions.clear();
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
@@ -161,7 +161,8 @@ var LwrViewRegistry = class {
|
|
|
161
161
|
freezeAssets,
|
|
162
162
|
locale: runtimeParams?.locale,
|
|
163
163
|
basePath: runtimeParams?.basePath,
|
|
164
|
-
debug: runtimeEnvironment.debug
|
|
164
|
+
debug: runtimeEnvironment.debug,
|
|
165
|
+
nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
|
|
165
166
|
});
|
|
166
167
|
import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
|
|
167
168
|
const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
|
|
@@ -182,7 +183,8 @@ var LwrViewRegistry = class {
|
|
|
182
183
|
freezeAssets,
|
|
183
184
|
locale: runtimeParams?.locale,
|
|
184
185
|
basePath: runtimeParams?.basePath,
|
|
185
|
-
debug: runtimeEnvironment.debug
|
|
186
|
+
debug: runtimeEnvironment.debug,
|
|
187
|
+
nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
|
|
186
188
|
});
|
|
187
189
|
import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
|
|
188
190
|
const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
|
|
@@ -194,6 +196,8 @@ var LwrViewRegistry = class {
|
|
|
194
196
|
return viewDefinition2.viewDefinition;
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
const updatableViewParams = {...viewParams};
|
|
200
|
+
(0, import_utils.generateViewNonce)(updatableViewParams);
|
|
197
201
|
const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
|
|
198
202
|
const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
|
|
199
203
|
name: import_instrumentation.ViewSpan.RenderView,
|
|
@@ -201,10 +205,12 @@ var LwrViewRegistry = class {
|
|
|
201
205
|
view: view.id,
|
|
202
206
|
ssr: view.bootstrap?.ssr === true
|
|
203
207
|
}
|
|
204
|
-
}, () => this.renderView(view,
|
|
208
|
+
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
|
|
209
|
+
viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
|
|
205
210
|
if (cacheDisabled === false) {
|
|
206
211
|
const route = this.globalConfig.routes.find((r) => r.id === view.id);
|
|
207
|
-
const
|
|
212
|
+
const maxTtl = process.env.MAX_VIEW_CACHE_TTL && parseInt(process.env.MAX_VIEW_CACHE_TTL, 10);
|
|
213
|
+
const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
|
|
208
214
|
if (ttl !== 0) {
|
|
209
215
|
this.viewDefinitions.set(viewDefCacheKey, {
|
|
210
216
|
view,
|
|
@@ -227,7 +233,7 @@ var LwrViewRegistry = class {
|
|
|
227
233
|
async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
|
|
228
234
|
const {id, contentTemplate, rootComponent, layoutTemplate} = view;
|
|
229
235
|
const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
|
|
230
|
-
const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, renderOptions);
|
|
236
|
+
const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment, renderOptions);
|
|
231
237
|
let normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedContent.options, renderOptions);
|
|
232
238
|
const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
|
|
233
239
|
if (!layout) {
|
|
@@ -247,7 +253,7 @@ var LwrViewRegistry = class {
|
|
|
247
253
|
...viewParams,
|
|
248
254
|
body: renderedContent.renderedView,
|
|
249
255
|
lwr_resources: lwrResourcesId
|
|
250
|
-
}, runtimeParams);
|
|
256
|
+
}, runtimeParams, runtimeEnvironment);
|
|
251
257
|
normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
|
|
252
258
|
const renderedViewDef = await this.link({
|
|
253
259
|
...renderedLayout,
|
|
@@ -285,7 +291,7 @@ var LwrViewRegistry = class {
|
|
|
285
291
|
});
|
|
286
292
|
return renderedViewDef;
|
|
287
293
|
}
|
|
288
|
-
async render(viewId, viewParams, runtimeParams, renderOptions) {
|
|
294
|
+
async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
|
|
289
295
|
const globalContext = this.globalData;
|
|
290
296
|
const {id, rootComponent, contentTemplate} = viewId;
|
|
291
297
|
const compiledView = await this.getView({id, contentTemplate, rootComponent}, renderOptions?.skipCaching);
|
|
@@ -294,7 +300,7 @@ var LwrViewRegistry = class {
|
|
|
294
300
|
...globalContext,
|
|
295
301
|
...compiledView.properties,
|
|
296
302
|
...viewParams
|
|
297
|
-
});
|
|
303
|
+
}, runtimeEnvironment);
|
|
298
304
|
const normalizedResult = (0, import_utils.normalizeRenderedResult)(result);
|
|
299
305
|
return {
|
|
300
306
|
compiledView,
|
|
@@ -360,7 +366,8 @@ var LwrViewRegistry = class {
|
|
|
360
366
|
renderedView: linkedAssetContent,
|
|
361
367
|
immutable,
|
|
362
368
|
viewRecord: {
|
|
363
|
-
assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences)
|
|
369
|
+
assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
|
|
370
|
+
moduleResources: []
|
|
364
371
|
},
|
|
365
372
|
cache: {ttl: pageTtl}
|
|
366
373
|
};
|
|
@@ -49,9 +49,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
49
49
|
resourceRegistry,
|
|
50
50
|
viewMetadata
|
|
51
51
|
} = resourceContext;
|
|
52
|
-
const {
|
|
52
|
+
const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
|
|
53
53
|
const {customElements, serverData, serverDebug} = viewMetadata;
|
|
54
|
-
const version = lwrVersion;
|
|
55
54
|
const isAMD = format === "amd";
|
|
56
55
|
const {bundleConfig} = resourceContext;
|
|
57
56
|
const {external = {}, exclude = []} = bundleConfig;
|
|
@@ -98,9 +97,12 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
98
97
|
const viewPreloads = {
|
|
99
98
|
uris: [],
|
|
100
99
|
specifiers: [],
|
|
101
|
-
groups: new Map()
|
|
100
|
+
groups: new Map(),
|
|
101
|
+
integrities: new Map()
|
|
102
102
|
};
|
|
103
103
|
const isSSR = view.bootstrap?.ssr;
|
|
104
|
+
const version = view.bootstrap?.lwrVersion;
|
|
105
|
+
const nonce = (0, import_utils.getViewNonce)(viewParams);
|
|
104
106
|
let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
|
|
105
107
|
const customElementsRecords = [];
|
|
106
108
|
const flattenedElements = (0, import_utils2.flattenCustomElements)(customElements, isSSR);
|
|
@@ -125,6 +127,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
125
127
|
if (!def.inline && !def.src) {
|
|
126
128
|
throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
|
|
127
129
|
}
|
|
130
|
+
(0, import_utils.addExternalScriptNonce)(def, nonce);
|
|
128
131
|
requiredResources.push(def);
|
|
129
132
|
const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
|
|
130
133
|
if (!errorShimDef) {
|
|
@@ -133,6 +136,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
133
136
|
if (!errorShimDef.inline && !errorShimDef.src) {
|
|
134
137
|
throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
|
|
135
138
|
}
|
|
139
|
+
(0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
|
|
136
140
|
requiredResources.push(errorShimDef);
|
|
137
141
|
}
|
|
138
142
|
const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
@@ -146,11 +150,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
146
150
|
if (!uri) {
|
|
147
151
|
throw Error(`Invalid Module Resource ${versionedSpecifier}`);
|
|
148
152
|
}
|
|
149
|
-
|
|
153
|
+
const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
|
|
154
|
+
moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
|
|
150
155
|
for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
|
|
151
156
|
const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
|
|
152
157
|
if (uri2) {
|
|
153
|
-
(0,
|
|
158
|
+
const integrity2 = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, depSpecifier);
|
|
159
|
+
(0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, integrity2, groups, viewPreloads);
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
if ((0, import_shared_utils.isBundler)(defRegistry)) {
|
|
@@ -187,12 +193,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
187
193
|
if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
|
|
188
194
|
const specifier = graph.graphs[0].specifier;
|
|
189
195
|
const uri = graph.uriMap[specifier];
|
|
190
|
-
(0,
|
|
196
|
+
const integrity = (0, import_utils2.getBundleIntegrity)(graph, specifier);
|
|
197
|
+
(0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, integrity, groups, viewPreloads);
|
|
191
198
|
if (bundle) {
|
|
192
199
|
for (const depSpecifier of graph.graphs[0].static) {
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
(0,
|
|
200
|
+
const depUri = getPreloadUri(depSpecifier, graph.uriMap);
|
|
201
|
+
if (depUri) {
|
|
202
|
+
const integrity2 = (0, import_utils2.getBundleIntegrity)(graph, depSpecifier);
|
|
203
|
+
(0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, depUri, integrity2, groups, viewPreloads);
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
206
|
}
|
|
@@ -211,6 +219,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
211
219
|
}
|
|
212
220
|
}));
|
|
213
221
|
if (viewContainsLiveElements) {
|
|
222
|
+
if ((0, import_shared_utils.isLocalDev)()) {
|
|
223
|
+
const localDevSpecifier = "lwr_local_dev/bootstrap";
|
|
224
|
+
rootComponents.push(localDevSpecifier);
|
|
225
|
+
const localDevMod = await (0, import_utils.getModuleResource)({specifier: localDevSpecifier, version: ""}, runtimeEnvironment, {}, moduleRegistry, runtimeParams);
|
|
226
|
+
if (localDevMod.src)
|
|
227
|
+
imports[localDevSpecifier] = localDevMod.src;
|
|
228
|
+
}
|
|
214
229
|
configResources.unshift((0, import_utils2.getViewBootstrapConfigurationResource)({
|
|
215
230
|
id: view.id,
|
|
216
231
|
url: viewParams?.page?.url,
|
|
@@ -235,7 +250,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
235
250
|
}
|
|
236
251
|
const dedupedUris = [...new Set(viewPreloads.uris)];
|
|
237
252
|
for (const preloadUri of dedupedUris) {
|
|
238
|
-
|
|
253
|
+
const integrity = viewPreloads.integrities.get(preloadUri);
|
|
254
|
+
moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
|
|
255
|
+
integrity,
|
|
256
|
+
isPreload: true,
|
|
257
|
+
isSSR,
|
|
258
|
+
nonce
|
|
259
|
+
}));
|
|
239
260
|
}
|
|
240
261
|
const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
|
|
241
262
|
return {
|
|
@@ -243,6 +264,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
243
264
|
viewRecord: {
|
|
244
265
|
resources: requiredResources,
|
|
245
266
|
customElements: customElementsRecords,
|
|
267
|
+
moduleResources,
|
|
246
268
|
bootstrapModule: bootstrapModuleRef
|
|
247
269
|
}
|
|
248
270
|
};
|
|
@@ -29,7 +29,7 @@ __export(exports, {
|
|
|
29
29
|
});
|
|
30
30
|
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
31
31
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
32
|
-
function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
32
|
+
function setPreloadModulesMeta(specifier, uri, integrity, groups, preloads) {
|
|
33
33
|
if (!uri) {
|
|
34
34
|
throw (0, import_diagnostics.createSingleDiagnosticError)({
|
|
35
35
|
description: import_diagnostics.descriptions.UNRESOLVABLE.PRELOAD_MODULE(specifier)
|
|
@@ -41,6 +41,7 @@ function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
|
41
41
|
const preloadModulesSpecifiers = preloads.specifiers;
|
|
42
42
|
const preloadBundleGroupsMap = preloads.groups;
|
|
43
43
|
const preloadModulesURIs = preloads.uris;
|
|
44
|
+
const preloadModuleIntegrities = preloads.integrities;
|
|
44
45
|
preloadModulesSpecifiers.push(specifier);
|
|
45
46
|
const {specifier: unversionedSpecifier} = (0, import_shared_utils.explodeSpecifier)(specifier);
|
|
46
47
|
const groupName = (0, import_shared_utils.getGroupName)(unversionedSpecifier, groups);
|
|
@@ -49,6 +50,7 @@ function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
|
49
50
|
}
|
|
50
51
|
preloadModulesURIs.push(uri);
|
|
51
52
|
groupName && preloadBundleGroupsMap.set(groupName, true);
|
|
53
|
+
preloadModuleIntegrities.set(uri, integrity);
|
|
52
54
|
}
|
|
53
55
|
async function getPreloadModulesMeta(specifier, viewPreloads, bundleConfig, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, pending) {
|
|
54
56
|
const {exclude = [], external = {}, groups = {}} = bundleConfig;
|
|
@@ -72,9 +74,10 @@ async function getPreloadModulesMeta(specifier, viewPreloads, bundleConfig, modu
|
|
|
72
74
|
});
|
|
73
75
|
const uri = await defRegistry.resolveModuleUri(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
74
76
|
const normalizedSpecifier = versionedModuleId.version === import_shared_utils.VERSION_NOT_PROVIDED ? specifier : versionedModuleSpecifier;
|
|
75
|
-
|
|
77
|
+
const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
78
|
+
const {integrity} = preloadModuleRecord;
|
|
79
|
+
setPreloadModulesMeta(normalizedSpecifier, uri, integrity, groups, viewPreloads);
|
|
76
80
|
if (exclude.length || Object.keys(groups).length) {
|
|
77
|
-
const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
78
81
|
const {imports} = preloadModuleRecord.bundleRecord;
|
|
79
82
|
if (imports) {
|
|
80
83
|
if (!pending) {
|
|
@@ -25,6 +25,7 @@ var __toModule = (module2) => {
|
|
|
25
25
|
__markAsModule(exports);
|
|
26
26
|
__export(exports, {
|
|
27
27
|
flattenCustomElements: () => flattenCustomElements,
|
|
28
|
+
getBundleIntegrity: () => getBundleIntegrity,
|
|
28
29
|
getViewBootstrapConfigurationResource: () => getViewBootstrapConfigurationResource,
|
|
29
30
|
getViewHmrConfigurationResource: () => getViewHmrConfigurationResource
|
|
30
31
|
});
|
|
@@ -72,6 +73,7 @@ function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironm
|
|
|
72
73
|
type: CONTENT_TYPE,
|
|
73
74
|
content: configString,
|
|
74
75
|
inline: false,
|
|
76
|
+
integrity: (0, import_shared_utils.createIntegrityHash)(configString),
|
|
75
77
|
src: url
|
|
76
78
|
};
|
|
77
79
|
} else {
|
|
@@ -129,3 +131,8 @@ function flattenCustomElements(arr, isSSR = false) {
|
|
|
129
131
|
flatten(arr);
|
|
130
132
|
return ret;
|
|
131
133
|
}
|
|
134
|
+
function getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier) {
|
|
135
|
+
const def = bootstrapModuleGraph.linkedDefinitions[versionedSpecifier];
|
|
136
|
+
const integrity = def?.integrity;
|
|
137
|
+
return integrity;
|
|
138
|
+
}
|
|
@@ -41,10 +41,9 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
41
41
|
resourceRegistry,
|
|
42
42
|
viewMetadata
|
|
43
43
|
} = resourceContext;
|
|
44
|
-
const {
|
|
44
|
+
const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
|
|
45
45
|
const {customElements, serverData, serverDebug} = viewMetadata;
|
|
46
46
|
const defRegistry = bundle ? moduleBundler : moduleRegistry;
|
|
47
|
-
const version = lwrVersion;
|
|
48
47
|
const isAMD = format === "amd";
|
|
49
48
|
const depth = isAMD ? {static: import_shared_utils.GraphDepth.ALL, dynamic: 1} : {static: import_shared_utils.GraphDepth.NONE, dynamic: 1};
|
|
50
49
|
const {bundleConfig} = resourceContext;
|
|
@@ -87,9 +86,12 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
87
86
|
const viewPreloads = {
|
|
88
87
|
uris: [],
|
|
89
88
|
specifiers: [],
|
|
90
|
-
groups: new Map()
|
|
89
|
+
groups: new Map(),
|
|
90
|
+
integrities: new Map()
|
|
91
91
|
};
|
|
92
92
|
const isSSR = view.bootstrap?.ssr;
|
|
93
|
+
const version = view.bootstrap?.lwrVersion;
|
|
94
|
+
const nonce = (0, import_utils.getViewNonce)(viewParams);
|
|
93
95
|
let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
|
|
94
96
|
let importMetadata = {imports: {}};
|
|
95
97
|
const customElementsRecords = [];
|
|
@@ -105,6 +107,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
105
107
|
if (!def.inline && !def.src) {
|
|
106
108
|
throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
|
|
107
109
|
}
|
|
110
|
+
(0, import_utils.addExternalScriptNonce)(def, nonce);
|
|
108
111
|
requiredResources.push(def);
|
|
109
112
|
const errorShimDef = await resourceRegistry.getResource({specifier: "lwr-error-shim.js", version}, runtimeEnvironment, runtimeParams);
|
|
110
113
|
if (!errorShimDef) {
|
|
@@ -113,6 +116,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
113
116
|
if (!errorShimDef.inline && !errorShimDef.src) {
|
|
114
117
|
throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
|
|
115
118
|
}
|
|
119
|
+
(0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
|
|
116
120
|
requiredResources.push(errorShimDef);
|
|
117
121
|
}
|
|
118
122
|
const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
@@ -126,11 +130,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
126
130
|
if (!uri) {
|
|
127
131
|
throw Error(`Invalid Module Resource ${versionedSpecifier}`);
|
|
128
132
|
}
|
|
129
|
-
|
|
133
|
+
const integrity = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, versionedSpecifier);
|
|
134
|
+
moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {integrity, isPreload: false, isSSR, nonce}));
|
|
130
135
|
for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
|
|
131
136
|
const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
|
|
132
137
|
if (uri2) {
|
|
133
|
-
(0,
|
|
138
|
+
const integrity2 = (0, import_utils2.getBundleIntegrity)(bootstrapModuleGraph, depSpecifier);
|
|
139
|
+
(0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, integrity2, groups, viewPreloads);
|
|
134
140
|
}
|
|
135
141
|
}
|
|
136
142
|
if ((0, import_shared_utils.isBundler)(defRegistry)) {
|
|
@@ -168,12 +174,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
168
174
|
if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
|
|
169
175
|
const specifier = graph.graphs[0].specifier;
|
|
170
176
|
const uri = graph.uriMap[specifier];
|
|
171
|
-
(0,
|
|
177
|
+
const integrity = (0, import_utils2.getBundleIntegrity)(graph, specifier);
|
|
178
|
+
(0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, integrity, groups, viewPreloads);
|
|
172
179
|
if (bundle) {
|
|
173
180
|
for (const depSpecifier of graph.graphs[0].static) {
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
176
|
-
(0,
|
|
181
|
+
const depUri = getPreloadUri(depSpecifier, graph.uriMap);
|
|
182
|
+
if (depUri) {
|
|
183
|
+
const integrity2 = (0, import_utils2.getBundleIntegrity)(graph, depSpecifier);
|
|
184
|
+
(0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, depUri, integrity2, groups, viewPreloads);
|
|
177
185
|
}
|
|
178
186
|
}
|
|
179
187
|
}
|
|
@@ -215,7 +223,13 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
215
223
|
}
|
|
216
224
|
const dedupedUris = [...new Set(viewPreloads.uris)];
|
|
217
225
|
for (const preloadUri of dedupedUris) {
|
|
218
|
-
|
|
226
|
+
const integrity = viewPreloads.integrities.get(preloadUri);
|
|
227
|
+
moduleResources.push((0, import_utils.getModuleResourceByUri)(preloadUri, runtimeEnvironment, {
|
|
228
|
+
integrity,
|
|
229
|
+
isPreload: true,
|
|
230
|
+
isSSR,
|
|
231
|
+
nonce
|
|
232
|
+
}));
|
|
219
233
|
}
|
|
220
234
|
const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(import_utils.generateHtmlTag));
|
|
221
235
|
const mapping = (0, import_shared_utils.getMappingUriPrefix)(runtimeEnvironment, runtimeParams);
|
|
@@ -231,6 +245,7 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
231
245
|
customElements: customElementsRecords,
|
|
232
246
|
endpoints,
|
|
233
247
|
importMetadata,
|
|
248
|
+
moduleResources,
|
|
234
249
|
bootstrapModule: bootstrapModuleRef
|
|
235
250
|
}
|
|
236
251
|
};
|
package/build/cjs/utils.cjs
CHANGED
|
@@ -24,11 +24,14 @@ var __toModule = (module2) => {
|
|
|
24
24
|
// packages/@lwrjs/view-registry/src/utils.ts
|
|
25
25
|
__markAsModule(exports);
|
|
26
26
|
__export(exports, {
|
|
27
|
+
addExternalScriptNonce: () => addExternalScriptNonce,
|
|
27
28
|
createJsonModule: () => createJsonModule,
|
|
28
29
|
generateHtmlTag: () => generateHtmlTag,
|
|
29
30
|
generatePageContext: () => generatePageContext,
|
|
31
|
+
generateViewNonce: () => generateViewNonce,
|
|
30
32
|
getModuleResource: () => getModuleResource,
|
|
31
33
|
getModuleResourceByUri: () => getModuleResourceByUri,
|
|
34
|
+
getViewNonce: () => getViewNonce,
|
|
32
35
|
isViewResponse: () => isViewResponse,
|
|
33
36
|
normalizeRenderOptions: () => normalizeRenderOptions,
|
|
34
37
|
normalizeRenderedResult: () => normalizeRenderedResult,
|
|
@@ -38,17 +41,26 @@ __export(exports, {
|
|
|
38
41
|
var import_path = __toModule(require("path"));
|
|
39
42
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
40
43
|
var import_identity = __toModule(require("@lwrjs/app-service/identity"));
|
|
44
|
+
var import_crypto = __toModule(require("crypto"));
|
|
41
45
|
function generateExternalStyle(src) {
|
|
42
46
|
return `<link rel="stylesheet" href="${src}">`;
|
|
43
47
|
}
|
|
44
|
-
function generateExternalScript(type = "application/javascript", src, async, defer) {
|
|
48
|
+
function generateExternalScript(type = "application/javascript", src, async, defer, nonce, integrity) {
|
|
45
49
|
let scriptLoadOrder = "";
|
|
46
50
|
if (defer) {
|
|
47
51
|
scriptLoadOrder = " defer";
|
|
48
52
|
} else if (async) {
|
|
49
53
|
scriptLoadOrder = " async";
|
|
50
54
|
}
|
|
51
|
-
|
|
55
|
+
let cspHashAttr = "";
|
|
56
|
+
if ((0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE) {
|
|
57
|
+
if (integrity) {
|
|
58
|
+
cspHashAttr = ` integrity="${integrity}"`;
|
|
59
|
+
} else if (nonce) {
|
|
60
|
+
cspHashAttr = ` nonce="${nonce}"`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return `<script type="${type}"${scriptLoadOrder}${cspHashAttr} src="${src}"></script>`;
|
|
52
64
|
}
|
|
53
65
|
function generateLinkPreloadTag({href, type}) {
|
|
54
66
|
if (type === "module") {
|
|
@@ -57,19 +69,27 @@ function generateLinkPreloadTag({href, type}) {
|
|
|
57
69
|
return `<link rel="preload" href="${href}" type="${type}" />`;
|
|
58
70
|
}
|
|
59
71
|
}
|
|
60
|
-
function generateExternalTag({
|
|
72
|
+
function generateExternalTag({
|
|
73
|
+
type,
|
|
74
|
+
src = "",
|
|
75
|
+
async,
|
|
76
|
+
defer,
|
|
77
|
+
isPreload,
|
|
78
|
+
nonce,
|
|
79
|
+
integrity
|
|
80
|
+
}) {
|
|
61
81
|
if (isPreload) {
|
|
62
82
|
return generateLinkPreloadTag({href: src, type});
|
|
63
83
|
} else if (type === "text/css") {
|
|
64
84
|
return generateExternalStyle(src);
|
|
65
85
|
} else {
|
|
66
|
-
return generateExternalScript(type, src, async, defer);
|
|
86
|
+
return generateExternalScript(type, src, async, defer, nonce, integrity);
|
|
67
87
|
}
|
|
68
88
|
}
|
|
69
89
|
async function generateInlineTag({specifier, type, content, stream, nonce}) {
|
|
70
90
|
const typeStr = type === "text/css" ? "" : ` type="${type}"`;
|
|
71
91
|
const tag = type === "text/css" ? "style" : "script";
|
|
72
|
-
const nonceStr = nonce ? ` nonce="${nonce}"` : "";
|
|
92
|
+
const nonceStr = (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : "";
|
|
73
93
|
if (!content && !stream) {
|
|
74
94
|
throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
|
|
75
95
|
}
|
|
@@ -223,14 +243,16 @@ async function getModuleResource(moduleId, runtimeEnvironment, moduleResourceMet
|
|
|
223
243
|
};
|
|
224
244
|
}
|
|
225
245
|
function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
|
|
226
|
-
const {isSSR = false, isPreload = false} = moduleResourceMeta;
|
|
246
|
+
const {integrity, isSSR = false, isPreload = false, nonce} = moduleResourceMeta;
|
|
227
247
|
const {format} = runtimeEnvironment;
|
|
228
248
|
return {
|
|
229
249
|
src: uri,
|
|
230
250
|
type: format === "amd" ? "application/javascript" : "module",
|
|
231
251
|
async: !isSSR && isPreload,
|
|
232
252
|
defer: isSSR,
|
|
233
|
-
isPreload: format !== "amd" && isPreload
|
|
253
|
+
isPreload: format !== "amd" && isPreload,
|
|
254
|
+
integrity,
|
|
255
|
+
nonce
|
|
234
256
|
};
|
|
235
257
|
}
|
|
236
258
|
async function createJsonModule(specifier, moduleRegistry, environment, params) {
|
|
@@ -252,3 +274,21 @@ async function createJsonModule(specifier, moduleRegistry, environment, params)
|
|
|
252
274
|
}
|
|
253
275
|
};
|
|
254
276
|
}
|
|
277
|
+
function getViewNonce(viewParams) {
|
|
278
|
+
return (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE ? viewParams?.page?.nonce : void 0;
|
|
279
|
+
}
|
|
280
|
+
function generateViewNonce(viewParams) {
|
|
281
|
+
if ((0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE) {
|
|
282
|
+
const nonce = import_crypto.default.randomBytes(16).toString("base64");
|
|
283
|
+
if (!viewParams.page) {
|
|
284
|
+
viewParams.page = {nonce};
|
|
285
|
+
} else {
|
|
286
|
+
viewParams.page.nonce = nonce;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function addExternalScriptNonce(def, nonce) {
|
|
291
|
+
if (nonce && (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE && !def.inline) {
|
|
292
|
+
def.nonce = nonce;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -130,6 +130,8 @@ var LwrViewHandler = class {
|
|
|
130
130
|
const paths = {rootDir, assets, contentDir, layoutsDir};
|
|
131
131
|
const locale = runtimeParams.locale;
|
|
132
132
|
const basePath = runtimeParams.basePath;
|
|
133
|
+
const assetBasePath = runtimeParams.assetBasePath;
|
|
134
|
+
const uiBasePath = runtimeParams.assetBasePath;
|
|
133
135
|
const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
|
|
134
136
|
const response = await (0, import_instrumentation.getTracer)().trace({
|
|
135
137
|
name: import_instrumentation.ViewSpan.ExecuteRouteHandler,
|
|
@@ -139,7 +141,7 @@ var LwrViewHandler = class {
|
|
|
139
141
|
}
|
|
140
142
|
}, async () => {
|
|
141
143
|
try {
|
|
142
|
-
return await routeHandlerFn({...viewRequest, locale, basePath}, {route, viewApi, ...paths}, routeHandlerOptions);
|
|
144
|
+
return await routeHandlerFn({...viewRequest, locale, basePath, assetBasePath, uiBasePath}, {route, viewApi, ...paths}, routeHandlerOptions);
|
|
143
145
|
} catch (err) {
|
|
144
146
|
if (err instanceof import_diagnostics.DiagnosticsError) {
|
|
145
147
|
throw err;
|
|
@@ -148,6 +150,9 @@ var LwrViewHandler = class {
|
|
|
148
150
|
throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message)}, import_diagnostics.LwrApplicationError);
|
|
149
151
|
}
|
|
150
152
|
});
|
|
153
|
+
if (response?.locale) {
|
|
154
|
+
runtimeParams.locale = response.locale;
|
|
155
|
+
}
|
|
151
156
|
return response;
|
|
152
157
|
}
|
|
153
158
|
getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams) {
|
|
@@ -164,6 +169,9 @@ var LwrViewHandler = class {
|
|
|
164
169
|
async getViewResponse(viewRequest, route, runtimeEnvironment, runtimeParams = {}, view, viewParams, renderOptions) {
|
|
165
170
|
const {id, bootstrap} = route;
|
|
166
171
|
const managedView = {...view, id, bootstrap};
|
|
172
|
+
if (view.locale) {
|
|
173
|
+
runtimeParams.locale = view.locale;
|
|
174
|
+
}
|
|
167
175
|
const viewResponse = {
|
|
168
176
|
view: managedView,
|
|
169
177
|
viewParams,
|
package/build/es/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getSpecifier, normalizeResourcePath, shortestTtl, } from '@lwrjs/shared-utils';
|
|
1
|
+
import { InflightTasks, createStringBuilder, extractMetadataFromHtml, getCacheKeyFromJson, getFeatureFlags, getSpecifier, isLocalDev, normalizeResourcePath, shortestTtl, } from '@lwrjs/shared-utils';
|
|
2
2
|
import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
|
|
3
|
-
import { normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences } from './utils.js';
|
|
3
|
+
import { generateViewNonce, getViewNonce, normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences, } from './utils.js';
|
|
4
4
|
import { linkLwrResources } from './linkers/link-lwr-resources.js';
|
|
5
|
+
// TODO: investigate perf impact W-16056356
|
|
5
6
|
import { LRUCache } from 'lru-cache';
|
|
6
7
|
import { DiagnosticsError, LwrServerError, createSingleDiagnosticError, descriptions, logger, } from '@lwrjs/diagnostics';
|
|
7
8
|
export { LwrViewHandler } from './view-handler.js';
|
|
@@ -37,7 +38,7 @@ export class LwrViewRegistry {
|
|
|
37
38
|
}
|
|
38
39
|
async onModuleDefinitionChange(moduleDefinition) {
|
|
39
40
|
// TODO we will make this more robust in the future w/ full MRT HMR
|
|
40
|
-
if (
|
|
41
|
+
if (isLocalDev()) {
|
|
41
42
|
this.viewDefinitions.clear();
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
@@ -63,7 +64,7 @@ export class LwrViewRegistry {
|
|
|
63
64
|
}
|
|
64
65
|
async onViewSourceChange(compiledView) {
|
|
65
66
|
// TODO we will make this more robust in the future w/ full MRT HMR
|
|
66
|
-
if (
|
|
67
|
+
if (isLocalDev()) {
|
|
67
68
|
this.viewDefinitions.clear();
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
@@ -150,9 +151,11 @@ export class LwrViewRegistry {
|
|
|
150
151
|
locale: runtimeParams?.locale,
|
|
151
152
|
basePath: runtimeParams?.basePath,
|
|
152
153
|
debug: runtimeEnvironment.debug,
|
|
154
|
+
// Add a variable on if the nonce is enabled
|
|
155
|
+
nonceEnabled: getFeatureFlags().ENABLE_NONCE,
|
|
153
156
|
});
|
|
154
157
|
logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
|
|
155
|
-
// viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing
|
|
158
|
+
// viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
|
|
156
159
|
// to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
|
|
157
160
|
// on every request, while still reusing our caching logic.
|
|
158
161
|
const viewParamKey = viewParamCacheKey
|
|
@@ -177,6 +180,8 @@ export class LwrViewRegistry {
|
|
|
177
180
|
locale: runtimeParams?.locale,
|
|
178
181
|
basePath: runtimeParams?.basePath,
|
|
179
182
|
debug: runtimeEnvironment.debug,
|
|
183
|
+
// Add a variable on if the nonce is enabled
|
|
184
|
+
nonceEnabled: getFeatureFlags().ENABLE_NONCE,
|
|
180
185
|
});
|
|
181
186
|
logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
|
|
182
187
|
// viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
|
|
@@ -196,6 +201,9 @@ export class LwrViewRegistry {
|
|
|
196
201
|
return viewDefinition.viewDefinition;
|
|
197
202
|
}
|
|
198
203
|
}
|
|
204
|
+
// If we missed cache generate a nonce in the page context (we do not want it part of the cache key)
|
|
205
|
+
const updatableViewParams = { ...viewParams };
|
|
206
|
+
generateViewNonce(updatableViewParams);
|
|
199
207
|
const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
|
|
200
208
|
const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
|
|
201
209
|
name: ViewSpan.RenderView,
|
|
@@ -203,10 +211,14 @@ export class LwrViewRegistry {
|
|
|
203
211
|
view: view.id,
|
|
204
212
|
ssr: view.bootstrap?.ssr === true,
|
|
205
213
|
},
|
|
206
|
-
}, () => this.renderView(view,
|
|
214
|
+
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
|
|
215
|
+
// Once the view is generated add the nonce to the response so it can be cached and then added to the headers
|
|
216
|
+
viewDefinition.nonce = getViewNonce(updatableViewParams);
|
|
207
217
|
if (cacheDisabled === false) {
|
|
208
218
|
const route = this.globalConfig.routes.find((r) => r.id === view.id);
|
|
209
|
-
|
|
219
|
+
// optionally set a max TTL on the view registry cache
|
|
220
|
+
const maxTtl = process.env.MAX_VIEW_CACHE_TTL && parseInt(process.env.MAX_VIEW_CACHE_TTL, 10);
|
|
221
|
+
const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
|
|
210
222
|
if (ttl !== 0) {
|
|
211
223
|
// cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
|
|
212
224
|
this.viewDefinitions.set(viewDefCacheKey, {
|
|
@@ -233,7 +245,7 @@ export class LwrViewRegistry {
|
|
|
233
245
|
async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
|
|
234
246
|
const { id, contentTemplate, rootComponent, layoutTemplate } = view;
|
|
235
247
|
const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
|
|
236
|
-
const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, renderOptions);
|
|
248
|
+
const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, runtimeEnvironment, renderOptions);
|
|
237
249
|
// normalize the renderOptions provided by the CompiledView content with the request options.
|
|
238
250
|
let normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedContent.options, renderOptions);
|
|
239
251
|
const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
|
|
@@ -257,7 +269,7 @@ export class LwrViewRegistry {
|
|
|
257
269
|
...viewParams,
|
|
258
270
|
body: renderedContent.renderedView,
|
|
259
271
|
lwr_resources: lwrResourcesId,
|
|
260
|
-
}, runtimeParams);
|
|
272
|
+
}, runtimeParams, runtimeEnvironment);
|
|
261
273
|
normalizedRenderOptions = normalizeRenderOptions(this.runtimeEnvironment, renderedLayout.options, normalizedRenderOptions);
|
|
262
274
|
const renderedViewDef = await this.link({
|
|
263
275
|
...renderedLayout,
|
|
@@ -301,7 +313,7 @@ export class LwrViewRegistry {
|
|
|
301
313
|
});
|
|
302
314
|
return renderedViewDef;
|
|
303
315
|
}
|
|
304
|
-
async render(viewId, viewParams, runtimeParams, renderOptions) {
|
|
316
|
+
async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
|
|
305
317
|
const globalContext = this.globalData;
|
|
306
318
|
const { id, rootComponent, contentTemplate } = viewId;
|
|
307
319
|
const compiledView = await this.getView({ id, contentTemplate, rootComponent }, renderOptions?.skipCaching);
|
|
@@ -320,7 +332,7 @@ export class LwrViewRegistry {
|
|
|
320
332
|
...globalContext,
|
|
321
333
|
...compiledView.properties,
|
|
322
334
|
...viewParams,
|
|
323
|
-
});
|
|
335
|
+
}, runtimeEnvironment);
|
|
324
336
|
const normalizedResult = normalizeRenderedResult(result);
|
|
325
337
|
return {
|
|
326
338
|
compiledView,
|
|
@@ -345,6 +357,7 @@ export class LwrViewRegistry {
|
|
|
345
357
|
importer: importer || renderedView.compiledView.filePath,
|
|
346
358
|
};
|
|
347
359
|
const stringBuilder = createStringBuilder(renderedViewContent);
|
|
360
|
+
// Note: this is the TTL for the page NOT for the view registry cache
|
|
348
361
|
let pageTtl = renderedView.cache.ttl;
|
|
349
362
|
for (const viewTransformer of this.viewTransformers) {
|
|
350
363
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -384,6 +397,7 @@ export class LwrViewRegistry {
|
|
|
384
397
|
immutable,
|
|
385
398
|
viewRecord: {
|
|
386
399
|
assetReferences: reduceSourceAssetReferences(linkedMetadata.assetReferences),
|
|
400
|
+
moduleResources: [],
|
|
387
401
|
},
|
|
388
402
|
cache: { ttl: pageTtl },
|
|
389
403
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { logger } from '@lwrjs/diagnostics';
|
|
2
|
-
import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, } from '@lwrjs/shared-utils';
|
|
2
|
+
import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isExternalSpecifier, isLocalDev, } from '@lwrjs/shared-utils';
|
|
3
3
|
import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
|
|
4
|
-
import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
|
|
5
|
-
import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
4
|
+
import { addExternalScriptNonce, generateHtmlTag, getModuleResource, getModuleResourceByUri, getViewNonce, } from '../utils.js';
|
|
5
|
+
import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
6
6
|
import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
|
|
7
7
|
function includeIdFactory(bundleConfig) {
|
|
8
8
|
return (moduleRef) => {
|
|
@@ -17,9 +17,8 @@ function includeIdFactory(bundleConfig) {
|
|
|
17
17
|
}
|
|
18
18
|
export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
19
19
|
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
|
|
20
|
-
const {
|
|
20
|
+
const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
|
|
21
21
|
const { customElements, serverData, serverDebug } = viewMetadata;
|
|
22
|
-
const version = lwrVersion;
|
|
23
22
|
const isAMD = format === 'amd';
|
|
24
23
|
const { bundleConfig } = resourceContext;
|
|
25
24
|
const { external = {}, exclude = [] } = bundleConfig;
|
|
@@ -89,9 +88,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
89
88
|
uris: [],
|
|
90
89
|
specifiers: [],
|
|
91
90
|
groups: new Map(),
|
|
91
|
+
integrities: new Map(),
|
|
92
92
|
};
|
|
93
93
|
// Determine if server side rendering view modules
|
|
94
94
|
const isSSR = view.bootstrap?.ssr;
|
|
95
|
+
// Determine the LWR client version
|
|
96
|
+
const version = view.bootstrap?.lwrVersion;
|
|
97
|
+
// Page level nonce for script tags
|
|
98
|
+
const nonce = getViewNonce(viewParams);
|
|
95
99
|
// ABS module and custom element references
|
|
96
100
|
let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
|
|
97
101
|
const customElementsRecords = [];
|
|
@@ -107,7 +111,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
107
111
|
let def = (await resourceRegistry.getResource({ specifier: shimBundle, version }, runtimeEnvironment, runtimeParams));
|
|
108
112
|
if (!def) {
|
|
109
113
|
// HACK: fallback to looking for the other shim.
|
|
110
|
-
// TODO: remove this once
|
|
114
|
+
// TODO: remove this once KJ fixes W-15953000
|
|
111
115
|
let fallbackShimBundle;
|
|
112
116
|
if (shimBundle === 'lwr-loader-shim-legacy.bundle.js') {
|
|
113
117
|
fallbackShimBundle = 'lwr-loader-shim-legacy.bundle.min.js';
|
|
@@ -126,6 +130,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
126
130
|
if (!def.inline && !def.src) {
|
|
127
131
|
throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
|
|
128
132
|
}
|
|
133
|
+
addExternalScriptNonce(def, nonce);
|
|
129
134
|
requiredResources.push(def);
|
|
130
135
|
// Always inline the error shim script after the shim
|
|
131
136
|
const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
|
|
@@ -136,6 +141,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
136
141
|
if (!errorShimDef.inline && !errorShimDef.src) {
|
|
137
142
|
throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
|
|
138
143
|
}
|
|
144
|
+
addExternalScriptNonce(errorShimDef, nonce);
|
|
139
145
|
requiredResources.push(errorShimDef);
|
|
140
146
|
}
|
|
141
147
|
// ------- Application Bootstrap module
|
|
@@ -155,12 +161,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
155
161
|
if (!uri) {
|
|
156
162
|
throw Error(`Invalid Module Resource ${versionedSpecifier}`);
|
|
157
163
|
}
|
|
158
|
-
|
|
164
|
+
const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
|
|
165
|
+
moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
|
|
159
166
|
// PRELOAD the bootstrap module static dependencies as preloaded script resources
|
|
160
167
|
for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
|
|
161
168
|
const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
|
|
162
169
|
if (uri) {
|
|
163
|
-
|
|
170
|
+
const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
|
|
171
|
+
setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
|
|
164
172
|
}
|
|
165
173
|
}
|
|
166
174
|
// PRELOAD configured preloadModules as preloaded script resources
|
|
@@ -210,13 +218,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
210
218
|
// PRELOAD the custom element module as a link resource
|
|
211
219
|
const specifier = graph.graphs[0].specifier;
|
|
212
220
|
const uri = graph.uriMap[specifier];
|
|
213
|
-
|
|
221
|
+
const integrity = getBundleIntegrity(graph, specifier);
|
|
222
|
+
setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
|
|
214
223
|
// PRELOAD custom element static deps as link resources when bundling is ON
|
|
215
224
|
if (bundle) {
|
|
216
225
|
for (const depSpecifier of graph.graphs[0].static) {
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
|
|
226
|
+
const depUri = getPreloadUri(depSpecifier, graph.uriMap);
|
|
227
|
+
if (depUri) {
|
|
228
|
+
const integrity = getBundleIntegrity(graph, depSpecifier);
|
|
229
|
+
setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
|
|
220
230
|
}
|
|
221
231
|
}
|
|
222
232
|
}
|
|
@@ -238,6 +248,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
238
248
|
}
|
|
239
249
|
}));
|
|
240
250
|
if (viewContainsLiveElements) {
|
|
251
|
+
if (isLocalDev()) {
|
|
252
|
+
// ADD the client-side bootstrap module and mapping for local-dev
|
|
253
|
+
const localDevSpecifier = 'lwr_local_dev/bootstrap';
|
|
254
|
+
rootComponents.push(localDevSpecifier);
|
|
255
|
+
const localDevMod = await getModuleResource({ specifier: localDevSpecifier, version: '' }, runtimeEnvironment, {}, moduleRegistry, runtimeParams);
|
|
256
|
+
if (localDevMod.src)
|
|
257
|
+
imports[localDevSpecifier] = localDevMod.src;
|
|
258
|
+
}
|
|
241
259
|
// ADD configuration of the bootstrapModule
|
|
242
260
|
configResources.unshift(getViewBootstrapConfigurationResource({
|
|
243
261
|
id: view.id,
|
|
@@ -265,7 +283,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
265
283
|
const dedupedUris = [...new Set(viewPreloads.uris)];
|
|
266
284
|
// PRELOAD script resources for preload module URIs after the bootstrap module
|
|
267
285
|
for (const preloadUri of dedupedUris) {
|
|
268
|
-
|
|
286
|
+
const integrity = viewPreloads.integrities.get(preloadUri);
|
|
287
|
+
moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
|
|
288
|
+
integrity,
|
|
289
|
+
isPreload: true,
|
|
290
|
+
isSSR,
|
|
291
|
+
nonce,
|
|
292
|
+
}));
|
|
269
293
|
}
|
|
270
294
|
// generate html partial
|
|
271
295
|
const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
|
|
@@ -274,6 +298,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
274
298
|
viewRecord: {
|
|
275
299
|
resources: requiredResources,
|
|
276
300
|
customElements: customElementsRecords,
|
|
301
|
+
moduleResources,
|
|
277
302
|
bootstrapModule: bootstrapModuleRef,
|
|
278
303
|
},
|
|
279
304
|
};
|
|
@@ -3,11 +3,12 @@ export type ViewPreloads = {
|
|
|
3
3
|
groups: Map<string, boolean>;
|
|
4
4
|
uris: string[];
|
|
5
5
|
specifiers: string[];
|
|
6
|
+
integrities: Map<string, string | undefined>;
|
|
6
7
|
};
|
|
7
8
|
/**
|
|
8
9
|
* keeps track of preloadModules metadata
|
|
9
10
|
*/
|
|
10
|
-
export declare function setPreloadModulesMeta(specifier: string, uri: string, groups: BundleGroups, preloads: ViewPreloads): void;
|
|
11
|
+
export declare function setPreloadModulesMeta(specifier: string, uri: string, integrity: string | undefined, groups: BundleGroups, preloads: ViewPreloads): void;
|
|
11
12
|
/**
|
|
12
13
|
* Recursively gets preloadModules metadata starting with a specifier
|
|
13
14
|
* Note: don't call me unless you got bundles
|
|
@@ -3,7 +3,7 @@ import { explodeSpecifier, getGroupName, getVersionedModuleId, normalizeVersionT
|
|
|
3
3
|
/**
|
|
4
4
|
* keeps track of preloadModules metadata
|
|
5
5
|
*/
|
|
6
|
-
export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
6
|
+
export function setPreloadModulesMeta(specifier, uri, integrity, groups, preloads) {
|
|
7
7
|
// Throw a very specific error if we get this back and the uri property is not set
|
|
8
8
|
if (!uri) {
|
|
9
9
|
throw createSingleDiagnosticError({
|
|
@@ -20,6 +20,7 @@ export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
|
20
20
|
const preloadModulesSpecifiers = preloads.specifiers;
|
|
21
21
|
const preloadBundleGroupsMap = preloads.groups;
|
|
22
22
|
const preloadModulesURIs = preloads.uris;
|
|
23
|
+
const preloadModuleIntegrities = preloads.integrities;
|
|
23
24
|
preloadModulesSpecifiers.push(specifier);
|
|
24
25
|
const { specifier: unversionedSpecifier } = explodeSpecifier(specifier);
|
|
25
26
|
const groupName = getGroupName(unversionedSpecifier, groups);
|
|
@@ -29,6 +30,7 @@ export function setPreloadModulesMeta(specifier, uri, groups, preloads) {
|
|
|
29
30
|
// With bundling groups, we only want to include one URI
|
|
30
31
|
preloadModulesURIs.push(uri);
|
|
31
32
|
groupName && preloadBundleGroupsMap.set(groupName, true);
|
|
33
|
+
preloadModuleIntegrities.set(uri, integrity);
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Recursively gets preloadModules metadata starting with a specifier
|
|
@@ -60,12 +62,13 @@ viewPreloads, bundleConfig, moduleRegistry, defRegistry, runtimeEnvironment, run
|
|
|
60
62
|
const uri =
|
|
61
63
|
// eslint-disable-next-line no-await-in-loop
|
|
62
64
|
await defRegistry.resolveModuleUri(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
63
|
-
// fallback to
|
|
65
|
+
// fallback to un-versioned specifier if needed
|
|
64
66
|
const normalizedSpecifier = versionedModuleId.version === VERSION_NOT_PROVIDED ? specifier : versionedModuleSpecifier;
|
|
65
|
-
|
|
67
|
+
// Will set the integrity after loading the record below
|
|
68
|
+
const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
69
|
+
const { integrity } = preloadModuleRecord;
|
|
70
|
+
setPreloadModulesMeta(normalizedSpecifier, uri, integrity, groups, viewPreloads);
|
|
66
71
|
if (exclude.length || Object.keys(groups).length) {
|
|
67
|
-
// check if we need to also preload any excluded dependencies of this preload module
|
|
68
|
-
const preloadModuleRecord = await defRegistry.getModuleBundle(versionedModuleId, runtimeEnvironment, runtimeParams);
|
|
69
72
|
const { imports } = preloadModuleRecord.bundleRecord;
|
|
70
73
|
if (imports) {
|
|
71
74
|
if (!pending) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ClientBootstrapConfig, RuntimeEnvironment, RuntimeParams, ResourceDefinition, RenderedViewMetadata, CustomElementReference, View, ViewInfo } from '@lwrjs/types';
|
|
1
|
+
import type { ClientBootstrapConfig, RuntimeEnvironment, RuntimeParams, ResourceDefinition, RenderedViewMetadata, CustomElementReference, View, ViewInfo, FlattenedModuleGraphs } from '@lwrjs/types';
|
|
2
2
|
export declare function getViewBootstrapConfigurationResource(viewInfo: ViewInfo, config: ClientBootstrapConfig, runtimeEnvironment: RuntimeEnvironment, runtimeParams: RuntimeParams, debugMessage?: string): ResourceDefinition;
|
|
3
3
|
export declare function getViewHmrConfigurationResource(view: View, viewMetadata: RenderedViewMetadata): ResourceDefinition;
|
|
4
4
|
export declare function flattenCustomElements(arr: CustomElementReference[], isSSR?: boolean): CustomElementReference[];
|
|
5
|
+
export declare function getBundleIntegrity(bootstrapModuleGraph: FlattenedModuleGraphs, versionedSpecifier: string): string | undefined;
|
|
5
6
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildEnvironmentContext, getMappingUriPrefix, getModuleUriPrefix, getClientBootstrapConfigurationUri, hashContent, } from '@lwrjs/shared-utils';
|
|
1
|
+
import { buildEnvironmentContext, getMappingUriPrefix, getModuleUriPrefix, getClientBootstrapConfigurationUri, hashContent, createIntegrityHash, } from '@lwrjs/shared-utils';
|
|
2
2
|
const CONTENT_TYPE = 'application/javascript';
|
|
3
3
|
export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironment, runtimeParams, debugMessage) {
|
|
4
4
|
const { compat, debug, hmrEnabled, apiVersion, format } = runtimeEnvironment;
|
|
@@ -49,6 +49,7 @@ export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeE
|
|
|
49
49
|
type: CONTENT_TYPE,
|
|
50
50
|
content: configString,
|
|
51
51
|
inline: false,
|
|
52
|
+
integrity: createIntegrityHash(configString),
|
|
52
53
|
src: url,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
@@ -111,4 +112,9 @@ export function flattenCustomElements(arr, isSSR = false) {
|
|
|
111
112
|
flatten(arr);
|
|
112
113
|
return ret;
|
|
113
114
|
}
|
|
115
|
+
export function getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier) {
|
|
116
|
+
const def = bootstrapModuleGraph.linkedDefinitions[versionedSpecifier];
|
|
117
|
+
const integrity = def?.integrity;
|
|
118
|
+
return integrity;
|
|
119
|
+
}
|
|
114
120
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { logger } from '@lwrjs/diagnostics';
|
|
2
2
|
import { kebabCaseToModuleSpecifier, toImportMetadata, getModuleGraphs, getMappingUriPrefix, GraphDepth, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, } from '@lwrjs/shared-utils';
|
|
3
3
|
import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
|
|
4
|
-
import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
|
|
5
|
-
import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
4
|
+
import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
|
|
5
|
+
import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
6
6
|
import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
|
|
7
7
|
export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
8
8
|
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
|
|
9
|
-
const {
|
|
9
|
+
const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
|
|
10
10
|
const { customElements, serverData, serverDebug } = viewMetadata;
|
|
11
11
|
const defRegistry = bundle ? moduleBundler : moduleRegistry;
|
|
12
|
-
const version = lwrVersion;
|
|
13
12
|
const isAMD = format === 'amd';
|
|
14
13
|
const depth = isAMD
|
|
15
14
|
? { static: GraphDepth.ALL, dynamic: 1 }
|
|
@@ -72,9 +71,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
72
71
|
uris: [],
|
|
73
72
|
specifiers: [],
|
|
74
73
|
groups: new Map(),
|
|
74
|
+
integrities: new Map(),
|
|
75
75
|
};
|
|
76
76
|
// Determine if server side rendering view modules
|
|
77
77
|
const isSSR = view.bootstrap?.ssr;
|
|
78
|
+
// Determine the LWR client version
|
|
79
|
+
const version = view.bootstrap?.lwrVersion;
|
|
80
|
+
// Page level nonce for script tags
|
|
81
|
+
const nonce = getViewNonce(viewParams);
|
|
78
82
|
// ABS module and custom element references
|
|
79
83
|
let bootstrapModuleRef, versionedSpecifier = bootstrapSpecifier;
|
|
80
84
|
let importMetadata = { imports: {} };
|
|
@@ -94,6 +98,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
94
98
|
if (!def.inline && !def.src) {
|
|
95
99
|
throw Error(`Invalid Shim ${shimBundle}: ${JSON.stringify(def)}`);
|
|
96
100
|
}
|
|
101
|
+
addExternalScriptNonce(def, nonce);
|
|
97
102
|
requiredResources.push(def);
|
|
98
103
|
// Always inline the error shim script after the shim
|
|
99
104
|
const errorShimDef = (await resourceRegistry.getResource({ specifier: 'lwr-error-shim.js', version }, runtimeEnvironment, runtimeParams));
|
|
@@ -104,6 +109,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
104
109
|
if (!errorShimDef.inline && !errorShimDef.src) {
|
|
105
110
|
throw Error(`Invalid Shim lwr-error-shim.js: ${JSON.stringify(errorShimDef)}`);
|
|
106
111
|
}
|
|
112
|
+
addExternalScriptNonce(errorShimDef, nonce);
|
|
107
113
|
requiredResources.push(errorShimDef);
|
|
108
114
|
}
|
|
109
115
|
// ------- Application Bootstrap module
|
|
@@ -122,12 +128,14 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
122
128
|
if (!uri) {
|
|
123
129
|
throw Error(`Invalid Module Resource ${versionedSpecifier}`);
|
|
124
130
|
}
|
|
125
|
-
|
|
131
|
+
const integrity = getBundleIntegrity(bootstrapModuleGraph, versionedSpecifier);
|
|
132
|
+
moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { integrity, isPreload: false, isSSR, nonce }));
|
|
126
133
|
// PRELOAD the bootstrap module static dependencies as preloaded script resources
|
|
127
134
|
for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
|
|
128
135
|
const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
|
|
129
136
|
if (uri) {
|
|
130
|
-
|
|
137
|
+
const integrity = getBundleIntegrity(bootstrapModuleGraph, depSpecifier);
|
|
138
|
+
setPreloadModulesMeta(depSpecifier, uri, integrity, groups, viewPreloads);
|
|
131
139
|
}
|
|
132
140
|
}
|
|
133
141
|
// PRELOAD configured preloadModules as preloaded script resources
|
|
@@ -179,13 +187,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
179
187
|
// PRELOAD the custom element module as a link resource
|
|
180
188
|
const specifier = graph.graphs[0].specifier;
|
|
181
189
|
const uri = graph.uriMap[specifier];
|
|
182
|
-
|
|
190
|
+
const integrity = getBundleIntegrity(graph, specifier);
|
|
191
|
+
setPreloadModulesMeta(specifier, uri, integrity, groups, viewPreloads);
|
|
183
192
|
// PRELOAD custom element static deps as link resources when bundling is ON
|
|
184
193
|
if (bundle) {
|
|
185
194
|
for (const depSpecifier of graph.graphs[0].static) {
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
188
|
-
|
|
195
|
+
const depUri = getPreloadUri(depSpecifier, graph.uriMap);
|
|
196
|
+
if (depUri) {
|
|
197
|
+
const integrity = getBundleIntegrity(graph, depSpecifier);
|
|
198
|
+
setPreloadModulesMeta(depSpecifier, depUri, integrity, groups, viewPreloads);
|
|
189
199
|
}
|
|
190
200
|
}
|
|
191
201
|
}
|
|
@@ -234,7 +244,13 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
234
244
|
// PRELOAD script resources for preload module URIs after the bootstrap module
|
|
235
245
|
const dedupedUris = [...new Set(viewPreloads.uris)];
|
|
236
246
|
for (const preloadUri of dedupedUris) {
|
|
237
|
-
|
|
247
|
+
const integrity = viewPreloads.integrities.get(preloadUri);
|
|
248
|
+
moduleResources.push(getModuleResourceByUri(preloadUri, runtimeEnvironment, {
|
|
249
|
+
integrity,
|
|
250
|
+
isPreload: true,
|
|
251
|
+
isSSR,
|
|
252
|
+
nonce,
|
|
253
|
+
}));
|
|
238
254
|
}
|
|
239
255
|
// generate html partial
|
|
240
256
|
const htmlResources = await Promise.all([...configResources, ...requiredResources, ...moduleResources].map(generateHtmlTag));
|
|
@@ -251,6 +267,7 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
251
267
|
customElements: customElementsRecords,
|
|
252
268
|
endpoints,
|
|
253
269
|
importMetadata,
|
|
270
|
+
moduleResources,
|
|
254
271
|
bootstrapModule: bootstrapModuleRef,
|
|
255
272
|
},
|
|
256
273
|
};
|
package/build/es/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetReference, JsonCompatible, LinkedViewDefinition, LwrErrorRoute, LwrRoute, ModuleBundler, ModuleId, ModuleJson, ModuleRegistry, NormalizedRenderingResult, PublicModuleRegistry, RenderOptions, RenderedAssetReference, RenderingResult, ResourceDefinition, RouteHandlerViewResponse, RuntimeEnvironment, RuntimeParams, ViewModuleResourceContext, ViewPageContext, ViewRequest, ViewResponse } from '@lwrjs/types';
|
|
1
|
+
import type { AssetReference, JsonCompatible, LinkedViewDefinition, LwrErrorRoute, LwrRoute, ModuleBundler, ModuleId, ModuleJson, ModuleRegistry, NormalizedRenderingResult, PublicModuleRegistry, RenderOptions, RenderedAssetReference, RenderingResult, ResourceDefinition, RouteHandlerViewResponse, RuntimeEnvironment, RuntimeParams, ViewModuleResourceContext, ViewPageContext, ViewParams, ViewRequest, ViewResponse } from '@lwrjs/types';
|
|
2
2
|
export type HTMLResource = Partial<ResourceDefinition>;
|
|
3
3
|
export declare function generateHtmlTag(definition: HTMLResource): Promise<string>;
|
|
4
4
|
export declare function normalizeRenderedResult({ renderedView, metadata, options, cache, }: RenderingResult): NormalizedRenderingResult;
|
|
@@ -10,4 +10,16 @@ export declare function toJsonFormat(viewRequest: ViewRequest, viewDefinition: L
|
|
|
10
10
|
export declare function getModuleResource(moduleId: Pick<ModuleId, 'specifier' | 'version'>, runtimeEnvironment: RuntimeEnvironment, moduleResourceMeta: ViewModuleResourceContext, defRegistry: ModuleRegistry | ModuleBundler, runtimeParams: RuntimeParams): Promise<ResourceDefinition>;
|
|
11
11
|
export declare function getModuleResourceByUri(uri: string, runtimeEnvironment: RuntimeEnvironment, moduleResourceMeta: ViewModuleResourceContext): ResourceDefinition;
|
|
12
12
|
export declare function createJsonModule(specifier: string, moduleRegistry: PublicModuleRegistry, environment: RuntimeEnvironment, params: RuntimeParams): Promise<ModuleJson>;
|
|
13
|
+
/**
|
|
14
|
+
* Get the nonce set on the page context of the view params
|
|
15
|
+
*/
|
|
16
|
+
export declare function getViewNonce(viewParams: ViewParams): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Generate a nonce in the page context of the view params
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateViewNonce(viewParams: ViewParams): void;
|
|
21
|
+
/**
|
|
22
|
+
* Add a nonce to a script definition in view if it is external (not inline)
|
|
23
|
+
*/
|
|
24
|
+
export declare function addExternalScriptNonce(def: ResourceDefinition, nonce?: string): void;
|
|
13
25
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/es/utils.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { basename, extname } from 'path';
|
|
2
|
-
import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, } from '@lwrjs/shared-utils';
|
|
2
|
+
import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, getFeatureFlags, } from '@lwrjs/shared-utils';
|
|
3
3
|
import { AppResourceEnum, getAppSpecifier, ResourceIdentityTypes, } from '@lwrjs/app-service/identity';
|
|
4
|
+
import crypto from 'crypto';
|
|
4
5
|
function generateExternalStyle(src) {
|
|
5
6
|
return `<link rel="stylesheet" href="${src}">`;
|
|
6
7
|
}
|
|
7
|
-
function generateExternalScript(type = 'application/javascript', src, async, defer) {
|
|
8
|
+
function generateExternalScript(type = 'application/javascript', src, async, defer, nonce, integrity) {
|
|
9
|
+
// add script loader order attribute
|
|
8
10
|
let scriptLoadOrder = '';
|
|
9
11
|
if (defer) {
|
|
10
12
|
scriptLoadOrder = ' defer';
|
|
@@ -12,7 +14,19 @@ function generateExternalScript(type = 'application/javascript', src, async, def
|
|
|
12
14
|
else if (async) {
|
|
13
15
|
scriptLoadOrder = ' async';
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
// add the right CSP header attribute
|
|
18
|
+
let cspHashAttr = '';
|
|
19
|
+
// For now use the ENABLE_NONCE to gate adding nonce or integrity
|
|
20
|
+
// W-15868505 is open to create a better config
|
|
21
|
+
if (getFeatureFlags().ENABLE_NONCE) {
|
|
22
|
+
if (integrity) {
|
|
23
|
+
cspHashAttr = ` integrity="${integrity}"`;
|
|
24
|
+
}
|
|
25
|
+
else if (nonce) {
|
|
26
|
+
cspHashAttr = ` nonce="${nonce}"`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return `<script type="${type}"${scriptLoadOrder}${cspHashAttr} src="${src}"></script>`;
|
|
16
30
|
}
|
|
17
31
|
function generateLinkPreloadTag({ href, type }) {
|
|
18
32
|
if (type === 'module') {
|
|
@@ -22,7 +36,7 @@ function generateLinkPreloadTag({ href, type }) {
|
|
|
22
36
|
return `<link rel="preload" href="${href}" type="${type}" />`;
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
|
-
function generateExternalTag({ type, src = '', async, defer, isPreload }) {
|
|
39
|
+
function generateExternalTag({ type, src = '', async, defer, isPreload, nonce, integrity, }) {
|
|
26
40
|
if (isPreload) {
|
|
27
41
|
return generateLinkPreloadTag({ href: src, type: type });
|
|
28
42
|
}
|
|
@@ -30,13 +44,13 @@ function generateExternalTag({ type, src = '', async, defer, isPreload }) {
|
|
|
30
44
|
return generateExternalStyle(src);
|
|
31
45
|
}
|
|
32
46
|
else {
|
|
33
|
-
return generateExternalScript(type, src, async, defer);
|
|
47
|
+
return generateExternalScript(type, src, async, defer, nonce, integrity);
|
|
34
48
|
}
|
|
35
49
|
}
|
|
36
50
|
async function generateInlineTag({ specifier, type, content, stream, nonce }) {
|
|
37
51
|
const typeStr = type === 'text/css' ? '' : ` type="${type}"`;
|
|
38
52
|
const tag = type === 'text/css' ? 'style' : 'script';
|
|
39
|
-
const nonceStr = nonce ? ` nonce="${nonce}"` : '';
|
|
53
|
+
const nonceStr = getFeatureFlags().ENABLE_NONCE && nonce && nonce ? ` nonce="${nonce}"` : '';
|
|
40
54
|
if (!content && !stream) {
|
|
41
55
|
throw new Error(`Invalid inline Resource Definition: must have either "content" or "stream": "${specifier}"`);
|
|
42
56
|
}
|
|
@@ -203,7 +217,7 @@ export async function getModuleResource(moduleId, runtimeEnvironment, moduleReso
|
|
|
203
217
|
};
|
|
204
218
|
}
|
|
205
219
|
export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMeta) {
|
|
206
|
-
const { isSSR = false, isPreload = false } = moduleResourceMeta;
|
|
220
|
+
const { integrity, isSSR = false, isPreload = false, nonce } = moduleResourceMeta;
|
|
207
221
|
const { format } = runtimeEnvironment;
|
|
208
222
|
return {
|
|
209
223
|
src: uri,
|
|
@@ -213,6 +227,8 @@ export function getModuleResourceByUri(uri, runtimeEnvironment, moduleResourceMe
|
|
|
213
227
|
// only use link preload for ESM for compat reasons.
|
|
214
228
|
// AMD should use regular script tags for preloading
|
|
215
229
|
isPreload: format !== 'amd' && isPreload,
|
|
230
|
+
integrity,
|
|
231
|
+
nonce,
|
|
216
232
|
};
|
|
217
233
|
}
|
|
218
234
|
// Given a specifier and resource type, return the JSON serialized Module data
|
|
@@ -236,4 +252,34 @@ export async function createJsonModule(specifier, moduleRegistry, environment, p
|
|
|
236
252
|
},
|
|
237
253
|
};
|
|
238
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Get the nonce set on the page context of the view params
|
|
257
|
+
*/
|
|
258
|
+
export function getViewNonce(viewParams) {
|
|
259
|
+
return getFeatureFlags().ENABLE_NONCE
|
|
260
|
+
? viewParams?.page?.nonce
|
|
261
|
+
: undefined;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Generate a nonce in the page context of the view params
|
|
265
|
+
*/
|
|
266
|
+
export function generateViewNonce(viewParams) {
|
|
267
|
+
if (getFeatureFlags().ENABLE_NONCE) {
|
|
268
|
+
const nonce = crypto.randomBytes(16).toString('base64');
|
|
269
|
+
if (!viewParams.page) {
|
|
270
|
+
viewParams.page = { nonce };
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
viewParams.page.nonce = nonce;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Add a nonce to a script definition in view if it is external (not inline)
|
|
279
|
+
*/
|
|
280
|
+
export function addExternalScriptNonce(def, nonce) {
|
|
281
|
+
if (nonce && getFeatureFlags().ENABLE_NONCE && !def.inline) {
|
|
282
|
+
def.nonce = nonce;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
239
285
|
//# sourceMappingURL=utils.js.map
|
package/build/es/view-handler.js
CHANGED
|
@@ -146,6 +146,8 @@ export class LwrViewHandler {
|
|
|
146
146
|
const paths = { rootDir, assets, contentDir, layoutsDir };
|
|
147
147
|
const locale = runtimeParams.locale;
|
|
148
148
|
const basePath = runtimeParams.basePath;
|
|
149
|
+
const assetBasePath = runtimeParams.assetBasePath;
|
|
150
|
+
const uiBasePath = runtimeParams.assetBasePath;
|
|
149
151
|
const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
|
|
150
152
|
const response = await getTracer().trace({
|
|
151
153
|
name: ViewSpan.ExecuteRouteHandler,
|
|
@@ -155,7 +157,7 @@ export class LwrViewHandler {
|
|
|
155
157
|
},
|
|
156
158
|
}, async () => {
|
|
157
159
|
try {
|
|
158
|
-
return await routeHandlerFn({ ...viewRequest, locale, basePath }, { route: route, viewApi, ...paths }, routeHandlerOptions);
|
|
160
|
+
return await routeHandlerFn({ ...viewRequest, locale, basePath, assetBasePath, uiBasePath }, { route: route, viewApi, ...paths }, routeHandlerOptions);
|
|
159
161
|
}
|
|
160
162
|
catch (err) {
|
|
161
163
|
if (err instanceof DiagnosticsError) {
|
|
@@ -165,6 +167,10 @@ export class LwrViewHandler {
|
|
|
165
167
|
throw createSingleDiagnosticError({ description: descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message) }, LwrApplicationError);
|
|
166
168
|
}
|
|
167
169
|
});
|
|
170
|
+
// if the locale was returned by the route handler update the runtime time params
|
|
171
|
+
if (response?.locale) {
|
|
172
|
+
runtimeParams.locale = response.locale;
|
|
173
|
+
}
|
|
168
174
|
return response;
|
|
169
175
|
}
|
|
170
176
|
/*
|
|
@@ -191,6 +197,11 @@ export class LwrViewHandler {
|
|
|
191
197
|
view, viewParams, renderOptions) {
|
|
192
198
|
const { id, bootstrap } = route;
|
|
193
199
|
const managedView = { ...view, id, bootstrap };
|
|
200
|
+
// If this is a localized view request (could have come from a route handler)
|
|
201
|
+
// Update the runtime params
|
|
202
|
+
if (view.locale) {
|
|
203
|
+
runtimeParams.locale = view.locale;
|
|
204
|
+
}
|
|
194
205
|
const viewResponse = {
|
|
195
206
|
view: managedView,
|
|
196
207
|
viewParams,
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.13.0-alpha.
|
|
7
|
+
"version": "0.13.0-alpha.21",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -29,18 +29,21 @@
|
|
|
29
29
|
"build/**/*.cjs",
|
|
30
30
|
"build/**/*.d.ts"
|
|
31
31
|
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -b"
|
|
34
|
+
},
|
|
32
35
|
"dependencies": {
|
|
33
|
-
"@lwrjs/app-service": "0.13.0-alpha.
|
|
34
|
-
"@lwrjs/diagnostics": "0.13.0-alpha.
|
|
35
|
-
"@lwrjs/instrumentation": "0.13.0-alpha.
|
|
36
|
-
"@lwrjs/shared-utils": "0.13.0-alpha.
|
|
37
|
-
"lru-cache": "^10.2.
|
|
36
|
+
"@lwrjs/app-service": "0.13.0-alpha.21",
|
|
37
|
+
"@lwrjs/diagnostics": "0.13.0-alpha.21",
|
|
38
|
+
"@lwrjs/instrumentation": "0.13.0-alpha.21",
|
|
39
|
+
"@lwrjs/shared-utils": "0.13.0-alpha.21",
|
|
40
|
+
"lru-cache": "^10.2.2"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
40
|
-
"@lwrjs/types": "0.13.0-alpha.
|
|
43
|
+
"@lwrjs/types": "0.13.0-alpha.21"
|
|
41
44
|
},
|
|
42
45
|
"engines": {
|
|
43
46
|
"node": ">=18.0.0"
|
|
44
47
|
},
|
|
45
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "d272dcd07881fa469ee73bd28d2f30f99957e122"
|
|
46
49
|
}
|