@lwrjs/view-registry 0.12.0-alpha.2 → 0.12.0-alpha.20

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.
@@ -167,44 +167,53 @@ var LwrViewRegistry = class {
167
167
  return false;
168
168
  }
169
169
  async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
170
- const {skipCaching, freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
171
- const viewDefCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({
172
- ...view,
173
- freezeAssets,
174
- locale: runtimeParams?.locale,
175
- basePath: runtimeParams?.basePath,
176
- debug: runtimeEnvironment.debug
177
- });
178
- import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
179
- const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
180
- import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
181
- const cacheDisabled = process.env.NOCACHE === "true" || skipCaching;
182
- if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
183
- const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey);
184
- if (viewDefinition2 && viewDefinition2.paramKey === viewParamKey && viewDefinition2.viewDefinition.immutable) {
185
- return viewDefinition2.viewDefinition;
170
+ try {
171
+ const {skipCaching, freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
172
+ const viewDefCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({
173
+ ...view,
174
+ freezeAssets,
175
+ locale: runtimeParams?.locale,
176
+ basePath: runtimeParams?.basePath,
177
+ debug: runtimeEnvironment.debug
178
+ });
179
+ import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
180
+ const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
181
+ import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
182
+ const cacheDisabled = process.env.NOCACHE === "true" || skipCaching;
183
+ if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
184
+ const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey);
185
+ if (viewDefinition2 && viewDefinition2.paramKey === viewParamKey && viewDefinition2.viewDefinition.immutable) {
186
+ return viewDefinition2.viewDefinition;
187
+ }
186
188
  }
187
- }
188
- const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
189
- const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
190
- name: import_instrumentation.ViewSpan.RenderView,
191
- attributes: {
192
- view: view.id,
193
- ssr: view.bootstrap?.ssr === true
189
+ const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
190
+ const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
191
+ name: import_instrumentation.ViewSpan.RenderView,
192
+ attributes: {
193
+ view: view.id,
194
+ ssr: view.bootstrap?.ssr === true
195
+ }
196
+ }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
197
+ if (cacheDisabled === false) {
198
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
199
+ const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
200
+ if (ttl !== 0) {
201
+ this.viewDefinitions.set(viewDefCacheKey, {
202
+ view,
203
+ viewDefinition,
204
+ paramKey: viewParamKey
205
+ }, {ttl: ttl ? ttl * 1e3 : void 0});
206
+ }
194
207
  }
195
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
196
- if (cacheDisabled === false) {
197
- const route = this.globalConfig.routes.find((r) => r.id === view.id);
198
- const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
199
- if (ttl !== 0) {
200
- this.viewDefinitions.set(viewDefCacheKey, {
201
- view,
202
- viewDefinition,
203
- paramKey: viewParamKey
204
- }, {ttl: ttl ? ttl * 1e3 : void 0});
208
+ return viewDefinition;
209
+ } catch (err) {
210
+ if (err instanceof import_diagnostics.DiagnosticsError) {
211
+ throw err;
205
212
  }
213
+ import_diagnostics.logger.error(`Failed to get view definition "${view.id}": ${err}`);
214
+ const message = err instanceof Error ? err.message : String(err);
215
+ throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.SERVER.UNEXPECTED_ERROR(message)}, import_diagnostics.LwrServerError);
206
216
  }
207
- return viewDefinition;
208
217
  }
209
218
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
210
219
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
@@ -254,7 +263,8 @@ var LwrViewRegistry = class {
254
263
  ...renderedContent.metadata.serverDebug,
255
264
  ...renderedLayout.metadata.serverDebug
256
265
  }
257
- }
266
+ },
267
+ cache: renderedContent.cache
258
268
  }, {
259
269
  view: {...view, layoutTemplate: layoutTemplatePath},
260
270
  viewParams,
@@ -304,11 +314,12 @@ var LwrViewRegistry = class {
304
314
  const linkedMetadata = skipMetadataCollection ? renderedViewMetadata : await (0, import_shared_utils.extractMetadataFromHtml)(renderedViewContent, renderedViewMetadata, this.globalConfig);
305
315
  const mergedViewContext = {
306
316
  ...viewContext,
317
+ config: this.globalConfig,
307
318
  runtimeEnvironment,
308
319
  importer: importer || renderedView.compiledView.filePath
309
320
  };
310
321
  const stringBuilder = (0, import_shared_utils.createStringBuilder)(renderedViewContent);
311
- let pageTtl;
322
+ let pageTtl = renderedView.cache.ttl;
312
323
  for (const viewTransformer of this.viewTransformers) {
313
324
  const linkResults = await viewTransformer.link?.(stringBuilder, mergedViewContext, linkedMetadata);
314
325
  const ttl = linkResults && linkResults.cache?.ttl;
@@ -46,11 +46,21 @@ async function getHtmlResources(view, viewParams, resourceContext) {
46
46
  const version = lwrVersion;
47
47
  const isAMD = format === "amd";
48
48
  const {bundleConfig} = resourceContext;
49
- const {external = {}} = bundleConfig;
49
+ const {external = {}, exclude = []} = bundleConfig;
50
50
  const groups = isAMD ? bundleConfig.groups || {} : {};
51
- const isExternal = function(rawSpecifier) {
51
+ const getPreloadUri = function(rawSpecifier, uriMap) {
52
52
  const {specifier} = (0, import_shared_utils.explodeSpecifier)(rawSpecifier);
53
- return Object.keys(external).some((e) => specifier === e);
53
+ if (Object.keys(external).some((e) => specifier === e))
54
+ return;
55
+ const uri = uriMap[rawSpecifier];
56
+ if (!uri && (exclude.includes(specifier) || (0, import_shared_utils.isGroupie)(specifier, groups))) {
57
+ import_diagnostics.logger.warn({
58
+ label: "view-registry",
59
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`
60
+ });
61
+ return;
62
+ }
63
+ return uri;
54
64
  };
55
65
  const {
56
66
  id: appName,
@@ -127,8 +137,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
127
137
  }
128
138
  moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
129
139
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
130
- if (!isExternal(depSpecifier)) {
131
- const uri2 = bootstrapModuleGraph.uriMap[depSpecifier];
140
+ const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
141
+ if (uri2) {
132
142
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
133
143
  }
134
144
  }
@@ -169,8 +179,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
169
179
  (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, groups, viewPreloads);
170
180
  if (bundle) {
171
181
  for (const depSpecifier of graph.graphs[0].static) {
172
- if (!isExternal(depSpecifier)) {
173
- const uri2 = graph.uriMap[depSpecifier];
182
+ const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
183
+ if (uri2) {
174
184
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
175
185
  }
176
186
  }
@@ -31,7 +31,9 @@ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
31
31
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
32
32
  function setPreloadModulesMeta(specifier, uri, groups, preloads) {
33
33
  if (!uri) {
34
- throw Error(`Invalid Preload Module ${specifier}`);
34
+ throw (0, import_diagnostics.createSingleDiagnosticError)({
35
+ description: import_diagnostics.descriptions.UNRESOLVABLE.PRELOAD_MODULE(specifier)
36
+ }, import_diagnostics.LwrUnresolvableError);
35
37
  }
36
38
  const [removedVersion, version] = specifier.split("/v/");
37
39
  const normalizedSpecifier = version === import_shared_utils.VERSION_NOT_PROVIDED ? removedVersion : specifier;
@@ -45,8 +45,10 @@ function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironm
45
45
  },
46
46
  ...debug && {modifiers: {debug: "true"}}
47
47
  };
48
- const environment = {
49
- NODE_ENV: runtimeEnvironment.serverMode,
48
+ const nodeEnv = {
49
+ NODE_ENV: runtimeEnvironment.serverMode
50
+ };
51
+ const lwrEnv = {
50
52
  SSR: false,
51
53
  ...(0, import_shared_utils.buildEnvironmentContext)(runtimeParams)
52
54
  };
@@ -58,7 +60,8 @@ function getViewBootstrapConfigurationResource(viewInfo, config, runtimeEnvironm
58
60
  ...config,
59
61
  endpoints
60
62
  })});`,
61
- `globalThis.process = { env: ${JSON.stringify(environment)} };`,
63
+ `globalThis.LWR = {...globalThis.LWR, env: ${JSON.stringify(lwrEnv)}};`,
64
+ `globalThis.process={...globalThis.process,env:{...globalThis.process?.env,...${JSON.stringify(nodeEnv)}}};`,
62
65
  `globalThis.lwcRuntimeFlags = { ENABLE_MIXED_SHADOW_MODE: ${viewInfo.mixedMode} };`,
63
66
  debug && debugMessage && `console.warn(${JSON.stringify(debugMessage)});`
64
67
  ].filter(Boolean).join("\n");
@@ -48,11 +48,21 @@ async function getHtmlResources(view, viewParams, resourceContext) {
48
48
  const isAMD = format === "amd";
49
49
  const depth = isAMD ? {static: import_shared_utils.GraphDepth.ALL, dynamic: 1} : {static: import_shared_utils.GraphDepth.NONE, dynamic: 1};
50
50
  const {bundleConfig} = resourceContext;
51
- const {external = {}} = bundleConfig;
51
+ const {external = {}, exclude = []} = bundleConfig;
52
52
  const groups = isAMD ? bundleConfig.groups || {} : {};
53
- const isExternal = function(rawSpecifier) {
53
+ const getPreloadUri = function(rawSpecifier, uriMap) {
54
54
  const {specifier} = (0, import_shared_utils.explodeSpecifier)(rawSpecifier);
55
- return Object.keys(external).some((e) => specifier === e);
55
+ if (Object.keys(external).some((e) => specifier === e))
56
+ return;
57
+ const uri = uriMap[rawSpecifier];
58
+ if (!uri && (exclude.includes(specifier) || (0, import_shared_utils.isGroupie)(specifier, groups))) {
59
+ import_diagnostics.logger.warn({
60
+ label: "view-registry",
61
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`
62
+ });
63
+ return;
64
+ }
65
+ return uri;
56
66
  };
57
67
  const {
58
68
  id: appName,
@@ -118,8 +128,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
118
128
  }
119
129
  moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
120
130
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
121
- if (!isExternal(depSpecifier)) {
122
- const uri2 = bootstrapModuleGraph.uriMap[depSpecifier];
131
+ const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
132
+ if (uri2) {
123
133
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
124
134
  }
125
135
  }
@@ -161,8 +171,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
161
171
  (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, groups, viewPreloads);
162
172
  if (bundle) {
163
173
  for (const depSpecifier of graph.graphs[0].static) {
164
- if (!isExternal(depSpecifier)) {
165
- const uri2 = graph.uriMap[depSpecifier];
174
+ const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
175
+ if (uri2) {
166
176
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
167
177
  }
168
178
  }
@@ -87,7 +87,8 @@ async function generateHtmlTag(definition) {
87
87
  function normalizeRenderedResult({
88
88
  renderedView,
89
89
  metadata,
90
- options
90
+ options,
91
+ cache
91
92
  }) {
92
93
  return {
93
94
  renderedView,
@@ -99,7 +100,8 @@ function normalizeRenderedResult({
99
100
  },
100
101
  options: {
101
102
  skipMetadataCollection: options ? options.skipMetadataCollection : false
102
- }
103
+ },
104
+ cache: cache || {}
103
105
  };
104
106
  }
105
107
  function reduceSourceAssetReferences(assets) {
@@ -30,6 +30,7 @@ var import_path = __toModule(require("path"));
30
30
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
31
31
  var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
32
32
  var import_utils = __toModule(require("./utils.cjs"));
33
+ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
33
34
  var LwrViewHandler = class {
34
35
  constructor(context, globalConfig) {
35
36
  this.globalConfig = globalConfig;
@@ -128,6 +129,7 @@ var LwrViewHandler = class {
128
129
  const {rootDir, assets, contentDir, layoutsDir} = this.globalConfig;
129
130
  const paths = {rootDir, assets, contentDir, layoutsDir};
130
131
  const locale = runtimeParams.locale;
132
+ const basePath = runtimeParams.basePath;
131
133
  const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
132
134
  const response = await (0, import_instrumentation.getTracer)().trace({
133
135
  name: import_instrumentation.ViewSpan.ExecuteRouteHandler,
@@ -135,7 +137,17 @@ var LwrViewHandler = class {
135
137
  view: route.id,
136
138
  route: viewRequest.requestPath
137
139
  }
138
- }, async () => routeHandlerFn({...viewRequest, locale}, {route, viewApi, ...paths}, routeHandlerOptions));
140
+ }, async () => {
141
+ try {
142
+ return await routeHandlerFn({...viewRequest, locale, basePath}, {route, viewApi, ...paths}, routeHandlerOptions);
143
+ } catch (err) {
144
+ if (err instanceof import_diagnostics.DiagnosticsError) {
145
+ throw err;
146
+ }
147
+ const message = err instanceof Error ? err.message : String(err);
148
+ throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message)}, import_diagnostics.LwrApplicationError);
149
+ }
150
+ });
139
151
  return response;
140
152
  }
141
153
  getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams) {
package/build/es/index.js CHANGED
@@ -3,7 +3,7 @@ import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
3
3
  import { normalizeRenderOptions, normalizeRenderedResult, reduceSourceAssetReferences } from './utils.js';
4
4
  import { linkLwrResources } from './linkers/link-lwr-resources.js';
5
5
  import { LRUCache } from 'lru-cache';
6
- import { logger } from '@lwrjs/diagnostics';
6
+ import { DiagnosticsError, LwrServerError, createSingleDiagnosticError, descriptions, logger, } from '@lwrjs/diagnostics';
7
7
  export { LwrViewHandler } from './view-handler.js';
8
8
  export class LwrViewRegistry {
9
9
  constructor(context, globalConfig) {
@@ -159,55 +159,65 @@ export class LwrViewRegistry {
159
159
  return false;
160
160
  }
161
161
  async getViewDefinition(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions) {
162
- const { skipCaching, freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
163
- const viewDefCacheKey = getCacheKeyFromJson({
164
- ...view,
165
- freezeAssets,
166
- locale: runtimeParams?.locale,
167
- basePath: runtimeParams?.basePath,
168
- debug: runtimeEnvironment.debug,
169
- });
170
- logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
171
- // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
172
- // to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
173
- // on every request, while still reusing our caching logic.
174
- const viewParamKey = viewParamCacheKey
175
- ? getCacheKeyFromJson(viewParamCacheKey)
176
- : getCacheKeyFromJson(viewParams);
177
- logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
178
- const cacheDisabled = process.env.NOCACHE === 'true' || skipCaching;
179
- // important: cache key does not include the unbounded viewParams
180
- if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
181
- const viewDefinition = this.viewDefinitions.get(viewDefCacheKey);
182
- if (viewDefinition &&
183
- viewDefinition.paramKey === viewParamKey &&
184
- viewDefinition.viewDefinition.immutable) {
185
- return viewDefinition.viewDefinition;
162
+ try {
163
+ const { skipCaching, freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
164
+ const viewDefCacheKey = getCacheKeyFromJson({
165
+ ...view,
166
+ freezeAssets,
167
+ locale: runtimeParams?.locale,
168
+ basePath: runtimeParams?.basePath,
169
+ debug: runtimeEnvironment.debug,
170
+ });
171
+ logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
172
+ // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
173
+ // to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
174
+ // on every request, while still reusing our caching logic.
175
+ const viewParamKey = viewParamCacheKey
176
+ ? getCacheKeyFromJson(viewParamCacheKey)
177
+ : getCacheKeyFromJson(viewParams);
178
+ logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
179
+ const cacheDisabled = process.env.NOCACHE === 'true' || skipCaching;
180
+ // important: cache key does not include the unbounded viewParams
181
+ if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
182
+ const viewDefinition = this.viewDefinitions.get(viewDefCacheKey);
183
+ if (viewDefinition &&
184
+ viewDefinition.paramKey === viewParamKey &&
185
+ viewDefinition.viewDefinition.immutable) {
186
+ return viewDefinition.viewDefinition;
187
+ }
186
188
  }
189
+ const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
190
+ const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
191
+ name: ViewSpan.RenderView,
192
+ attributes: {
193
+ view: view.id,
194
+ ssr: view.bootstrap?.ssr === true,
195
+ },
196
+ }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
197
+ if (cacheDisabled === false) {
198
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
199
+ const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
200
+ if (ttl !== 0) {
201
+ // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
202
+ this.viewDefinitions.set(viewDefCacheKey, {
203
+ view,
204
+ viewDefinition,
205
+ paramKey: viewParamKey,
206
+ },
207
+ // s -> ms
208
+ { ttl: ttl ? ttl * 1000 : undefined });
209
+ }
210
+ }
211
+ return viewDefinition;
187
212
  }
188
- const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
189
- const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
190
- name: ViewSpan.RenderView,
191
- attributes: {
192
- view: view.id,
193
- ssr: view.bootstrap?.ssr === true,
194
- },
195
- }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
196
- if (cacheDisabled === false) {
197
- const route = this.globalConfig.routes.find((r) => r.id === view.id);
198
- const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
199
- if (ttl !== 0) {
200
- // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
201
- this.viewDefinitions.set(viewDefCacheKey, {
202
- view,
203
- viewDefinition,
204
- paramKey: viewParamKey,
205
- },
206
- // s -> ms
207
- { ttl: ttl ? ttl * 1000 : undefined });
213
+ catch (err) {
214
+ if (err instanceof DiagnosticsError) {
215
+ throw err;
208
216
  }
217
+ logger.error(`Failed to get view definition "${view.id}": ${err}`);
218
+ const message = err instanceof Error ? err.message : String(err);
219
+ throw createSingleDiagnosticError({ description: descriptions.SERVER.UNEXPECTED_ERROR(message) }, LwrServerError);
209
220
  }
210
- return viewDefinition;
211
221
  }
212
222
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
213
223
  const { id, contentTemplate, rootComponent, layoutTemplate } = view;
@@ -264,6 +274,7 @@ export class LwrViewRegistry {
264
274
  ...renderedLayout.metadata.serverDebug,
265
275
  },
266
276
  },
277
+ cache: renderedContent.cache,
267
278
  },
268
279
  // Render Content now contains a layout
269
280
  {
@@ -318,11 +329,12 @@ export class LwrViewRegistry {
318
329
  : await extractMetadataFromHtml(renderedViewContent, renderedViewMetadata, this.globalConfig);
319
330
  const mergedViewContext = {
320
331
  ...viewContext,
332
+ config: this.globalConfig,
321
333
  runtimeEnvironment,
322
334
  importer: importer || renderedView.compiledView.filePath,
323
335
  };
324
336
  const stringBuilder = createStringBuilder(renderedViewContent);
325
- let pageTtl;
337
+ let pageTtl = renderedView.cache.ttl;
326
338
  for (const viewTransformer of this.viewTransformers) {
327
339
  // eslint-disable-next-line no-await-in-loop
328
340
  const linkResults = await viewTransformer.link?.(stringBuilder, mergedViewContext, linkedMetadata);
@@ -1,5 +1,5 @@
1
1
  import { logger } from '@lwrjs/diagnostics';
2
- import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, } from '@lwrjs/shared-utils';
2
+ import { kebabCaseToModuleSpecifier, getModuleGraphs, GraphDepth, getModuleUriPrefix, explodeSpecifier, isBundler, getHydrateDirective, isGroupie, } from '@lwrjs/shared-utils';
3
3
  import { AppResourceEnum, getAppSpecifier } from '@lwrjs/app-service/identity';
4
4
  import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
5
5
  import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
@@ -11,12 +11,26 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
11
11
  const version = lwrVersion;
12
12
  const isAMD = format === 'amd';
13
13
  const { bundleConfig } = resourceContext;
14
- const { external = {} } = bundleConfig;
14
+ const { external = {}, exclude = [] } = bundleConfig;
15
15
  // Bundling groups is only supported in AMD for now
16
16
  const groups = isAMD ? bundleConfig.groups || {} : {};
17
- const isExternal = function (rawSpecifier) {
17
+ const getPreloadUri = function (rawSpecifier, uriMap) {
18
18
  const { specifier } = explodeSpecifier(rawSpecifier);
19
- return Object.keys(external).some((e) => specifier === e);
19
+ // do not preload externals; this is the app's responsibility
20
+ if (Object.keys(external).some((e) => specifier === e))
21
+ return;
22
+ const uri = uriMap[rawSpecifier];
23
+ // if there is no uri for an exclude or groupie, they've been handled via another specifier
24
+ // eg: if a bundle group has already been added to the URI map, its groups will not also be added
25
+ if (!uri && (exclude.includes(specifier) || isGroupie(specifier, groups))) {
26
+ // warn instead of throwing from setPreloadModulesMeta()
27
+ logger.warn({
28
+ label: 'view-registry',
29
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`,
30
+ });
31
+ return;
32
+ }
33
+ return uri;
20
34
  };
21
35
  const { id: appName, bootstrap: { services, module: bootstrapModule, preloadModules = [] } = {
22
36
  services: [],
@@ -130,8 +144,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
130
144
  moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
131
145
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
132
146
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
133
- if (!isExternal(depSpecifier)) {
134
- const uri = bootstrapModuleGraph.uriMap[depSpecifier];
147
+ const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
148
+ if (uri) {
135
149
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
136
150
  }
137
151
  }
@@ -186,8 +200,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
186
200
  // PRELOAD custom element static deps as link resources when bundling is ON
187
201
  if (bundle) {
188
202
  for (const depSpecifier of graph.graphs[0].static) {
189
- if (!isExternal(depSpecifier)) {
190
- const uri = graph.uriMap[depSpecifier];
203
+ const uri = getPreloadUri(depSpecifier, graph.uriMap);
204
+ if (uri) {
191
205
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
192
206
  }
193
207
  }
@@ -1,4 +1,4 @@
1
- import { logger } from '@lwrjs/diagnostics';
1
+ import { LwrUnresolvableError, createSingleDiagnosticError, descriptions, logger } from '@lwrjs/diagnostics';
2
2
  import { explodeSpecifier, getGroupName, getVersionedModuleId, normalizeVersionToUri, VERSION_NOT_PROVIDED, getSpecifier, isGroupie, } from '@lwrjs/shared-utils';
3
3
  /**
4
4
  * keeps track of preloadModules metadata
@@ -6,7 +6,9 @@ import { explodeSpecifier, getGroupName, getVersionedModuleId, normalizeVersionT
6
6
  export function setPreloadModulesMeta(specifier, uri, 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
- throw Error(`Invalid Preload Module ${specifier}`);
9
+ throw createSingleDiagnosticError({
10
+ description: descriptions.UNRESOLVABLE.PRELOAD_MODULE(specifier),
11
+ }, LwrUnresolvableError);
10
12
  }
11
13
  // We need to support version-less preloadModules, including version-less rootComponents.
12
14
  // Removing the "/v/version_not_provided" hack from the preloadModules specifier
@@ -17,9 +17,11 @@ export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeE
17
17
  },
18
18
  ...(debug && { modifiers: { debug: 'true' } }),
19
19
  };
20
- const environment = {
20
+ const nodeEnv = {
21
21
  // TODO: W-12639529 change NODE_ENV after addressing downstream customers
22
22
  NODE_ENV: runtimeEnvironment.serverMode,
23
+ };
24
+ const lwrEnv = {
23
25
  // Note: SSR is always false because this script is executed on the client
24
26
  SSR: false,
25
27
  // Used by `lwr/environment`
@@ -33,7 +35,8 @@ export function getViewBootstrapConfigurationResource(viewInfo, config, runtimeE
33
35
  ...config,
34
36
  endpoints,
35
37
  })});`,
36
- `globalThis.process = { env: ${JSON.stringify(environment)} };`,
38
+ `globalThis.LWR = {...globalThis.LWR, env: ${JSON.stringify(lwrEnv)}};`,
39
+ `globalThis.process={...globalThis.process,env:{...globalThis.process?.env,...${JSON.stringify(nodeEnv)}}};`,
37
40
  `globalThis.lwcRuntimeFlags = { ENABLE_MIXED_SHADOW_MODE: ${viewInfo.mixedMode} };`,
38
41
  debug && debugMessage && `console.warn(${JSON.stringify(debugMessage)});`,
39
42
  ]
@@ -1,5 +1,5 @@
1
1
  import { logger } from '@lwrjs/diagnostics';
2
- import { kebabCaseToModuleSpecifier, toImportMetadata, getModuleGraphs, getMappingUriPrefix, GraphDepth, explodeSpecifier, isBundler, getHydrateDirective, } from '@lwrjs/shared-utils';
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
4
  import { generateHtmlTag, getModuleResourceByUri } from '../utils.js';
5
5
  import { flattenCustomElements, getViewBootstrapConfigurationResource, getViewHmrConfigurationResource, } from './utils.js';
@@ -15,12 +15,23 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
15
15
  ? { static: GraphDepth.ALL, dynamic: 1 }
16
16
  : { static: GraphDepth.NONE, dynamic: 1 };
17
17
  const { bundleConfig } = resourceContext;
18
- const { external = {} } = bundleConfig;
18
+ const { external = {}, exclude = [] } = bundleConfig;
19
19
  // Bundling groups is only supported in AMD for now
20
20
  const groups = isAMD ? bundleConfig.groups || {} : {};
21
- const isExternal = function (rawSpecifier) {
21
+ const getPreloadUri = function (rawSpecifier, uriMap) {
22
22
  const { specifier } = explodeSpecifier(rawSpecifier);
23
- return Object.keys(external).some((e) => specifier === e);
23
+ if (Object.keys(external).some((e) => specifier === e))
24
+ return;
25
+ const uri = uriMap[rawSpecifier];
26
+ if (!uri && (exclude.includes(specifier) || isGroupie(specifier, groups))) {
27
+ // warn instead of throwing from setPreloadModulesMeta()
28
+ logger.warn({
29
+ label: 'view-registry',
30
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`,
31
+ });
32
+ return;
33
+ }
34
+ return uri;
24
35
  };
25
36
  const { id: appName, bootstrap: { services, module: bootstrapModule, preloadModules = [] } = {
26
37
  services: [],
@@ -114,8 +125,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
114
125
  moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
115
126
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
116
127
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
117
- if (!isExternal(depSpecifier)) {
118
- const uri = bootstrapModuleGraph.uriMap[depSpecifier];
128
+ const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
129
+ if (uri) {
119
130
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
120
131
  }
121
132
  }
@@ -172,8 +183,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
172
183
  // PRELOAD custom element static deps as link resources when bundling is ON
173
184
  if (bundle) {
174
185
  for (const depSpecifier of graph.graphs[0].static) {
175
- if (!isExternal(depSpecifier)) {
176
- const uri = graph.uriMap[depSpecifier];
186
+ const uri = getPreloadUri(depSpecifier, graph.uriMap);
187
+ if (uri) {
177
188
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
178
189
  }
179
190
  }
@@ -1,7 +1,7 @@
1
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';
2
2
  export type HTMLResource = Partial<ResourceDefinition>;
3
3
  export declare function generateHtmlTag(definition: HTMLResource): Promise<string>;
4
- export declare function normalizeRenderedResult({ renderedView, metadata, options, }: RenderingResult): NormalizedRenderingResult;
4
+ export declare function normalizeRenderedResult({ renderedView, metadata, options, cache, }: RenderingResult): NormalizedRenderingResult;
5
5
  export declare function reduceSourceAssetReferences(assets: AssetReference[]): RenderedAssetReference[];
6
6
  export declare function normalizeRenderOptions(runtimeEnvironment: RuntimeEnvironment, overrideRenderOptions?: RenderOptions, baseRenderOptions?: RenderOptions): Required<RenderOptions>;
7
7
  export declare function generatePageContext({ requestPath: url }: ViewRequest, { id, contentTemplate, properties }: LwrRoute | LwrErrorRoute, runtimeParams: RuntimeParams): JsonCompatible<ViewPageContext>;
package/build/es/utils.js CHANGED
@@ -52,7 +52,7 @@ export async function generateHtmlTag(definition) {
52
52
  }
53
53
  throw new Error(`Invalid external Resource Definition: missing a "src": "${definition.specifier}"`);
54
54
  }
55
- export function normalizeRenderedResult({ renderedView, metadata, options, }) {
55
+ export function normalizeRenderedResult({ renderedView, metadata, options, cache, }) {
56
56
  return {
57
57
  renderedView,
58
58
  metadata: {
@@ -64,6 +64,7 @@ export function normalizeRenderedResult({ renderedView, metadata, options, }) {
64
64
  options: {
65
65
  skipMetadataCollection: options ? options.skipMetadataCollection : false,
66
66
  },
67
+ cache: cache || {},
67
68
  };
68
69
  }
69
70
  export function reduceSourceAssetReferences(assets) {
@@ -2,6 +2,7 @@ import { resolve } from 'path';
2
2
  import { normalizeResourcePath, shortestTtl } from '@lwrjs/shared-utils';
3
3
  import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
4
4
  import { generateHtmlTag, generatePageContext, isViewResponse, toJsonFormat } from './utils.js';
5
+ import { DiagnosticsError, LwrApplicationError, createSingleDiagnosticError, descriptions, } from '@lwrjs/diagnostics';
5
6
  export class LwrViewHandler {
6
7
  constructor(context, globalConfig) {
7
8
  this.globalConfig = globalConfig;
@@ -144,15 +145,26 @@ export class LwrViewHandler {
144
145
  const { rootDir, assets, contentDir, layoutsDir } = this.globalConfig;
145
146
  const paths = { rootDir, assets, contentDir, layoutsDir };
146
147
  const locale = runtimeParams.locale;
148
+ const basePath = runtimeParams.basePath;
147
149
  const viewApi = this.getBoundApi(viewRequest, route, runtimeEnvironment, runtimeParams);
148
- // TODO: add trace attributes
149
150
  const response = await getTracer().trace({
150
151
  name: ViewSpan.ExecuteRouteHandler,
151
152
  attributes: {
152
153
  view: route.id,
153
154
  route: viewRequest.requestPath,
154
155
  },
155
- }, async () => routeHandlerFn({ ...viewRequest, locale }, { route: route, viewApi, ...paths }, routeHandlerOptions));
156
+ }, async () => {
157
+ try {
158
+ return await routeHandlerFn({ ...viewRequest, locale, basePath }, { route: route, viewApi, ...paths }, routeHandlerOptions);
159
+ }
160
+ catch (err) {
161
+ if (err instanceof DiagnosticsError) {
162
+ throw err;
163
+ }
164
+ const message = err instanceof Error ? err.message : String(err);
165
+ throw createSingleDiagnosticError({ description: descriptions.APPLICATION.ROUTE_HANDLER_ERROR(route.id, message) }, LwrApplicationError);
166
+ }
167
+ });
156
168
  return response;
157
169
  }
158
170
  /*
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.12.0-alpha.2",
7
+ "version": "0.12.0-alpha.20",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -30,17 +30,17 @@
30
30
  "build/**/*.d.ts"
31
31
  ],
32
32
  "dependencies": {
33
- "@lwrjs/app-service": "0.12.0-alpha.2",
34
- "@lwrjs/diagnostics": "0.12.0-alpha.2",
35
- "@lwrjs/instrumentation": "0.12.0-alpha.2",
36
- "@lwrjs/shared-utils": "0.12.0-alpha.2",
37
- "lru-cache": "^10.0.0"
33
+ "@lwrjs/app-service": "0.12.0-alpha.20",
34
+ "@lwrjs/diagnostics": "0.12.0-alpha.20",
35
+ "@lwrjs/instrumentation": "0.12.0-alpha.20",
36
+ "@lwrjs/shared-utils": "0.12.0-alpha.20",
37
+ "lru-cache": "^10.2.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@lwrjs/types": "0.12.0-alpha.2"
40
+ "@lwrjs/types": "0.12.0-alpha.20"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18.0.0"
44
44
  },
45
- "gitHead": "586a2aa659882483af9249dc3db7fe07bc842a25"
45
+ "gitHead": "ae1793e34eaf4e9b97996d7aea9031908b23a13a"
46
46
  }