@lwrjs/view-registry 0.15.0-alpha.26 → 0.15.0-alpha.28
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 +42 -34
- package/build/cjs/linkers/legacy_view_bootstrap.cjs +23 -4
- package/build/cjs/linkers/link-lwr-resources.cjs +7 -7
- package/build/cjs/linkers/view_bootstrap.cjs +24 -4
- package/build/cjs/utils.cjs +20 -0
- package/build/es/index.js +45 -36
- package/build/es/linkers/legacy_view_bootstrap.d.ts +2 -14
- package/build/es/linkers/legacy_view_bootstrap.js +28 -5
- package/build/es/linkers/link-lwr-resources.d.ts +3 -1
- package/build/es/linkers/link-lwr-resources.js +11 -11
- package/build/es/linkers/view_bootstrap.d.ts +2 -14
- package/build/es/linkers/view_bootstrap.js +30 -6
- package/build/es/utils.d.ts +3 -1
- package/build/es/utils.js +20 -1
- package/package.json +10 -7
package/build/cjs/index.cjs
CHANGED
|
@@ -145,28 +145,20 @@ var LwrViewRegistry = class {
|
|
|
145
145
|
const {contentTemplate, rootComponent} = viewId;
|
|
146
146
|
const compiledViewCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({contentTemplate, rootComponent});
|
|
147
147
|
import_diagnostics.logger.debug(`[view-registry][getView] compiledViewCacheKey=${compiledViewCacheKey}`);
|
|
148
|
-
|
|
148
|
+
const route = this.globalConfig.routes.find((r) => r.id === viewId.id);
|
|
149
|
+
const skipCaching = route?.cache?.ttl === 0;
|
|
150
|
+
if (!skipCaching && this.compiledViews.has(compiledViewCacheKey)) {
|
|
149
151
|
return this.compiledViews.get(compiledViewCacheKey);
|
|
150
152
|
}
|
|
151
153
|
const compiledView = await this.delegateGetView(viewId);
|
|
152
|
-
|
|
154
|
+
if (!skipCaching) {
|
|
155
|
+
this.compiledViews.set(compiledViewCacheKey, compiledView);
|
|
156
|
+
}
|
|
153
157
|
return compiledView;
|
|
154
158
|
}
|
|
155
159
|
hasViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
|
|
156
|
-
const {id, bootstrap, rootComponent, contentTemplate, layoutTemplate} = view;
|
|
157
160
|
const {freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
|
|
158
|
-
const viewDefId = (0,
|
|
159
|
-
id,
|
|
160
|
-
bootstrap,
|
|
161
|
-
rootComponent,
|
|
162
|
-
contentTemplate,
|
|
163
|
-
layoutTemplate,
|
|
164
|
-
freezeAssets,
|
|
165
|
-
locale: runtimeParams?.locale,
|
|
166
|
-
basePath: runtimeParams?.basePath,
|
|
167
|
-
debug: runtimeEnvironment.debug,
|
|
168
|
-
nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
|
|
169
|
-
});
|
|
161
|
+
const viewDefId = (0, import_utils.getViewDefCacheKey)(view, runtimeEnvironment, freezeAssets, runtimeParams);
|
|
170
162
|
import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
|
|
171
163
|
const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
|
|
172
164
|
import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewParamKey=${viewParamKey}`);
|
|
@@ -182,14 +174,7 @@ var LwrViewRegistry = class {
|
|
|
182
174
|
runtimeParams.requestCache = runtimeParams.requestCache ?? {};
|
|
183
175
|
try {
|
|
184
176
|
const {freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
|
|
185
|
-
const viewDefCacheKey = (0,
|
|
186
|
-
...view,
|
|
187
|
-
freezeAssets,
|
|
188
|
-
locale: runtimeParams?.locale,
|
|
189
|
-
basePath: runtimeParams?.basePath,
|
|
190
|
-
debug: runtimeEnvironment.debug,
|
|
191
|
-
nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
|
|
192
|
-
});
|
|
177
|
+
const viewDefCacheKey = (0, import_utils.getViewDefCacheKey)(view, runtimeEnvironment, freezeAssets, runtimeParams);
|
|
193
178
|
import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
|
|
194
179
|
const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
|
|
195
180
|
import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
|
|
@@ -208,7 +193,7 @@ var LwrViewRegistry = class {
|
|
|
208
193
|
view: view.id,
|
|
209
194
|
ssr: view.bootstrap?.ssr === true
|
|
210
195
|
}
|
|
211
|
-
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
|
|
196
|
+
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, pendingViewDefCacheKey, renderOptions)));
|
|
212
197
|
viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
|
|
213
198
|
const route = this.globalConfig.routes.find((r) => r.id === view.id);
|
|
214
199
|
const maxViewCacheTtl = (0, import_shared_utils.getFeatureFlags)().MAX_VIEW_CACHE_TTL;
|
|
@@ -232,7 +217,7 @@ var LwrViewRegistry = class {
|
|
|
232
217
|
throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.SERVER.UNEXPECTED_ERROR(message)}, import_diagnostics.LwrServerError);
|
|
233
218
|
}
|
|
234
219
|
}
|
|
235
|
-
async renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
|
|
220
|
+
async renderView(view, viewParams, runtimeEnvironment, runtimeParams, viewCacheKey, renderOptions) {
|
|
236
221
|
const {id, contentTemplate, rootComponent, layoutTemplate} = view;
|
|
237
222
|
const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
|
|
238
223
|
const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment);
|
|
@@ -245,7 +230,8 @@ var LwrViewRegistry = class {
|
|
|
245
230
|
runtimeEnvironment,
|
|
246
231
|
runtimeParams,
|
|
247
232
|
renderOptions: normalizedRenderOptions,
|
|
248
|
-
contentIds: {lwrResourcesId}
|
|
233
|
+
contentIds: {lwrResourcesId},
|
|
234
|
+
viewCacheKey
|
|
249
235
|
});
|
|
250
236
|
return renderedViewDef2;
|
|
251
237
|
}
|
|
@@ -290,7 +276,8 @@ var LwrViewRegistry = class {
|
|
|
290
276
|
runtimeParams,
|
|
291
277
|
renderOptions: normalizedRenderOptions,
|
|
292
278
|
contentIds: {lwrResourcesId},
|
|
293
|
-
importer: renderedContent.compiledView.filePath
|
|
279
|
+
importer: renderedContent.compiledView.filePath,
|
|
280
|
+
viewCacheKey
|
|
294
281
|
});
|
|
295
282
|
return renderedViewDef;
|
|
296
283
|
}
|
|
@@ -318,7 +305,8 @@ var LwrViewRegistry = class {
|
|
|
318
305
|
runtimeParams,
|
|
319
306
|
renderOptions,
|
|
320
307
|
contentIds,
|
|
321
|
-
importer
|
|
308
|
+
importer,
|
|
309
|
+
viewCacheKey
|
|
322
310
|
} = viewContext;
|
|
323
311
|
const {skipMetadataCollection, freezeAssets} = renderOptions;
|
|
324
312
|
const {lwrResourcesId} = contentIds;
|
|
@@ -329,19 +317,37 @@ var LwrViewRegistry = class {
|
|
|
329
317
|
metadata: renderedViewMetadata,
|
|
330
318
|
compiledView: {immutable = true}
|
|
331
319
|
} = renderedView;
|
|
332
|
-
const linkedMetadata =
|
|
320
|
+
const {linkedMetadata, stringBuilder} = await (0, import_instrumentation.getTracer)().trace({
|
|
321
|
+
name: import_instrumentation.ViewSpan.ParseView,
|
|
322
|
+
attributes: {
|
|
323
|
+
view: view.id,
|
|
324
|
+
ssr: view.bootstrap?.ssr === true
|
|
325
|
+
}
|
|
326
|
+
}, async () => {
|
|
327
|
+
const linkedMetadata2 = skipMetadataCollection ? renderedViewMetadata : await (0, import_shared_utils.extractMetadataFromHtml)(renderedViewContent, renderedViewMetadata, this.globalConfig);
|
|
328
|
+
const stringBuilder2 = (0, import_shared_utils.createStringBuilder)(renderedViewContent);
|
|
329
|
+
return {linkedMetadata: linkedMetadata2, stringBuilder: stringBuilder2};
|
|
330
|
+
});
|
|
333
331
|
const mergedViewContext = {
|
|
334
332
|
...viewContext,
|
|
335
333
|
config: this.globalConfig,
|
|
336
334
|
runtimeEnvironment,
|
|
337
335
|
importer: importer || renderedView.compiledView.filePath
|
|
338
336
|
};
|
|
339
|
-
const stringBuilder = (0, import_shared_utils.createStringBuilder)(renderedViewContent);
|
|
340
337
|
let pageTtl = renderedView.cache.ttl;
|
|
338
|
+
let pageRedirect = renderedView.redirect;
|
|
341
339
|
for (const viewTransformer of this.viewTransformers) {
|
|
342
|
-
const linkResults = await
|
|
340
|
+
const linkResults = await (0, import_instrumentation.getTracer)().trace({
|
|
341
|
+
name: import_instrumentation.ViewSpan.Transform,
|
|
342
|
+
attributes: {
|
|
343
|
+
name: viewTransformer.name
|
|
344
|
+
}
|
|
345
|
+
}, () => viewTransformer.link?.(stringBuilder, mergedViewContext, linkedMetadata));
|
|
343
346
|
const ttl = linkResults && linkResults.cache?.ttl;
|
|
344
347
|
pageTtl = (0, import_shared_utils.shortestTtl)(ttl || void 0, pageTtl);
|
|
348
|
+
if (!pageRedirect) {
|
|
349
|
+
pageRedirect = linkResults ? linkResults.redirect : void 0;
|
|
350
|
+
}
|
|
345
351
|
}
|
|
346
352
|
const linkedAssetContent = stringBuilder.toString();
|
|
347
353
|
if (linkedAssetContent.includes(lwrResourcesId)) {
|
|
@@ -353,7 +359,9 @@ var LwrViewRegistry = class {
|
|
|
353
359
|
resourceRegistry,
|
|
354
360
|
runtimeEnvironment,
|
|
355
361
|
runtimeParams,
|
|
356
|
-
bundleConfig: this.globalConfig.bundleConfig
|
|
362
|
+
bundleConfig: this.globalConfig.bundleConfig,
|
|
363
|
+
unsafeEnableViewLinkCaching: this.globalConfig.unsafeEnableViewLinkCaching,
|
|
364
|
+
viewLinkCacheKey: viewCacheKey
|
|
357
365
|
});
|
|
358
366
|
return {
|
|
359
367
|
renderedView: linkedView,
|
|
@@ -363,7 +371,7 @@ var LwrViewRegistry = class {
|
|
|
363
371
|
...viewRecord
|
|
364
372
|
},
|
|
365
373
|
cache: {ttl: pageTtl},
|
|
366
|
-
redirect:
|
|
374
|
+
redirect: pageRedirect
|
|
367
375
|
};
|
|
368
376
|
}
|
|
369
377
|
return {
|
|
@@ -374,7 +382,7 @@ var LwrViewRegistry = class {
|
|
|
374
382
|
moduleResources: []
|
|
375
383
|
},
|
|
376
384
|
cache: {ttl: pageTtl},
|
|
377
|
-
redirect:
|
|
385
|
+
redirect: pageRedirect
|
|
378
386
|
};
|
|
379
387
|
}
|
|
380
388
|
};
|
|
@@ -32,6 +32,7 @@ var import_identity = __toModule(require("@lwrjs/app-service/identity"));
|
|
|
32
32
|
var import_utils = __toModule(require("../utils.cjs"));
|
|
33
33
|
var import_utils2 = __toModule(require("./utils.cjs"));
|
|
34
34
|
var import_preload_utils = __toModule(require("./preload-utils.cjs"));
|
|
35
|
+
var import_lru_cache = __toModule(require("lru-cache"));
|
|
35
36
|
function includeIdFactory(bundleConfig) {
|
|
36
37
|
return (moduleRef) => {
|
|
37
38
|
if ((0, import_shared_utils.isExternalSpecifier)(moduleRef.specifier, bundleConfig)) {
|
|
@@ -40,6 +41,8 @@ function includeIdFactory(bundleConfig) {
|
|
|
40
41
|
return true;
|
|
41
42
|
};
|
|
42
43
|
}
|
|
44
|
+
var moduleGraphsCache = new import_lru_cache.LRUCache({max: 500});
|
|
45
|
+
var isRunningLocalDev = (0, import_shared_utils.isLocalDev)();
|
|
43
46
|
async function getHtmlResources(view, viewParams, resourceContext) {
|
|
44
47
|
const {
|
|
45
48
|
runtimeEnvironment,
|
|
@@ -47,14 +50,16 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
47
50
|
moduleRegistry,
|
|
48
51
|
moduleBundler,
|
|
49
52
|
resourceRegistry,
|
|
50
|
-
viewMetadata
|
|
53
|
+
viewMetadata,
|
|
54
|
+
viewLinkCacheKey
|
|
51
55
|
} = resourceContext;
|
|
52
56
|
const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
|
|
53
57
|
const {customElements, serverData, serverDebug} = viewMetadata;
|
|
54
58
|
const isAMD = format === "amd";
|
|
55
|
-
const {bundleConfig} = resourceContext;
|
|
59
|
+
const {bundleConfig, unsafeEnableViewLinkCaching} = resourceContext;
|
|
56
60
|
const {external = {}, exclude = []} = bundleConfig;
|
|
57
61
|
const groups = isAMD ? bundleConfig.groups || {} : {};
|
|
62
|
+
const enableModuleGraphsCache = unsafeEnableViewLinkCaching && !isRunningLocalDev && !process.env.NOCACHE;
|
|
58
63
|
const getPreloadUri = function(rawSpecifier, uriMap) {
|
|
59
64
|
const {specifier} = (0, import_shared_utils.explodeSpecifier)(rawSpecifier);
|
|
60
65
|
if (Object.keys(external).some((e) => specifier === e))
|
|
@@ -139,7 +144,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
139
144
|
(0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
|
|
140
145
|
requiredResources.push(errorShimDef);
|
|
141
146
|
}
|
|
142
|
-
|
|
147
|
+
let bootstrapModuleGraph;
|
|
148
|
+
const bootstrapModuleGraphCacheKey = (0, import_utils.getModuleGraphCacheKey)(bootstrapSpecifier, viewLinkCacheKey);
|
|
149
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(bootstrapModuleGraphCacheKey)) {
|
|
150
|
+
bootstrapModuleGraph = moduleGraphsCache.get(bootstrapModuleGraphCacheKey);
|
|
151
|
+
} else {
|
|
152
|
+
bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
153
|
+
enableModuleGraphsCache && moduleGraphsCache.set(bootstrapModuleGraphCacheKey, bootstrapModuleGraph);
|
|
154
|
+
}
|
|
143
155
|
bootstrapModuleRef = {
|
|
144
156
|
specifier: bootstrapModuleGraph.graphs[0].specifier,
|
|
145
157
|
flatGraph: bootstrapModuleGraph,
|
|
@@ -190,7 +202,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
190
202
|
await Promise.all(flattenedElements.map(async ({tagName: element, props}) => {
|
|
191
203
|
const hydrateDirective = (0, import_shared_utils.getHydrateDirective)(props);
|
|
192
204
|
const isSsrOnly = isSSR && !hydrateDirective;
|
|
193
|
-
const
|
|
205
|
+
const moduleGraphCacheKey = (0, import_utils.getModuleGraphCacheKey)(element, viewLinkCacheKey);
|
|
206
|
+
let graph;
|
|
207
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(moduleGraphCacheKey)) {
|
|
208
|
+
graph = moduleGraphsCache.get(moduleGraphCacheKey);
|
|
209
|
+
} else {
|
|
210
|
+
graph = await (0, import_shared_utils.getModuleGraphs)((0, import_shared_utils.kebabCaseToModuleSpecifier)(element), {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, {...runtimeParams, ssr: isSsrOnly}, visitedCache);
|
|
211
|
+
enableModuleGraphsCache && moduleGraphsCache.set(moduleGraphCacheKey, graph);
|
|
212
|
+
}
|
|
194
213
|
customElementsRecords.push({elementName: element, flatGraph: graph});
|
|
195
214
|
if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
|
|
196
215
|
const specifier = graph.graphs[0].specifier;
|
|
@@ -32,16 +32,16 @@ var import_legacy_view_bootstrap = __toModule(require("./legacy_view_bootstrap.c
|
|
|
32
32
|
async function linkLwrResources(source, view, viewParams, cxt) {
|
|
33
33
|
const {lwrResourcesId, ...resourceContext} = cxt;
|
|
34
34
|
const LEGACY_LOADER = !!resourceContext.runtimeEnvironment.featureFlags.LEGACY_LOADER;
|
|
35
|
-
|
|
35
|
+
return await (0, import_instrumentation.getTracer)().trace({
|
|
36
36
|
name: import_instrumentation.ViewSpan.Generate,
|
|
37
37
|
attributes: {
|
|
38
38
|
legacyLoader: LEGACY_LOADER
|
|
39
39
|
}
|
|
40
|
-
}, () => {
|
|
41
|
-
|
|
40
|
+
}, async () => {
|
|
41
|
+
const {partial, viewRecord} = await (LEGACY_LOADER ? (0, import_legacy_view_bootstrap.getHtmlResources)(view, viewParams, resourceContext) : (0, import_view_bootstrap.getHtmlResources)(view, viewParams, resourceContext));
|
|
42
|
+
return {
|
|
43
|
+
renderedView: source.replace(lwrResourcesId, () => partial),
|
|
44
|
+
viewRecord
|
|
45
|
+
};
|
|
42
46
|
});
|
|
43
|
-
return {
|
|
44
|
-
renderedView: source.replace(lwrResourcesId, () => partial),
|
|
45
|
-
viewRecord
|
|
46
|
-
};
|
|
47
47
|
}
|
|
@@ -28,10 +28,14 @@ __export(exports, {
|
|
|
28
28
|
});
|
|
29
29
|
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
30
30
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
31
|
+
var import_lru_cache = __toModule(require("lru-cache"));
|
|
31
32
|
var import_identity = __toModule(require("@lwrjs/app-service/identity"));
|
|
32
33
|
var import_utils = __toModule(require("../utils.cjs"));
|
|
33
34
|
var import_utils2 = __toModule(require("./utils.cjs"));
|
|
35
|
+
var import_utils3 = __toModule(require("../utils.cjs"));
|
|
34
36
|
var import_preload_utils = __toModule(require("./preload-utils.cjs"));
|
|
37
|
+
var moduleGraphsCache = new import_lru_cache.LRUCache({max: 500});
|
|
38
|
+
var isRunningLocalDev = (0, import_shared_utils.isLocalDev)();
|
|
35
39
|
async function getHtmlResources(view, viewParams, resourceContext) {
|
|
36
40
|
const {
|
|
37
41
|
runtimeEnvironment,
|
|
@@ -39,16 +43,18 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
39
43
|
moduleRegistry,
|
|
40
44
|
moduleBundler,
|
|
41
45
|
resourceRegistry,
|
|
42
|
-
viewMetadata
|
|
46
|
+
viewMetadata,
|
|
47
|
+
viewLinkCacheKey
|
|
43
48
|
} = resourceContext;
|
|
44
49
|
const {format, hmrEnabled, bundle, debug, minify} = runtimeEnvironment;
|
|
45
50
|
const {customElements, serverData, serverDebug} = viewMetadata;
|
|
46
51
|
const defRegistry = bundle ? moduleBundler : moduleRegistry;
|
|
47
52
|
const isAMD = format === "amd";
|
|
48
53
|
const depth = isAMD ? {static: import_shared_utils.GraphDepth.ALL, dynamic: 1} : {static: import_shared_utils.GraphDepth.NONE, dynamic: 1};
|
|
49
|
-
const {bundleConfig} = resourceContext;
|
|
54
|
+
const {bundleConfig, unsafeEnableViewLinkCaching} = resourceContext;
|
|
50
55
|
const {external = {}, exclude = []} = bundleConfig;
|
|
51
56
|
const groups = isAMD ? bundleConfig.groups || {} : {};
|
|
57
|
+
const enableModuleGraphsCache = unsafeEnableViewLinkCaching && !isRunningLocalDev && !process.env.NOCACHE;
|
|
52
58
|
const getPreloadUri = function(rawSpecifier, uriMap) {
|
|
53
59
|
const {specifier} = (0, import_shared_utils.explodeSpecifier)(rawSpecifier);
|
|
54
60
|
if (Object.keys(external).some((e) => specifier === e))
|
|
@@ -119,7 +125,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
119
125
|
(0, import_utils.addExternalScriptNonce)(errorShimDef, nonce);
|
|
120
126
|
requiredResources.push(errorShimDef);
|
|
121
127
|
}
|
|
122
|
-
|
|
128
|
+
let bootstrapModuleGraph;
|
|
129
|
+
const bootstrapModuleGraphCacheKey = (0, import_utils3.getModuleGraphCacheKey)(bootstrapSpecifier, viewLinkCacheKey);
|
|
130
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(bootstrapModuleGraphCacheKey)) {
|
|
131
|
+
bootstrapModuleGraph = moduleGraphsCache.get(bootstrapModuleGraphCacheKey);
|
|
132
|
+
} else {
|
|
133
|
+
bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
134
|
+
enableModuleGraphsCache && moduleGraphsCache.set(bootstrapModuleGraphCacheKey, bootstrapModuleGraph);
|
|
135
|
+
}
|
|
123
136
|
bootstrapModuleRef = {
|
|
124
137
|
specifier: bootstrapModuleGraph.graphs[0].specifier,
|
|
125
138
|
flatGraph: bootstrapModuleGraph,
|
|
@@ -171,7 +184,14 @@ async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
171
184
|
for (const {tagName: element, props} of flattenedElements) {
|
|
172
185
|
const hydrateDirective = (0, import_shared_utils.getHydrateDirective)(props);
|
|
173
186
|
const isSsrOnly = isSSR && !hydrateDirective;
|
|
174
|
-
const
|
|
187
|
+
const moduleGraphCacheKey = (0, import_utils3.getModuleGraphCacheKey)(element, viewLinkCacheKey);
|
|
188
|
+
let graph;
|
|
189
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(moduleGraphCacheKey)) {
|
|
190
|
+
graph = moduleGraphsCache.get(moduleGraphCacheKey);
|
|
191
|
+
} else {
|
|
192
|
+
graph = await (0, import_shared_utils.getModuleGraphs)((0, import_shared_utils.kebabCaseToModuleSpecifier)(element), {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, {...runtimeParams, ssr: isSsrOnly}, visitedCache);
|
|
193
|
+
enableModuleGraphsCache && moduleGraphsCache.set(moduleGraphCacheKey, graph);
|
|
194
|
+
}
|
|
175
195
|
customElementsRecords.push({elementName: element, flatGraph: graph});
|
|
176
196
|
if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
|
|
177
197
|
const specifier = graph.graphs[0].specifier;
|
package/build/cjs/utils.cjs
CHANGED
|
@@ -30,8 +30,10 @@ __export(exports, {
|
|
|
30
30
|
generateLinkHeaders: () => generateLinkHeaders,
|
|
31
31
|
generatePageContext: () => generatePageContext,
|
|
32
32
|
generateViewNonce: () => generateViewNonce,
|
|
33
|
+
getModuleGraphCacheKey: () => getModuleGraphCacheKey,
|
|
33
34
|
getModuleResource: () => getModuleResource,
|
|
34
35
|
getModuleResourceByUri: () => getModuleResourceByUri,
|
|
36
|
+
getViewDefCacheKey: () => getViewDefCacheKey,
|
|
35
37
|
getViewNonce: () => getViewNonce,
|
|
36
38
|
isViewDefinitionResponse: () => isViewDefinitionResponse,
|
|
37
39
|
isViewResponse: () => isViewResponse,
|
|
@@ -318,3 +320,21 @@ function generateLinkHeaders(assets, patterns) {
|
|
|
318
320
|
return linkHeader;
|
|
319
321
|
}, "");
|
|
320
322
|
}
|
|
323
|
+
function getViewDefCacheKey(view, runtimeEnvironment, freezeAssets, runtimeParams) {
|
|
324
|
+
const {id, bootstrap, rootComponent, contentTemplate, layoutTemplate} = view;
|
|
325
|
+
return (0, import_shared_utils.getCacheKeyFromJson)({
|
|
326
|
+
id,
|
|
327
|
+
bootstrap,
|
|
328
|
+
rootComponent,
|
|
329
|
+
contentTemplate,
|
|
330
|
+
layoutTemplate,
|
|
331
|
+
freezeAssets,
|
|
332
|
+
locale: runtimeParams?.locale,
|
|
333
|
+
basePath: runtimeParams?.basePath,
|
|
334
|
+
debug: runtimeEnvironment.debug,
|
|
335
|
+
nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function getModuleGraphCacheKey(specifier, viewLinkCacheKey) {
|
|
339
|
+
return specifier + viewLinkCacheKey;
|
|
340
|
+
}
|
package/build/es/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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 { generateViewNonce, getViewNonce, normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences, } from './utils.js';
|
|
3
|
+
import { generateViewNonce, getViewNonce, normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences, getViewDefCacheKey, } from './utils.js';
|
|
4
4
|
import { linkLwrResources } from './linkers/link-lwr-resources.js';
|
|
5
5
|
// TODO: investigate perf impact W-16056356
|
|
6
6
|
import { LRUCache } from 'lru-cache';
|
|
@@ -132,30 +132,23 @@ export class LwrViewRegistry {
|
|
|
132
132
|
const { contentTemplate, rootComponent } = viewId;
|
|
133
133
|
const compiledViewCacheKey = getCacheKeyFromJson({ contentTemplate, rootComponent });
|
|
134
134
|
logger.debug(`[view-registry][getView] compiledViewCacheKey=${compiledViewCacheKey}`);
|
|
135
|
+
// For now we are only supporting ttl 0 == skipCaching.
|
|
136
|
+
const route = this.globalConfig.routes.find((r) => r.id === viewId.id);
|
|
137
|
+
const skipCaching = route?.cache?.ttl === 0;
|
|
135
138
|
// use cached compiledView if available
|
|
136
|
-
if (this.compiledViews.has(compiledViewCacheKey)) {
|
|
139
|
+
if (!skipCaching && this.compiledViews.has(compiledViewCacheKey)) {
|
|
137
140
|
return this.compiledViews.get(compiledViewCacheKey);
|
|
138
141
|
}
|
|
139
142
|
const compiledView = await this.delegateGetView(viewId);
|
|
140
|
-
|
|
143
|
+
// cache the compiled view
|
|
144
|
+
if (!skipCaching) {
|
|
145
|
+
this.compiledViews.set(compiledViewCacheKey, compiledView);
|
|
146
|
+
}
|
|
141
147
|
return compiledView;
|
|
142
148
|
}
|
|
143
149
|
hasViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
|
|
144
|
-
const { id, bootstrap, rootComponent, contentTemplate, layoutTemplate } = view;
|
|
145
150
|
const { freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
|
|
146
|
-
const viewDefId =
|
|
147
|
-
id,
|
|
148
|
-
bootstrap,
|
|
149
|
-
rootComponent,
|
|
150
|
-
contentTemplate,
|
|
151
|
-
layoutTemplate,
|
|
152
|
-
freezeAssets,
|
|
153
|
-
locale: runtimeParams?.locale,
|
|
154
|
-
basePath: runtimeParams?.basePath,
|
|
155
|
-
debug: runtimeEnvironment.debug,
|
|
156
|
-
// Add a variable on if the nonce is enabled
|
|
157
|
-
nonceEnabled: getFeatureFlags().ENABLE_NONCE,
|
|
158
|
-
});
|
|
151
|
+
const viewDefId = getViewDefCacheKey(view, runtimeEnvironment, freezeAssets, runtimeParams);
|
|
159
152
|
logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
|
|
160
153
|
// viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
|
|
161
154
|
// to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
|
|
@@ -177,15 +170,7 @@ export class LwrViewRegistry {
|
|
|
177
170
|
runtimeParams.requestCache = runtimeParams.requestCache ?? {};
|
|
178
171
|
try {
|
|
179
172
|
const { freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
|
|
180
|
-
const viewDefCacheKey =
|
|
181
|
-
...view,
|
|
182
|
-
freezeAssets,
|
|
183
|
-
locale: runtimeParams?.locale,
|
|
184
|
-
basePath: runtimeParams?.basePath,
|
|
185
|
-
debug: runtimeEnvironment.debug,
|
|
186
|
-
// Add a variable on if the nonce is enabled
|
|
187
|
-
nonceEnabled: getFeatureFlags().ENABLE_NONCE,
|
|
188
|
-
});
|
|
173
|
+
const viewDefCacheKey = getViewDefCacheKey(view, runtimeEnvironment, freezeAssets, runtimeParams);
|
|
189
174
|
logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
|
|
190
175
|
// viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
|
|
191
176
|
// to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
|
|
@@ -214,7 +199,7 @@ export class LwrViewRegistry {
|
|
|
214
199
|
view: view.id,
|
|
215
200
|
ssr: view.bootstrap?.ssr === true,
|
|
216
201
|
},
|
|
217
|
-
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
|
|
202
|
+
}, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, pendingViewDefCacheKey, renderOptions)));
|
|
218
203
|
// Once the view is generated add the nonce to the response so it can be cached and then added to the headers
|
|
219
204
|
viewDefinition.nonce = getViewNonce(updatableViewParams);
|
|
220
205
|
const route = this.globalConfig.routes.find((r) => r.id === view.id);
|
|
@@ -248,7 +233,7 @@ export class LwrViewRegistry {
|
|
|
248
233
|
throw createSingleDiagnosticError({ description: descriptions.SERVER.UNEXPECTED_ERROR(message) }, LwrServerError);
|
|
249
234
|
}
|
|
250
235
|
}
|
|
251
|
-
async renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
|
|
236
|
+
async renderView(view, viewParams, runtimeEnvironment, runtimeParams, viewCacheKey, renderOptions) {
|
|
252
237
|
const { id, contentTemplate, rootComponent, layoutTemplate } = view;
|
|
253
238
|
const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
|
|
254
239
|
const renderedContent = await this.render({ id, contentTemplate, rootComponent }, { ...viewParams, lwr_resources: lwrResourcesId }, runtimeParams, runtimeEnvironment);
|
|
@@ -265,6 +250,7 @@ export class LwrViewRegistry {
|
|
|
265
250
|
// using any options provided by the content, overridden with invocation provided rendering options
|
|
266
251
|
renderOptions: normalizedRenderOptions,
|
|
267
252
|
contentIds: { lwrResourcesId },
|
|
253
|
+
viewCacheKey,
|
|
268
254
|
});
|
|
269
255
|
return renderedViewDef;
|
|
270
256
|
}
|
|
@@ -317,6 +303,7 @@ export class LwrViewRegistry {
|
|
|
317
303
|
// TODO: We override the importer with the original view, however
|
|
318
304
|
// Layouts relative paths won't work
|
|
319
305
|
importer: renderedContent.compiledView.filePath,
|
|
306
|
+
viewCacheKey,
|
|
320
307
|
});
|
|
321
308
|
return renderedViewDef;
|
|
322
309
|
}
|
|
@@ -347,31 +334,50 @@ export class LwrViewRegistry {
|
|
|
347
334
|
};
|
|
348
335
|
}
|
|
349
336
|
async link(renderedView, viewContext) {
|
|
350
|
-
const { view, viewParams, runtimeEnvironment: runtimeEnv, runtimeParams, renderOptions, contentIds, importer, } = viewContext;
|
|
337
|
+
const { view, viewParams, runtimeEnvironment: runtimeEnv, runtimeParams, renderOptions, contentIds, importer, viewCacheKey, } = viewContext;
|
|
351
338
|
const { skipMetadataCollection, freezeAssets } = renderOptions;
|
|
352
339
|
const { lwrResourcesId } = contentIds;
|
|
353
340
|
const { moduleRegistry, resourceRegistry, moduleBundler } = this;
|
|
354
341
|
const runtimeEnvironment = { ...runtimeEnv, immutableAssets: freezeAssets };
|
|
355
342
|
// normalize/extract metadata
|
|
356
343
|
const { renderedView: renderedViewContent, metadata: renderedViewMetadata, compiledView: { immutable = true }, } = renderedView;
|
|
357
|
-
const linkedMetadata =
|
|
358
|
-
|
|
359
|
-
:
|
|
344
|
+
const { linkedMetadata, stringBuilder } = await getTracer().trace({
|
|
345
|
+
name: ViewSpan.ParseView,
|
|
346
|
+
attributes: {
|
|
347
|
+
view: view.id,
|
|
348
|
+
ssr: view.bootstrap?.ssr === true,
|
|
349
|
+
},
|
|
350
|
+
}, async () => {
|
|
351
|
+
const linkedMetadata = skipMetadataCollection
|
|
352
|
+
? renderedViewMetadata
|
|
353
|
+
: await extractMetadataFromHtml(renderedViewContent, renderedViewMetadata, this.globalConfig);
|
|
354
|
+
const stringBuilder = createStringBuilder(renderedViewContent);
|
|
355
|
+
return { linkedMetadata, stringBuilder };
|
|
356
|
+
});
|
|
360
357
|
const mergedViewContext = {
|
|
361
358
|
...viewContext,
|
|
362
359
|
config: this.globalConfig,
|
|
363
360
|
runtimeEnvironment,
|
|
364
361
|
importer: importer || renderedView.compiledView.filePath,
|
|
365
362
|
};
|
|
366
|
-
const stringBuilder = createStringBuilder(renderedViewContent);
|
|
367
363
|
// Note: this is the TTL for the page NOT for the view registry cache
|
|
368
364
|
let pageTtl = renderedView.cache.ttl;
|
|
365
|
+
let pageRedirect = renderedView.redirect;
|
|
369
366
|
for (const viewTransformer of this.viewTransformers) {
|
|
370
367
|
// eslint-disable-next-line no-await-in-loop
|
|
371
|
-
const linkResults = await
|
|
368
|
+
const linkResults = await getTracer().trace({
|
|
369
|
+
name: ViewSpan.Transform,
|
|
370
|
+
attributes: {
|
|
371
|
+
name: viewTransformer.name,
|
|
372
|
+
},
|
|
373
|
+
}, () => viewTransformer.link?.(stringBuilder, mergedViewContext, linkedMetadata));
|
|
372
374
|
// Keep track of the shortest TTL from each view transformer (e.g. lwcSsrViewTransformer)
|
|
373
375
|
const ttl = linkResults && linkResults.cache?.ttl;
|
|
374
376
|
pageTtl = shortestTtl(ttl || undefined, pageTtl);
|
|
377
|
+
// Set the redirect info, if it doesn't already exist
|
|
378
|
+
if (!pageRedirect) {
|
|
379
|
+
pageRedirect = linkResults ? linkResults.redirect : undefined;
|
|
380
|
+
}
|
|
375
381
|
}
|
|
376
382
|
const linkedAssetContent = stringBuilder.toString();
|
|
377
383
|
// Link LWR related resources
|
|
@@ -387,6 +393,9 @@ export class LwrViewRegistry {
|
|
|
387
393
|
runtimeEnvironment,
|
|
388
394
|
runtimeParams,
|
|
389
395
|
bundleConfig: this.globalConfig.bundleConfig,
|
|
396
|
+
unsafeEnableViewLinkCaching: this.globalConfig.unsafeEnableViewLinkCaching,
|
|
397
|
+
// Use the same cache key for the link stage
|
|
398
|
+
viewLinkCacheKey: viewCacheKey,
|
|
390
399
|
});
|
|
391
400
|
return {
|
|
392
401
|
// ...viewDefinition,
|
|
@@ -397,7 +406,7 @@ export class LwrViewRegistry {
|
|
|
397
406
|
...viewRecord,
|
|
398
407
|
},
|
|
399
408
|
cache: { ttl: pageTtl },
|
|
400
|
-
redirect:
|
|
409
|
+
redirect: pageRedirect,
|
|
401
410
|
};
|
|
402
411
|
}
|
|
403
412
|
return {
|
|
@@ -408,7 +417,7 @@ export class LwrViewRegistry {
|
|
|
408
417
|
moduleResources: [],
|
|
409
418
|
},
|
|
410
419
|
cache: { ttl: pageTtl },
|
|
411
|
-
redirect:
|
|
420
|
+
redirect: pageRedirect,
|
|
412
421
|
};
|
|
413
422
|
}
|
|
414
423
|
}
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
lwrResourcesId: string;
|
|
4
|
-
}
|
|
5
|
-
interface ResourceContext {
|
|
6
|
-
viewMetadata: RenderedViewMetadata;
|
|
7
|
-
runtimeEnvironment: RuntimeEnvironment;
|
|
8
|
-
runtimeParams: RuntimeParams;
|
|
9
|
-
moduleRegistry: ModuleRegistry;
|
|
10
|
-
moduleBundler: ModuleBundler;
|
|
11
|
-
resourceRegistry: ResourceRegistry;
|
|
12
|
-
bundleConfig: BundleConfig;
|
|
13
|
-
}
|
|
1
|
+
import type { RenderedViewRecord, View, ViewParams } from '@lwrjs/types';
|
|
2
|
+
import type { ResourceContext } from './link-lwr-resources.js';
|
|
14
3
|
export declare function getHtmlResources(view: View, viewParams: ViewParams, resourceContext: ResourceContext): Promise<{
|
|
15
4
|
partial: string;
|
|
16
5
|
viewRecord: RenderedViewRecord;
|
|
17
6
|
}>;
|
|
18
|
-
export {};
|
|
19
7
|
//# sourceMappingURL=legacy_view_bootstrap.d.ts.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { logger } from '@lwrjs/diagnostics';
|
|
2
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 { addExternalScriptNonce, generateHtmlTag, getModuleResource, getModuleResourceByUri, getViewNonce, } from '../utils.js';
|
|
4
|
+
import { addExternalScriptNonce, generateHtmlTag, getModuleResource, getModuleResourceByUri, getViewNonce, getModuleGraphCacheKey, } from '../utils.js';
|
|
5
5
|
import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
6
6
|
import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
|
|
7
|
+
import { LRUCache } from 'lru-cache';
|
|
7
8
|
function includeIdFactory(bundleConfig) {
|
|
8
9
|
return (moduleRef) => {
|
|
9
10
|
// Do not bundle externals, including the loader module, which is auto bundled
|
|
@@ -15,15 +16,20 @@ function includeIdFactory(bundleConfig) {
|
|
|
15
16
|
return true;
|
|
16
17
|
};
|
|
17
18
|
}
|
|
19
|
+
// `getModuleGraphs` is very expensive and does not need to be recomputed every time.
|
|
20
|
+
// Note: we use the same cache key passed in from the top level view-registry for consistency
|
|
21
|
+
const moduleGraphsCache = new LRUCache({ max: 500 });
|
|
22
|
+
const isRunningLocalDev = isLocalDev();
|
|
18
23
|
export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
19
|
-
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
|
|
24
|
+
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, viewLinkCacheKey, } = resourceContext;
|
|
20
25
|
const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
|
|
21
26
|
const { customElements, serverData, serverDebug } = viewMetadata;
|
|
22
27
|
const isAMD = format === 'amd';
|
|
23
|
-
const { bundleConfig } = resourceContext;
|
|
28
|
+
const { bundleConfig, unsafeEnableViewLinkCaching } = resourceContext;
|
|
24
29
|
const { external = {}, exclude = [] } = bundleConfig;
|
|
25
30
|
// Bundling groups is only supported in AMD for now
|
|
26
31
|
const groups = isAMD ? bundleConfig.groups || {} : {};
|
|
32
|
+
const enableModuleGraphsCache = unsafeEnableViewLinkCaching && !isRunningLocalDev && !process.env.NOCACHE;
|
|
27
33
|
const getPreloadUri = function (rawSpecifier, uriMap) {
|
|
28
34
|
const { specifier } = explodeSpecifier(rawSpecifier);
|
|
29
35
|
// do not preload externals; this is the app's responsibility
|
|
@@ -151,7 +157,16 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
151
157
|
// Traversal of the Bootstrap Module Graph is done to get all the URLS for discoverable static dependencies.
|
|
152
158
|
// Reasoning: This is to avoid unnecessary HTTP 302's during initial application module fetching.
|
|
153
159
|
// Scope: ESM currently only exposes immutable URI references, optimize for AMD formats
|
|
154
|
-
|
|
160
|
+
let bootstrapModuleGraph;
|
|
161
|
+
const bootstrapModuleGraphCacheKey = getModuleGraphCacheKey(bootstrapSpecifier, viewLinkCacheKey);
|
|
162
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(bootstrapModuleGraphCacheKey)) {
|
|
163
|
+
bootstrapModuleGraph = moduleGraphsCache.get(bootstrapModuleGraphCacheKey);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
bootstrapModuleGraph = await getModuleGraphs(bootstrapSpecifier, { includeUris: true, includeLinkedDefinitions: true, depth }, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
167
|
+
enableModuleGraphsCache &&
|
|
168
|
+
moduleGraphsCache.set(bootstrapModuleGraphCacheKey, bootstrapModuleGraph);
|
|
169
|
+
}
|
|
155
170
|
bootstrapModuleRef = {
|
|
156
171
|
specifier: bootstrapModuleGraph.graphs[0].specifier,
|
|
157
172
|
flatGraph: bootstrapModuleGraph,
|
|
@@ -215,7 +230,15 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
215
230
|
await Promise.all(flattenedElements.map(async ({ tagName: element, props }) => {
|
|
216
231
|
const hydrateDirective = getHydrateDirective(props);
|
|
217
232
|
const isSsrOnly = isSSR && !hydrateDirective;
|
|
218
|
-
const
|
|
233
|
+
const moduleGraphCacheKey = getModuleGraphCacheKey(element, viewLinkCacheKey);
|
|
234
|
+
let graph;
|
|
235
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(moduleGraphCacheKey)) {
|
|
236
|
+
graph = moduleGraphsCache.get(moduleGraphCacheKey);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
graph = await getModuleGraphs(kebabCaseToModuleSpecifier(element), { includeUris: true, includeLinkedDefinitions: true, depth }, moduleRegistry, defRegistry, runtimeEnvironment, { ...runtimeParams, ssr: isSsrOnly }, visitedCache);
|
|
240
|
+
enableModuleGraphsCache && moduleGraphsCache.set(moduleGraphCacheKey, graph);
|
|
241
|
+
}
|
|
219
242
|
// add to the viewRecord
|
|
220
243
|
customElementsRecords.push({ elementName: element, flatGraph: graph });
|
|
221
244
|
// Only process custom elements that are to be hydrated or are CSR-only islands
|
|
@@ -2,7 +2,7 @@ import type { ModuleRegistry, LinkedViewDefinition, RenderedViewMetadata, Resour
|
|
|
2
2
|
export interface LwrResourcesLinkedContext extends ResourceContext {
|
|
3
3
|
lwrResourcesId: string;
|
|
4
4
|
}
|
|
5
|
-
interface ResourceContext {
|
|
5
|
+
export interface ResourceContext {
|
|
6
6
|
viewMetadata: RenderedViewMetadata;
|
|
7
7
|
runtimeEnvironment: RuntimeEnvironment;
|
|
8
8
|
runtimeParams: RuntimeParams;
|
|
@@ -10,6 +10,8 @@ interface ResourceContext {
|
|
|
10
10
|
moduleBundler: ModuleBundler;
|
|
11
11
|
resourceRegistry: ResourceRegistry;
|
|
12
12
|
bundleConfig: BundleConfig;
|
|
13
|
+
unsafeEnableViewLinkCaching: boolean;
|
|
14
|
+
viewLinkCacheKey: string;
|
|
13
15
|
}
|
|
14
16
|
type LinkedResourcesViewDefinition = Pick<LinkedViewDefinition, 'renderedView' | 'viewRecord'>;
|
|
15
17
|
export declare function linkLwrResources(source: string, view: View, viewParams: ViewParams, cxt: LwrResourcesLinkedContext): Promise<LinkedResourcesViewDefinition>;
|
|
@@ -4,22 +4,22 @@ import { getHtmlResources as getLegacyHtmlResource } from './legacy_view_bootstr
|
|
|
4
4
|
export async function linkLwrResources(source, view, viewParams, cxt) {
|
|
5
5
|
const { lwrResourcesId, ...resourceContext } = cxt;
|
|
6
6
|
const LEGACY_LOADER = !!resourceContext.runtimeEnvironment.featureFlags.LEGACY_LOADER;
|
|
7
|
-
|
|
7
|
+
return await getTracer().trace({
|
|
8
8
|
name: ViewSpan.Generate,
|
|
9
9
|
attributes: {
|
|
10
10
|
legacyLoader: LEGACY_LOADER,
|
|
11
11
|
},
|
|
12
|
-
}, () => {
|
|
13
|
-
|
|
12
|
+
}, async () => {
|
|
13
|
+
const { partial, viewRecord } = await (LEGACY_LOADER
|
|
14
14
|
? getLegacyHtmlResource(view, viewParams, resourceContext)
|
|
15
|
-
: getHtmlResources(view, viewParams, resourceContext);
|
|
15
|
+
: getHtmlResources(view, viewParams, resourceContext));
|
|
16
|
+
// Finally replace the token with the real resources
|
|
17
|
+
return {
|
|
18
|
+
// partial may contain regex-token-like characters such as $$,
|
|
19
|
+
// so we want to bypass regex replacement
|
|
20
|
+
renderedView: source.replace(lwrResourcesId, () => partial),
|
|
21
|
+
viewRecord,
|
|
22
|
+
};
|
|
16
23
|
});
|
|
17
|
-
// Finally replace the token with the real resources
|
|
18
|
-
return {
|
|
19
|
-
// partial may contain regex-token-like characters such as $$,
|
|
20
|
-
// so we want to bypass regex replacement
|
|
21
|
-
renderedView: source.replace(lwrResourcesId, () => partial),
|
|
22
|
-
viewRecord,
|
|
23
|
-
};
|
|
24
24
|
}
|
|
25
25
|
//# sourceMappingURL=link-lwr-resources.js.map
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
lwrResourcesId: string;
|
|
4
|
-
}
|
|
5
|
-
interface ResourceContext {
|
|
6
|
-
viewMetadata: RenderedViewMetadata;
|
|
7
|
-
runtimeEnvironment: RuntimeEnvironment;
|
|
8
|
-
runtimeParams: RuntimeParams;
|
|
9
|
-
moduleRegistry: ModuleRegistry;
|
|
10
|
-
moduleBundler: ModuleBundler;
|
|
11
|
-
resourceRegistry: ResourceRegistry;
|
|
12
|
-
bundleConfig: BundleConfig;
|
|
13
|
-
}
|
|
1
|
+
import type { RenderedViewRecord, View, ViewParams } from '@lwrjs/types';
|
|
2
|
+
import type { ResourceContext } from './link-lwr-resources.js';
|
|
14
3
|
export declare function getHtmlResources(view: View, viewParams: ViewParams, resourceContext: ResourceContext): Promise<{
|
|
15
4
|
partial: string;
|
|
16
5
|
viewRecord: RenderedViewRecord;
|
|
17
6
|
}>;
|
|
18
|
-
export {};
|
|
19
7
|
//# sourceMappingURL=view_bootstrap.d.ts.map
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { logger } from '@lwrjs/diagnostics';
|
|
2
|
-
import { kebabCaseToModuleSpecifier, toImportMetadata, getModuleGraphs, getMappingUriPrefix, GraphDepth, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, } from '@lwrjs/shared-utils';
|
|
2
|
+
import { kebabCaseToModuleSpecifier, toImportMetadata, getModuleGraphs, getMappingUriPrefix, GraphDepth, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, isLocalDev, } from '@lwrjs/shared-utils';
|
|
3
|
+
import { LRUCache } from 'lru-cache';
|
|
3
4
|
import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
|
|
4
5
|
import { addExternalScriptNonce, generateHtmlTag, getModuleResourceByUri, getViewNonce } from '../utils.js';
|
|
5
6
|
import { flattenCustomElements, getBundleIntegrity, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
|
|
7
|
+
import { getModuleGraphCacheKey } from '../utils.js';
|
|
6
8
|
import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
|
|
9
|
+
// `getModuleGraphs` is very expensive and does not need to be recomputed every time.
|
|
10
|
+
// Note: we use the same cache key passed in from the top level view-registry for consistency
|
|
11
|
+
const moduleGraphsCache = new LRUCache({ max: 500 });
|
|
12
|
+
const isRunningLocalDev = isLocalDev();
|
|
7
13
|
export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
8
|
-
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
|
|
14
|
+
const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, viewLinkCacheKey, } = resourceContext;
|
|
9
15
|
const { format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
|
|
10
16
|
const { customElements, serverData, serverDebug } = viewMetadata;
|
|
11
17
|
const defRegistry = bundle ? moduleBundler : moduleRegistry;
|
|
@@ -13,10 +19,11 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
13
19
|
const depth = isAMD
|
|
14
20
|
? { static: GraphDepth.ALL, dynamic: 1 }
|
|
15
21
|
: { static: GraphDepth.NONE, dynamic: 1 };
|
|
16
|
-
const { bundleConfig } = resourceContext;
|
|
22
|
+
const { bundleConfig, unsafeEnableViewLinkCaching } = resourceContext;
|
|
17
23
|
const { external = {}, exclude = [] } = bundleConfig;
|
|
18
24
|
// Bundling groups is only supported in AMD for now
|
|
19
25
|
const groups = isAMD ? bundleConfig.groups || {} : {};
|
|
26
|
+
const enableModuleGraphsCache = unsafeEnableViewLinkCaching && !isRunningLocalDev && !process.env.NOCACHE;
|
|
20
27
|
const getPreloadUri = function (rawSpecifier, uriMap) {
|
|
21
28
|
const { specifier } = explodeSpecifier(rawSpecifier);
|
|
22
29
|
if (Object.keys(external).some((e) => specifier === e))
|
|
@@ -118,7 +125,16 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
118
125
|
// ------- Application Bootstrap module
|
|
119
126
|
// Traversal of the Bootstrap Module Graph is done to get all the URLS for discoverable static dependencies.
|
|
120
127
|
// Reasoning: This is to avoid unnecessary HTTP 302's during initial application module fetching.
|
|
121
|
-
|
|
128
|
+
let bootstrapModuleGraph;
|
|
129
|
+
const bootstrapModuleGraphCacheKey = getModuleGraphCacheKey(bootstrapSpecifier, viewLinkCacheKey);
|
|
130
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(bootstrapModuleGraphCacheKey)) {
|
|
131
|
+
bootstrapModuleGraph = moduleGraphsCache.get(bootstrapModuleGraphCacheKey);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
bootstrapModuleGraph = await getModuleGraphs(bootstrapSpecifier, { includeUris: true, includeLinkedDefinitions: true, depth }, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
|
|
135
|
+
enableModuleGraphsCache &&
|
|
136
|
+
moduleGraphsCache.set(bootstrapModuleGraphCacheKey, bootstrapModuleGraph);
|
|
137
|
+
}
|
|
122
138
|
bootstrapModuleRef = {
|
|
123
139
|
specifier: bootstrapModuleGraph.graphs[0].specifier,
|
|
124
140
|
flatGraph: bootstrapModuleGraph,
|
|
@@ -183,8 +199,16 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
|
|
|
183
199
|
for (const { tagName: element, props } of flattenedElements) {
|
|
184
200
|
const hydrateDirective = getHydrateDirective(props);
|
|
185
201
|
const isSsrOnly = isSSR && !hydrateDirective;
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
const moduleGraphCacheKey = getModuleGraphCacheKey(element, viewLinkCacheKey);
|
|
203
|
+
let graph;
|
|
204
|
+
if (enableModuleGraphsCache && moduleGraphsCache.has(moduleGraphCacheKey)) {
|
|
205
|
+
graph = moduleGraphsCache.get(moduleGraphCacheKey);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// eslint-disable-next-line no-await-in-loop
|
|
209
|
+
graph = await getModuleGraphs(kebabCaseToModuleSpecifier(element), { includeUris: true, includeLinkedDefinitions: true, depth }, moduleRegistry, defRegistry, runtimeEnvironment, { ...runtimeParams, ssr: isSsrOnly }, visitedCache);
|
|
210
|
+
enableModuleGraphsCache && moduleGraphsCache.set(moduleGraphCacheKey, graph);
|
|
211
|
+
}
|
|
188
212
|
// add to the viewRecord
|
|
189
213
|
customElementsRecords.push({ elementName: element, flatGraph: graph });
|
|
190
214
|
// Only process custom elements that are to be hydrated or are CSR-only islands
|
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, ViewParams, ViewRequest, ViewResponse, ViewDefinitionResponse } 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, ViewDefinitionResponse, View } 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, redirect, }: RenderingResult): NormalizedRenderingResult;
|
|
@@ -24,4 +24,6 @@ export declare function generateViewNonce(viewParams: ViewParams): void;
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function addExternalScriptNonce(def: ResourceDefinition, nonce?: string): void;
|
|
26
26
|
export declare function generateLinkHeaders(assets: RenderedAssetReference[], patterns: Record<string, any>[]): string;
|
|
27
|
+
export declare function getViewDefCacheKey(view: View, runtimeEnvironment: RuntimeEnvironment, freezeAssets: boolean, runtimeParams?: RuntimeParams): string;
|
|
28
|
+
export declare function getModuleGraphCacheKey(specifier: string, viewLinkCacheKey: string): string;
|
|
27
29
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/es/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, extname } from 'path';
|
|
2
|
-
import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, getFeatureFlags, } from '@lwrjs/shared-utils';
|
|
2
|
+
import { explodeSpecifier, getMappingUriPrefix, getSpecifier, getClientBootstrapConfigurationUri, mimeLookup, DEFAULT_TITLE, streamToString, getFeatureFlags, getCacheKeyFromJson, } from '@lwrjs/shared-utils';
|
|
3
3
|
import { AppResourceEnum, getAppSpecifier, ResourceIdentityTypes, } from '@lwrjs/app-service/identity';
|
|
4
4
|
import crypto from 'crypto';
|
|
5
5
|
function generateExternalStyle(src) {
|
|
@@ -312,4 +312,23 @@ export function generateLinkHeaders(assets, patterns) {
|
|
|
312
312
|
return linkHeader;
|
|
313
313
|
}, '');
|
|
314
314
|
}
|
|
315
|
+
export function getViewDefCacheKey(view, runtimeEnvironment, freezeAssets, runtimeParams) {
|
|
316
|
+
const { id, bootstrap, rootComponent, contentTemplate, layoutTemplate } = view;
|
|
317
|
+
return getCacheKeyFromJson({
|
|
318
|
+
id,
|
|
319
|
+
bootstrap,
|
|
320
|
+
rootComponent,
|
|
321
|
+
contentTemplate,
|
|
322
|
+
layoutTemplate,
|
|
323
|
+
freezeAssets,
|
|
324
|
+
locale: runtimeParams?.locale,
|
|
325
|
+
basePath: runtimeParams?.basePath,
|
|
326
|
+
debug: runtimeEnvironment.debug,
|
|
327
|
+
// Add a variable on if the nonce is enabled
|
|
328
|
+
nonceEnabled: getFeatureFlags().ENABLE_NONCE,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
export function getModuleGraphCacheKey(specifier, viewLinkCacheKey) {
|
|
332
|
+
return specifier + viewLinkCacheKey;
|
|
333
|
+
}
|
|
315
334
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.15.0-alpha.
|
|
7
|
+
"version": "0.15.0-alpha.28",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -33,17 +33,20 @@
|
|
|
33
33
|
"build": "tsc -b"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@lwrjs/app-service": "0.15.0-alpha.
|
|
37
|
-
"@lwrjs/diagnostics": "0.15.0-alpha.
|
|
38
|
-
"@lwrjs/instrumentation": "0.15.0-alpha.
|
|
39
|
-
"@lwrjs/shared-utils": "0.15.0-alpha.
|
|
36
|
+
"@lwrjs/app-service": "0.15.0-alpha.28",
|
|
37
|
+
"@lwrjs/diagnostics": "0.15.0-alpha.28",
|
|
38
|
+
"@lwrjs/instrumentation": "0.15.0-alpha.28",
|
|
39
|
+
"@lwrjs/shared-utils": "0.15.0-alpha.28",
|
|
40
40
|
"lru-cache": "^10.4.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@lwrjs/types": "0.15.0-alpha.
|
|
43
|
+
"@lwrjs/types": "0.15.0-alpha.28"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=18.0.0"
|
|
47
47
|
},
|
|
48
|
-
"
|
|
48
|
+
"volta": {
|
|
49
|
+
"extends": "../../../package.json"
|
|
50
|
+
},
|
|
51
|
+
"gitHead": "b14e7aab8eee6aa8f1b2a05cad098f9ef65e9ef4"
|
|
49
52
|
}
|