@lwrjs/view-registry 0.12.0-alpha.9 → 0.12.0

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.
@@ -57,6 +57,10 @@ var LwrViewRegistry = class {
57
57
  observer.onAssetSourceChange(({payload}) => this.onAssetSourceChange(payload));
58
58
  }
59
59
  async onModuleDefinitionChange(moduleDefinition) {
60
+ if (process.env.MRT_HMR === "true") {
61
+ this.viewDefinitions.clear();
62
+ return;
63
+ }
60
64
  const versionedSpecifier = (0, import_shared_utils.getSpecifier)(moduleDefinition);
61
65
  for (const [id, viewDefEntry] of this.viewDefinitions.entries()) {
62
66
  const {
@@ -76,6 +80,10 @@ var LwrViewRegistry = class {
76
80
  }
77
81
  }
78
82
  async onViewSourceChange(compiledView) {
83
+ if (process.env.MRT_HMR === "true") {
84
+ this.viewDefinitions.clear();
85
+ return;
86
+ }
79
87
  const {contentTemplate, rootComponent} = compiledView.viewId;
80
88
  const compiledViewCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({contentTemplate, rootComponent});
81
89
  this.compiledViews.set(compiledViewCacheKey, compiledView);
@@ -167,44 +175,54 @@ var LwrViewRegistry = class {
167
175
  return false;
168
176
  }
169
177
  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;
178
+ try {
179
+ const {skipCaching, freezeAssets, viewParamCacheKey} = (0, import_utils.normalizeRenderOptions)(this.runtimeEnvironment, renderOptions);
180
+ const viewDefCacheKey = (0, import_shared_utils.getCacheKeyFromJson)({
181
+ ...view,
182
+ freezeAssets,
183
+ locale: runtimeParams?.locale,
184
+ basePath: runtimeParams?.basePath,
185
+ debug: runtimeEnvironment.debug
186
+ });
187
+ import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
188
+ const viewParamKey = viewParamCacheKey ? (0, import_shared_utils.getCacheKeyFromJson)(viewParamCacheKey) : (0, import_shared_utils.getCacheKeyFromJson)(viewParams);
189
+ import_diagnostics.logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
190
+ const cacheDisabled = process.env.NOCACHE === "true" || skipCaching;
191
+ if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
192
+ const viewDefinition2 = this.viewDefinitions.get(viewDefCacheKey);
193
+ if (viewDefinition2 && viewDefinition2.paramKey === viewParamKey && viewDefinition2.viewDefinition.immutable) {
194
+ return viewDefinition2.viewDefinition;
195
+ }
186
196
  }
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
197
+ const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
198
+ const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => (0, import_instrumentation.getTracer)().trace({
199
+ name: import_instrumentation.ViewSpan.RenderView,
200
+ attributes: {
201
+ view: view.id,
202
+ ssr: view.bootstrap?.ssr === true
203
+ }
204
+ }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
205
+ if (cacheDisabled === false) {
206
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
207
+ const ttl = (0, import_shared_utils.shortestTtl)(viewDefinition.cache?.ttl, route?.cache?.ttl);
208
+ if (ttl !== 0) {
209
+ this.viewDefinitions.set(viewDefCacheKey, {
210
+ view,
211
+ viewDefinition,
212
+ paramKey: viewParamKey
213
+ }, {ttl: ttl ? ttl * 1e3 : void 0});
214
+ }
194
215
  }
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});
216
+ return viewDefinition;
217
+ } catch (err) {
218
+ if (err instanceof import_diagnostics.DiagnosticsError) {
219
+ throw err;
205
220
  }
221
+ import_diagnostics.logger.error(`Failed to get view definition "${view.id}"`);
222
+ import_diagnostics.logger.error(err);
223
+ const message = err instanceof Error ? err.message : String(err);
224
+ throw (0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.SERVER.UNEXPECTED_ERROR(message)}, import_diagnostics.LwrServerError);
206
225
  }
207
- return viewDefinition;
208
226
  }
209
227
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
210
228
  const {id, contentTemplate, rootComponent, layoutTemplate} = view;
@@ -305,6 +323,7 @@ var LwrViewRegistry = class {
305
323
  const linkedMetadata = skipMetadataCollection ? renderedViewMetadata : await (0, import_shared_utils.extractMetadataFromHtml)(renderedViewContent, renderedViewMetadata, this.globalConfig);
306
324
  const mergedViewContext = {
307
325
  ...viewContext,
326
+ config: this.globalConfig,
308
327
  runtimeEnvironment,
309
328
  importer: importer || renderedView.compiledView.filePath
310
329
  };
@@ -32,6 +32,14 @@ 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
+ function includeIdFactory(bundleConfig) {
36
+ return (moduleRef) => {
37
+ if ((0, import_shared_utils.isExternalSpecifier)(moduleRef.specifier, bundleConfig)) {
38
+ return false;
39
+ }
40
+ return true;
41
+ };
42
+ }
35
43
  async function getHtmlResources(view, viewParams, resourceContext) {
36
44
  const {
37
45
  runtimeEnvironment,
@@ -46,11 +54,21 @@ async function getHtmlResources(view, viewParams, resourceContext) {
46
54
  const version = lwrVersion;
47
55
  const isAMD = format === "amd";
48
56
  const {bundleConfig} = resourceContext;
49
- const {external = {}} = bundleConfig;
57
+ const {external = {}, exclude = []} = bundleConfig;
50
58
  const groups = isAMD ? bundleConfig.groups || {} : {};
51
- const isExternal = function(rawSpecifier) {
59
+ const getPreloadUri = function(rawSpecifier, uriMap) {
52
60
  const {specifier} = (0, import_shared_utils.explodeSpecifier)(rawSpecifier);
53
- return Object.keys(external).some((e) => specifier === e);
61
+ if (Object.keys(external).some((e) => specifier === e))
62
+ return;
63
+ const uri = uriMap[rawSpecifier];
64
+ if (!uri && (exclude.includes(specifier) || (0, import_shared_utils.isGroupie)(specifier, groups))) {
65
+ import_diagnostics.logger.warn({
66
+ label: "view-registry",
67
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`
68
+ });
69
+ return;
70
+ }
71
+ return uri;
54
72
  };
55
73
  const {
56
74
  id: appName,
@@ -61,6 +79,9 @@ async function getHtmlResources(view, viewParams, resourceContext) {
61
79
  } = view;
62
80
  const defRegistry = bundle ? moduleBundler : moduleRegistry;
63
81
  const depth = isAMD ? {static: import_shared_utils.GraphDepth.ALL, dynamic: 1} : {static: import_shared_utils.GraphDepth.NONE, dynamic: 0};
82
+ if (isAMD) {
83
+ depth.includeId = includeIdFactory(bundleConfig);
84
+ }
64
85
  const appIdentity = {
65
86
  appName,
66
87
  format: runtimeEnvironment.format,
@@ -127,8 +148,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
127
148
  }
128
149
  moduleResources.push((0, import_utils.getModuleResourceByUri)(uri, runtimeEnvironment, {isPreload: false, isSSR}));
129
150
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
130
- if (!isExternal(depSpecifier)) {
131
- const uri2 = bootstrapModuleGraph.uriMap[depSpecifier];
151
+ const uri2 = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
152
+ if (uri2) {
132
153
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
133
154
  }
134
155
  }
@@ -169,8 +190,8 @@ async function getHtmlResources(view, viewParams, resourceContext) {
169
190
  (0, import_preload_utils.setPreloadModulesMeta)(specifier, uri, groups, viewPreloads);
170
191
  if (bundle) {
171
192
  for (const depSpecifier of graph.graphs[0].static) {
172
- if (!isExternal(depSpecifier)) {
173
- const uri2 = graph.uriMap[depSpecifier];
193
+ const uri2 = getPreloadUri(depSpecifier, graph.uriMap);
194
+ if (uri2) {
174
195
  (0, import_preload_utils.setPreloadModulesMeta)(depSpecifier, uri2, groups, viewPreloads);
175
196
  }
176
197
  }
@@ -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,9 +60,10 @@ 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
- debug && debugMessage && `console.warn(${JSON.stringify(debugMessage)});`
66
+ debug && debugMessage && `console.error(${JSON.stringify(debugMessage)});`
64
67
  ].filter(Boolean).join("\n");
65
68
  if (viewInfo.configAsSrc) {
66
69
  const viewUrl = viewInfo.url || "/";
@@ -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
  }
@@ -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) {
@@ -36,6 +36,11 @@ export class LwrViewRegistry {
36
36
  observer.onAssetSourceChange(({ payload }) => this.onAssetSourceChange(payload));
37
37
  }
38
38
  async onModuleDefinitionChange(moduleDefinition) {
39
+ // TODO we will make this more robust in the future w/ full MRT HMR
40
+ if (process.env.MRT_HMR === 'true') {
41
+ this.viewDefinitions.clear();
42
+ return;
43
+ }
39
44
  const versionedSpecifier = getSpecifier(moduleDefinition);
40
45
  // invalidate viewDefinition cache entries with references to the LinkedModuleDefinition
41
46
  for (const [id, viewDefEntry] of this.viewDefinitions.entries()) {
@@ -57,6 +62,11 @@ export class LwrViewRegistry {
57
62
  }
58
63
  }
59
64
  async onViewSourceChange(compiledView) {
65
+ // TODO we will make this more robust in the future w/ full MRT HMR
66
+ if (process.env.MRT_HMR === 'true') {
67
+ this.viewDefinitions.clear();
68
+ return;
69
+ }
60
70
  // invalidate compiledViews and viewDefinition cache entries with references to the CompiledView template id.
61
71
  const { contentTemplate, rootComponent } = compiledView.viewId;
62
72
  const compiledViewCacheKey = getCacheKeyFromJson({ contentTemplate, rootComponent });
@@ -159,55 +169,66 @@ export class LwrViewRegistry {
159
169
  return false;
160
170
  }
161
171
  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;
172
+ try {
173
+ const { skipCaching, freezeAssets, viewParamCacheKey } = normalizeRenderOptions(this.runtimeEnvironment, renderOptions);
174
+ const viewDefCacheKey = getCacheKeyFromJson({
175
+ ...view,
176
+ freezeAssets,
177
+ locale: runtimeParams?.locale,
178
+ basePath: runtimeParams?.basePath,
179
+ debug: runtimeEnvironment.debug,
180
+ });
181
+ logger.debug(`[view-registry][getViewDefinition] viewDefCacheKey=${viewDefCacheKey}`);
182
+ // viewParams is an unbounded object and can be very large (17MB/view for developer.salesforce.com). Allowing consumers
183
+ // to provide a simple override avoids the excess memory / performance overhead of serializing & storing the viewParams
184
+ // on every request, while still reusing our caching logic.
185
+ const viewParamKey = viewParamCacheKey
186
+ ? getCacheKeyFromJson(viewParamCacheKey)
187
+ : getCacheKeyFromJson(viewParams);
188
+ logger.debug(`[view-registry][getViewDefinition] viewParamKey=${viewParamKey}`);
189
+ const cacheDisabled = process.env.NOCACHE === 'true' || skipCaching;
190
+ // important: cache key does not include the unbounded viewParams
191
+ if (cacheDisabled === false && this.viewDefinitions.has(viewDefCacheKey)) {
192
+ const viewDefinition = this.viewDefinitions.get(viewDefCacheKey);
193
+ if (viewDefinition &&
194
+ viewDefinition.paramKey === viewParamKey &&
195
+ viewDefinition.viewDefinition.immutable) {
196
+ return viewDefinition.viewDefinition;
197
+ }
198
+ }
199
+ const pendingViewDefCacheKey = viewDefCacheKey + viewParamKey;
200
+ const viewDefinition = await this.pendingViewDefinitions.execute(pendingViewDefCacheKey, () => getTracer().trace({
201
+ name: ViewSpan.RenderView,
202
+ attributes: {
203
+ view: view.id,
204
+ ssr: view.bootstrap?.ssr === true,
205
+ },
206
+ }, () => this.renderView(view, viewParams, runtimeEnvironment, runtimeParams, renderOptions)));
207
+ if (cacheDisabled === false) {
208
+ const route = this.globalConfig.routes.find((r) => r.id === view.id);
209
+ const ttl = shortestTtl(viewDefinition.cache?.ttl, route?.cache?.ttl);
210
+ if (ttl !== 0) {
211
+ // cache view definition for the shortest ttl or until it is the least recently used when ttl is undefined
212
+ this.viewDefinitions.set(viewDefCacheKey, {
213
+ view,
214
+ viewDefinition,
215
+ paramKey: viewParamKey,
216
+ },
217
+ // s -> ms
218
+ { ttl: ttl ? ttl * 1000 : undefined });
219
+ }
186
220
  }
221
+ return viewDefinition;
187
222
  }
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 });
223
+ catch (err) {
224
+ if (err instanceof DiagnosticsError) {
225
+ throw err;
208
226
  }
227
+ logger.error(`Failed to get view definition "${view.id}"`);
228
+ logger.error(err);
229
+ const message = err instanceof Error ? err.message : String(err);
230
+ throw createSingleDiagnosticError({ description: descriptions.SERVER.UNEXPECTED_ERROR(message) }, LwrServerError);
209
231
  }
210
- return viewDefinition;
211
232
  }
212
233
  async renderView(view, viewParams, runtimeEnvironment, runtimeParams = {}, renderOptions) {
213
234
  const { id, contentTemplate, rootComponent, layoutTemplate } = view;
@@ -319,6 +340,7 @@ export class LwrViewRegistry {
319
340
  : await extractMetadataFromHtml(renderedViewContent, renderedViewMetadata, this.globalConfig);
320
341
  const mergedViewContext = {
321
342
  ...viewContext,
343
+ config: this.globalConfig,
322
344
  runtimeEnvironment,
323
345
  importer: importer || renderedView.compiledView.filePath,
324
346
  };
@@ -1,9 +1,20 @@
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, isExternalSpecifier, } 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';
6
6
  import { setPreloadModulesMeta, getPreloadModulesMeta } from './preload-utils.js';
7
+ function includeIdFactory(bundleConfig) {
8
+ return (moduleRef) => {
9
+ // Do not bundle externals, including the loader module, which is auto bundled
10
+ // with the shim + loader combo
11
+ if (isExternalSpecifier(moduleRef.specifier, bundleConfig)) {
12
+ // Do not include externals in the required imports but also return false to indicate it should not be in the bundle
13
+ return false;
14
+ }
15
+ return true;
16
+ };
17
+ }
7
18
  export async function getHtmlResources(view, viewParams, resourceContext) {
8
19
  const { runtimeEnvironment, runtimeParams, moduleRegistry, moduleBundler, resourceRegistry, viewMetadata, } = resourceContext;
9
20
  const { lwrVersion, format, hmrEnabled, bundle, debug, minify } = runtimeEnvironment;
@@ -11,12 +22,26 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
11
22
  const version = lwrVersion;
12
23
  const isAMD = format === 'amd';
13
24
  const { bundleConfig } = resourceContext;
14
- const { external = {} } = bundleConfig;
25
+ const { external = {}, exclude = [] } = bundleConfig;
15
26
  // Bundling groups is only supported in AMD for now
16
27
  const groups = isAMD ? bundleConfig.groups || {} : {};
17
- const isExternal = function (rawSpecifier) {
28
+ const getPreloadUri = function (rawSpecifier, uriMap) {
18
29
  const { specifier } = explodeSpecifier(rawSpecifier);
19
- return Object.keys(external).some((e) => specifier === e);
30
+ // do not preload externals; this is the app's responsibility
31
+ if (Object.keys(external).some((e) => specifier === e))
32
+ return;
33
+ const uri = uriMap[rawSpecifier];
34
+ // if there is no uri for an exclude or groupie, they've been handled via another specifier
35
+ // eg: if a bundle group has already been added to the URI map, its groups will not also be added
36
+ if (!uri && (exclude.includes(specifier) || isGroupie(specifier, groups))) {
37
+ // warn instead of throwing from setPreloadModulesMeta()
38
+ logger.warn({
39
+ label: 'view-registry',
40
+ message: `Skipping preload of unknown static import: ${rawSpecifier}`,
41
+ });
42
+ return;
43
+ }
44
+ return uri;
20
45
  };
21
46
  const { id: appName, bootstrap: { services, module: bootstrapModule, preloadModules = [] } = {
22
47
  services: [],
@@ -26,6 +51,9 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
26
51
  const depth = isAMD
27
52
  ? { static: GraphDepth.ALL, dynamic: 1 }
28
53
  : { static: GraphDepth.NONE, dynamic: 0 };
54
+ if (isAMD) {
55
+ depth.includeId = includeIdFactory(bundleConfig);
56
+ }
29
57
  // The Application Bootstrap (ABS) module resource is EITHER
30
58
  // - configured as routes[x].bootstrap.module OR
31
59
  // - defaulted as "@lwrjs/app-service/{appName}/module/{format}"
@@ -130,8 +158,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
130
158
  moduleResources.push(getModuleResourceByUri(uri, runtimeEnvironment, { isPreload: false, isSSR }));
131
159
  // PRELOAD the bootstrap module static dependencies as preloaded script resources
132
160
  for (const depSpecifier of bootstrapModuleGraph.graphs[0].static) {
133
- if (!isExternal(depSpecifier)) {
134
- const uri = bootstrapModuleGraph.uriMap[depSpecifier];
161
+ const uri = getPreloadUri(depSpecifier, bootstrapModuleGraph.uriMap);
162
+ if (uri) {
135
163
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
136
164
  }
137
165
  }
@@ -186,8 +214,8 @@ export async function getHtmlResources(view, viewParams, resourceContext) {
186
214
  // PRELOAD custom element static deps as link resources when bundling is ON
187
215
  if (bundle) {
188
216
  for (const depSpecifier of graph.graphs[0].static) {
189
- if (!isExternal(depSpecifier)) {
190
- const uri = graph.uriMap[depSpecifier];
217
+ const uri = getPreloadUri(depSpecifier, graph.uriMap);
218
+ if (uri) {
191
219
  setPreloadModulesMeta(depSpecifier, uri, groups, viewPreloads);
192
220
  }
193
221
  }
@@ -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,9 +35,10 @@ 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
- debug && debugMessage && `console.warn(${JSON.stringify(debugMessage)});`,
41
+ debug && debugMessage && `console.error(${JSON.stringify(debugMessage)});`,
39
42
  ]
40
43
  .filter(Boolean)
41
44
  .join('\n');
@@ -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
  }
@@ -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.9",
7
+ "version": "0.12.0",
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.9",
34
- "@lwrjs/diagnostics": "0.12.0-alpha.9",
35
- "@lwrjs/instrumentation": "0.12.0-alpha.9",
36
- "@lwrjs/shared-utils": "0.12.0-alpha.9",
33
+ "@lwrjs/app-service": "0.12.0",
34
+ "@lwrjs/diagnostics": "0.12.0",
35
+ "@lwrjs/instrumentation": "0.12.0",
36
+ "@lwrjs/shared-utils": "0.12.0",
37
37
  "lru-cache": "^10.2.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@lwrjs/types": "0.12.0-alpha.9"
40
+ "@lwrjs/types": "0.12.0"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18.0.0"
44
44
  },
45
- "gitHead": "58b28fbc6300b704ac17f8878423120de0e376d7"
45
+ "gitHead": "90f93604b26003e1e1eb85bb0d1f34f4fc9e9ff9"
46
46
  }