@lwrjs/view-registry 0.15.0-alpha.3 → 0.15.0-alpha.30

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.
@@ -51,7 +51,12 @@ var LwrViewRegistry = class {
51
51
  this.globalData = context.globalData;
52
52
  this.appEmitter = context.appEmitter;
53
53
  const observer = context.appObserver;
54
- this.viewDefinitions = new import_lru_cache.LRUCache({max: parseInt(process.env.VIEW_CACHE_SIZE || "500", 10)});
54
+ this.viewDefinitions = new import_lru_cache.LRUCache({
55
+ max: parseInt(process.env.VIEW_CACHE_SIZE ?? "500", 10),
56
+ dispose: (_value, key) => {
57
+ import_diagnostics.logger.verbose(`View evicted from cache ${key}`);
58
+ }
59
+ });
55
60
  observer.onViewSourceChange(({payload}) => this.onViewSourceChange(payload));
56
61
  observer.onModuleDefinitionChange(({payload}) => this.onModuleDefinitionChange(payload));
57
62
  observer.onAssetSourceChange(({payload}) => this.onAssetSourceChange(payload));
@@ -140,28 +145,20 @@ var LwrViewRegistry = class {
140
145
  const {contentTemplate, rootComponent} = viewId;
141
146
  const compiledViewCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({contentTemplate, rootComponent});
142
147
  import_diagnostics.logger.debug(`[view-registry][getView] compiledViewCacheKey=${compiledViewCacheKey}`);
143
- if (this.compiledViews.has(compiledViewCacheKey)) {
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)) {
144
151
  return this.compiledViews.get(compiledViewCacheKey);
145
152
  }
146
153
  const compiledView = await this.delegateGetView(viewId);
147
- this.compiledViews.set(compiledViewCacheKey, compiledView);
154
+ if (!skipCaching) {
155
+ this.compiledViews.set(compiledViewCacheKey, compiledView);
156
+ }
148
157
  return compiledView;
149
158
  }
150
159
  hasViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
151
- const {id, bootstrap, rootComponent, contentTemplate, layoutTemplate} = view;
152
160
  const {freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
153
- const viewDefId = (0, import_shared_utils.getCacheKeyFromJson)({
154
- id,
155
- bootstrap,
156
- rootComponent,
157
- contentTemplate,
158
- layoutTemplate,
159
- freezeAssets,
160
- locale: runtimeParams?.locale,
161
- basePath: runtimeParams?.basePath,
162
- debug: runtimeEnvironment.debug,
163
- nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
164
- });
161
+ const viewDefId = (0, import_utils.getViewDefCacheKey)(view, runtimeEnvironment, freezeAssets, runtimeParams);
165
162
  import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewDefId=${viewDefId}`);
166
163
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
167
164
  import_diagnostics.logger.debug(`[view-registry][hasViewDefinition] viewParamKey=${viewParamKey}`);
@@ -173,22 +170,16 @@ var LwrViewRegistry = class {
173
170
  }
174
171
  return false;
175
172
  }
176
- async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
173
+ async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams = {requestCache: {}}, renderOptions) {
174
+ runtimeParams.requestCache = runtimeParams.requestCache ?? {};
177
175
  try {
178
176
  const {freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
179
- const viewDefCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({
180
- ...view,
181
- freezeAssets,
182
- locale: runtimeParams?.locale,
183
- basePath: runtimeParams?.basePath,
184
- debug: runtimeEnvironment.debug,
185
- nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
186
- });
177
+ const viewDefCacheKey = (0, import_utils.getViewDefCacheKey)(view, runtimeEnvironment, freezeAssets, runtimeParams);
187
178
  import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
188
179
  const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
189
180
  import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
190
- if (this.viewDefinitions.has(viewDefCacheKey)) {
191
- const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey);
181
+ if (this.viewDefinitions.has(viewDefCacheKey) || runtimeParams.requestCache[viewDefCacheKey]) {
182
+ const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey) || runtimeParams.requestCache[viewDefCacheKey];
192
183
  if (viewDefinition2 && viewDefinition2.paramKey === viewParamKey && viewDefinition2.viewDefinition.immutable) {
193
184
  return viewDefinition2.viewDefinition;
194
185
  }
@@ -202,18 +193,19 @@ var LwrViewRegistry = class {
202
193
  view: view.id,
203
194
  ssr: view.bootstrap?.ssr === true
204
195
  }
205
- }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, renderOptions)));
196
+ }, () => this.renderView(view, updatableViewParams, runtimeEnvironment, runtimeParams, pendingViewDefCacheKey, renderOptions)));
206
197
  viewDefinition.nonce = (0, import_utils.getViewNonce)(updatableViewParams);
207
198
  const route = this.globalConfig.routes.find((r) => r.id === view.id);
208
199
  const maxViewCacheTtl = (0, import_shared_utils.getFeatureFlags)().MAX_VIEW_CACHE_TTL;
209
200
  const maxTtl = maxViewCacheTtl && parseInt(maxViewCacheTtl, 10);
210
201
  const leastTtl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl, maxTtl);
211
202
  const ttl = leastTtl !== void 0 ? leastTtl === 0 ? 10 : leastTtl * 1e3 : void 0;
212
- this.viewDefinitions.set(viewDefCacheKey, {
213
- view,
214
- viewDefinition,
215
- paramKey: viewParamKey
216
- }, {ttl});
203
+ const viewDefCacheEntry = {view, viewDefinition, paramKey: viewParamKey};
204
+ if (view.bootstrap?.includeCookiesForSSR) {
205
+ runtimeParams.requestCache[viewDefCacheKey] = viewDefCacheEntry;
206
+ } else {
207
+ this.viewDefinitions.set(viewDefCacheKey, viewDefCacheEntry, {ttl});
208
+ }
217
209
  return viewDefinition;
218
210
  } catch (err) {
219
211
  if (err instanceof import_diagnostics.DiagnosticsError) {
@@ -225,10 +217,10 @@ var LwrViewRegistry = class {
225
217
  throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.SERVER.UNEXPECTED_ERROR(message)}, import_diagnostics.LwrServerError);
226
218
  }
227
219
  }
228
- async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
220
+ async renderView(view, viewParams, runtimeEnvironment, runtimeParams, viewCacheKey, renderOptions) {
229
221
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
230
222
  const lwrResourcesId = `__LWR_RESOURCES__${Date.now()}`;
231
- const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment, renderOptions);
223
+ const renderedContent = await this.render({id, contentTemplate, rootComponent}, {...viewParams, lwr_resources: lwrResourcesId}, runtimeParams, runtimeEnvironment);
232
224
  let normalizedRenderOptions = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderedContent.options, renderOptions);
233
225
  const layout = layoutTemplate || renderedContent.compiledView.layoutTemplate;
234
226
  if (!layout) {
@@ -238,7 +230,8 @@ var LwrViewRegistry = class {
238
230
  runtimeEnvironment,
239
231
  runtimeParams,
240
232
  renderOptions: normalizedRenderOptions,
241
- contentIds: {lwrResourcesId}
233
+ contentIds: {lwrResourcesId},
234
+ viewCacheKey
242
235
  });
243
236
  return renderedViewDef2;
244
237
  }
@@ -274,7 +267,8 @@ var LwrViewRegistry = class {
274
267
  ...renderedLayout.metadata.serverDebug
275
268
  }
276
269
  },
277
- cache: renderedContent.cache
270
+ cache: renderedContent.cache,
271
+ redirect: renderedContent.redirect
278
272
  }, {
279
273
  view: {...view, layoutTemplate: layoutTemplatePath},
280
274
  viewParams,
@@ -282,11 +276,12 @@ var LwrViewRegistry = class {
282
276
  runtimeParams,
283
277
  renderOptions: normalizedRenderOptions,
284
278
  contentIds: {lwrResourcesId},
285
- importer: renderedContent.compiledView.filePath
279
+ importer: renderedContent.compiledView.filePath,
280
+ viewCacheKey
286
281
  });
287
282
  return renderedViewDef;
288
283
  }
289
- async render(viewId, viewParams, runtimeParams, runtimeEnvironment, renderOptions) {
284
+ async render(viewId, viewParams, runtimeParams, runtimeEnvironment) {
290
285
  const globalContext = this.globalData;
291
286
  const {id, rootComponent, contentTemplate} = viewId;
292
287
  const compiledView = await this.getView({id, contentTemplate, rootComponent});
@@ -310,7 +305,8 @@ var LwrViewRegistry = class {
310
305
  runtimeParams,
311
306
  renderOptions,
312
307
  contentIds,
313
- importer
308
+ importer,
309
+ viewCacheKey
314
310
  } = viewContext;
315
311
  const {skipMetadataCollection, freezeAssets} = renderOptions;
316
312
  const {lwrResourcesId} = contentIds;
@@ -321,19 +317,37 @@ var LwrViewRegistry = class {
321
317
  metadata: renderedViewMetadata,
322
318
  compiledView: {immutable = true}
323
319
  } = renderedView;
324
- const linkedMetadata = skipMetadataCollection ? renderedViewMetadata : await (0, import_shared_utils.extractMetadataFromHtml)(renderedViewContent, renderedViewMetadata, this.globalConfig);
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
+ });
325
331
  const mergedViewContext = {
326
332
  ...viewContext,
327
333
  config: this.globalConfig,
328
334
  runtimeEnvironment,
329
335
  importer: importer || renderedView.compiledView.filePath
330
336
  };
331
- const stringBuilder = (0, import_shared_utils.createStringBuilder)(renderedViewContent);
332
337
  let pageTtl = renderedView.cache.ttl;
338
+ let pageRedirect = renderedView.redirect;
333
339
  for (const viewTransformer of this.viewTransformers) {
334
- const linkResults = await viewTransformer.link?.(stringBuilder, mergedViewContext, linkedMetadata);
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));
335
346
  const ttl = linkResults && linkResults.cache?.ttl;
336
347
  pageTtl = (0, import_shared_utils.shortestTtl)(ttl || void 0, pageTtl);
348
+ if (!pageRedirect) {
349
+ pageRedirect = linkResults ? linkResults.redirect : void 0;
350
+ }
337
351
  }
338
352
  const linkedAssetContent = stringBuilder.toString();
339
353
  if (linkedAssetContent.includes(lwrResourcesId)) {
@@ -345,7 +359,9 @@ var LwrViewRegistry = class {
345
359
  resourceRegistry,
346
360
  runtimeEnvironment,
347
361
  runtimeParams,
348
- bundleConfig: this.globalConfig.bundleConfig
362
+ bundleConfig: this.globalConfig.bundleConfig,
363
+ unsafeEnableViewLinkCaching: this.globalConfig.unsafeEnableViewLinkCaching,
364
+ viewLinkCacheKey: viewCacheKey
349
365
  });
350
366
  return {
351
367
  renderedView: linkedView,
@@ -354,7 +370,8 @@ var LwrViewRegistry = class {
354
370
  assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
355
371
  ...viewRecord
356
372
  },
357
- cache: {ttl: pageTtl}
373
+ cache: {ttl: pageTtl},
374
+ redirect: pageRedirect
358
375
  };
359
376
  }
360
377
  return {
@@ -364,7 +381,8 @@ var LwrViewRegistry = class {
364
381
  assetReferences: (0, import_utils.reduceSourceAssetReferences)(linkedMetadata.assetReferences),
365
382
  moduleResources: []
366
383
  },
367
- cache: {ttl: pageTtl}
384
+ cache: {ttl: pageTtl},
385
+ redirect: pageRedirect
368
386
  };
369
387
  }
370
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
- const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
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,
@@ -188,7 +200,16 @@ async function getHtmlResources(view, viewParams, resourceContext) {
188
200
  }
189
201
  }
190
202
  await Promise.all(flattenedElements.map(async ({tagName: element, props}) => {
191
- const graph = await (0, import_shared_utils.getModuleGraphs)((0, import_shared_utils.kebabCaseToModuleSpecifier)(element), {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams ? runtimeParams : {}, visitedCache);
203
+ const hydrateDirective = (0, import_shared_utils.getHydrateDirective)(props);
204
+ const isSsrOnly = isSSR && !hydrateDirective;
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
+ }
192
213
  customElementsRecords.push({elementName: element, flatGraph: graph});
193
214
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
194
215
  const specifier = graph.graphs[0].specifier;
@@ -231,7 +252,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
231
252
  url: viewParams?.page?.url,
232
253
  configAsSrc: view.bootstrap?.configAsSrc || false,
233
254
  mixedMode: view.bootstrap?.mixedMode || false,
234
- nonce: viewParams?.page?.nonce
255
+ nonce: viewParams?.page?.nonce,
256
+ ssr: view.bootstrap?.ssr || false
235
257
  }, {
236
258
  appId: appIdentity.appName,
237
259
  bootstrapModule: versionedSpecifier,
@@ -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
- const {partial, viewRecord} = await (0, import_instrumentation.getTracer)().trace({
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
- return LEGACY_LOADER ? (0, import_legacy_view_bootstrap.getHtmlResources)(view, viewParams, resourceContext) : (0, import_view_bootstrap.getHtmlResources)(view, viewParams, resourceContext);
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
  }
@@ -63,7 +63,7 @@ function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironm
63
63
  })});`,
64
64
  `globalThis.LWR = {...globalThis.LWR, env: ${JSON.stringify(lwrEnv)}};`,
65
65
  `globalThis.process={...globalThis.process,env:{...globalThis.process?.env,...${JSON.stringify(nodeEnv)}}};`,
66
- `globalThis.lwcRuntimeFlags = { ENABLE_MIXED_SHADOW_MODE: ${viewInfo.mixedMode} };`,
66
+ `globalThis.lwcRuntimeFlags = { ENABLE_MIXED_SHADOW_MODE: ${viewInfo.mixedMode}, ENABLE_WIRE_SYNC_EMIT: ${viewInfo.ssr} };`,
67
67
  debug && debugMessage && `console.error(${JSON.stringify(debugMessage)});`
68
68
  ].filter(Boolean).join("\n");
69
69
  if (viewInfo.configAsSrc) {
@@ -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
- const bootstrapModuleGraph = await (0, import_shared_utils.getModuleGraphs)(bootstrapSpecifier, {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams, visitedCache);
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,
@@ -169,7 +182,16 @@ async function getHtmlResources(view, viewParams, resourceContext) {
169
182
  importMetadata = await (0, import_shared_utils.toImportMetadata)(bootstrapModuleGraph, {imports: {}, index: {}}, moduleRegistry, runtimeEnvironment, runtimeParams);
170
183
  }
171
184
  for (const {tagName: element, props} of flattenedElements) {
172
- const graph = await (0, import_shared_utils.getModuleGraphs)((0, import_shared_utils.kebabCaseToModuleSpecifier)(element), {includeUris: true, includeLinkedDefinitions: true, depth}, moduleRegistry, defRegistry, runtimeEnvironment, runtimeParams ? runtimeParams : {}, visitedCache);
185
+ const hydrateDirective = (0, import_shared_utils.getHydrateDirective)(props);
186
+ const isSsrOnly = isSSR && !hydrateDirective;
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
+ }
173
195
  customElementsRecords.push({elementName: element, flatGraph: graph});
174
196
  if (!isSSR || (0, import_shared_utils.getHydrateDirective)(props)) {
175
197
  const specifier = graph.graphs[0].specifier;
@@ -206,7 +228,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
206
228
  url: viewParams?.page?.url,
207
229
  configAsSrc: view.bootstrap?.configAsSrc || false,
208
230
  mixedMode: view.bootstrap?.mixedMode || false,
209
- nonce: viewParams?.page?.nonce
231
+ nonce: viewParams?.page?.nonce,
232
+ ssr: view.bootstrap?.ssr || false
210
233
  }, {
211
234
  appId: appIdentity.appName,
212
235
  bootstrapModule: versionedSpecifier,
@@ -27,11 +27,15 @@ __export(exports, {
27
27
  addExternalScriptNonce: () => addExternalScriptNonce,
28
28
  createJsonModule: () => createJsonModule,
29
29
  generateHtmlTag: () => generateHtmlTag,
30
+ generateLinkHeaders: () => generateLinkHeaders,
30
31
  generatePageContext: () => generatePageContext,
31
32
  generateViewNonce: () => generateViewNonce,
33
+ getModuleGraphCacheKey: () => getModuleGraphCacheKey,
32
34
  getModuleResource: () => getModuleResource,
33
35
  getModuleResourceByUri: () => getModuleResourceByUri,
36
+ getViewDefCacheKey: () => getViewDefCacheKey,
34
37
  getViewNonce: () => getViewNonce,
38
+ isViewDefinitionResponse: () => isViewDefinitionResponse,
35
39
  isViewResponse: () => isViewResponse,
36
40
  normalizeRenderOptions: () => normalizeRenderOptions,
37
41
  normalizeRenderedResult: () => normalizeRenderedResult,
@@ -108,7 +112,8 @@ function normalizeRenderedResult({
108
112
  renderedView,
109
113
  metadata,
110
114
  options,
111
- cache
115
+ cache,
116
+ redirect
112
117
  }) {
113
118
  return {
114
119
  renderedView,
@@ -121,7 +126,8 @@ function normalizeRenderedResult({
121
126
  options: {
122
127
  skipMetadataCollection: options ? options.skipMetadataCollection : false
123
128
  },
124
- cache: cache || {}
129
+ cache: cache || {},
130
+ redirect
125
131
  };
126
132
  }
127
133
  function reduceSourceAssetReferences(assets) {
@@ -149,11 +155,16 @@ function generatePageContext({requestPath: url}, {id, contentTemplate, propertie
149
155
  const title = properties?.title || getTitleFromFilePath(contentTemplate);
150
156
  const locale = runtimeParams.locale;
151
157
  const basePath = runtimeParams.basePath;
152
- return {basePath, id, locale, title, url};
158
+ const assetBasePath = runtimeParams.assetBasePath;
159
+ const uiBasePath = runtimeParams.uiBasePath;
160
+ return {assetBasePath, basePath, id, locale, title, url, uiBasePath};
153
161
  }
154
162
  function isViewResponse(response) {
155
163
  return response.body !== void 0;
156
164
  }
165
+ function isViewDefinitionResponse(response) {
166
+ return response.view !== void 0;
167
+ }
157
168
  async function toJsonFormat(viewRequest, viewDefinition, route, runtimeEnvironment, runtimeParams, moduleRegistry) {
158
169
  const {viewRecord} = viewDefinition;
159
170
  const {bootstrap, id: appName} = route;
@@ -291,3 +302,41 @@ function addExternalScriptNonce(def, nonce) {
291
302
  def.nonce = nonce;
292
303
  }
293
304
  }
305
+ function generateLinkHeaders(assets, patterns) {
306
+ const assetConfig = {};
307
+ for (let i = 0; i < patterns.length; i++) {
308
+ const pattern = patterns[i].match;
309
+ assets.forEach((asset) => {
310
+ const path = (asset.override?.uri || asset.url).split("?")[0];
311
+ if (typeof pattern === "string" && path.endsWith(pattern) || typeof pattern === "object" && pattern.some((match) => path.endsWith(match))) {
312
+ assetConfig[path] = patterns[i].attributes;
313
+ }
314
+ });
315
+ }
316
+ return Object.keys(assetConfig).reduce((linkHeader, path) => {
317
+ linkHeader = `${linkHeader ? linkHeader + ", " : ""}<${path}>`;
318
+ const properties = assetConfig[path];
319
+ for (const prop in properties) {
320
+ linkHeader += properties[prop] !== "" ? `; ${prop}=${properties[prop]}` : `; ${prop}`;
321
+ }
322
+ return linkHeader;
323
+ }, "");
324
+ }
325
+ function getViewDefCacheKey(view, runtimeEnvironment, freezeAssets, runtimeParams) {
326
+ const {id, bootstrap, rootComponent, contentTemplate, layoutTemplate} = view;
327
+ return (0, import_shared_utils.getCacheKeyFromJson)({
328
+ id,
329
+ bootstrap,
330
+ rootComponent,
331
+ contentTemplate,
332
+ layoutTemplate,
333
+ freezeAssets,
334
+ locale: runtimeParams?.locale,
335
+ basePath: runtimeParams?.basePath,
336
+ debug: runtimeEnvironment.debug,
337
+ nonceEnabled: (0, import_shared_utils.getFeatureFlags)().ENABLE_NONCE
338
+ });
339
+ }
340
+ function getModuleGraphCacheKey(specifier, viewLinkCacheKey) {
341
+ return specifier + viewLinkCacheKey;
342
+ }
@@ -46,9 +46,11 @@ var LwrViewHandler = class {
46
46
  }
47
47
  const {view, viewParams, renderOptions} = normalizeViewProperties(viewRequest, response, route, this.globalConfig, runtimeParams);
48
48
  const viewDefinition2 = await this.viewRegistry.getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions);
49
+ const link2 = !!route?.bootstrap?.preloadResources?.patterns?.length && (0, import_utils.generateLinkHeaders)(viewDefinition2.viewRecord.assetReferences || [], route?.bootstrap?.preloadResources?.patterns || []);
49
50
  return {
50
51
  ...response,
51
52
  body: viewDefinition2.renderedView,
53
+ ...!!link2 && {headers: {link: link2}},
52
54
  metadata: {
53
55
  viewDefinition: viewDefinition2
54
56
  },
@@ -56,12 +58,14 @@ var LwrViewHandler = class {
56
58
  };
57
59
  }
58
60
  const viewDefinition = await this.getDefaultRouteViewDefinition(viewRequest, route, runtimeEnvironment, runtimeParams);
61
+ const link = !!route?.bootstrap?.preloadResources?.patterns?.length && (0, import_utils.generateLinkHeaders)(viewDefinition.viewRecord.assetReferences || [], route.bootstrap?.preloadResources?.patterns || []);
59
62
  return {
60
63
  body: viewDefinition.renderedView,
61
64
  metadata: {
62
65
  viewDefinition
63
66
  },
64
- cache: viewDefinition.cache
67
+ cache: viewDefinition.cache,
68
+ ...!!link && {headers: {link}}
65
69
  };
66
70
  }
67
71
  async getViewJson(viewRequest, route, runtimeEnvironment, runtimeParams = {}) {
@@ -153,6 +157,22 @@ var LwrViewHandler = class {
153
157
  if (response?.locale) {
154
158
  runtimeParams.locale = response.locale;
155
159
  }
160
+ const preloadResources = route?.bootstrap?.preloadResources?.patterns;
161
+ if (preloadResources && preloadResources.length) {
162
+ let viewDefintionMeta = response.metadata?.viewDefinition;
163
+ if (!viewDefintionMeta && (0, import_utils.isViewDefinitionResponse)(response)) {
164
+ viewDefintionMeta = (await viewApi.getViewResponse(response.view, response.viewParams, response.renderOptions)).metadata?.viewDefinition;
165
+ }
166
+ if (viewDefintionMeta) {
167
+ const link = (0, import_utils.generateLinkHeaders)(viewDefintionMeta?.viewRecord.assetReferences || [], preloadResources);
168
+ if (link) {
169
+ response.headers = {
170
+ ...response.headers,
171
+ link
172
+ };
173
+ }
174
+ }
175
+ }
156
176
  return response;
157
177
  }
158
178
  getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams) {