@lwrjs/lwc-ssr 0.17.2-alpha.2 → 0.17.2-alpha.4

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.
@@ -21,7 +21,6 @@ var Renderer = class {
21
21
  }
22
22
  async render(components) {
23
23
  const results = {};
24
- const errors = {};
25
24
  for (const [specifier] of Object.entries(components)) {
26
25
  const mockOutput = mockComponents[specifier];
27
26
  if (!mockOutput) {
@@ -31,12 +30,9 @@ var Renderer = class {
31
30
  results[specifier] = mockOutput.result;
32
31
  }
33
32
  if (mockOutput.error) {
34
- errors[specifier] = mockOutput.error;
33
+ throw new Error(mockOutput.error);
35
34
  }
36
35
  }
37
- if (Object.keys(errors).length) {
38
- return {results, errors};
39
- }
40
36
  return {results, bundles: new Set([2, 3, 4])};
41
37
  }
42
38
  };
@@ -42,11 +42,7 @@ function preloadDataViewTransformer(_options, {config, moduleBundler, resourceRe
42
42
  return {};
43
43
  }
44
44
  import_diagnostics.logger.debug({label: NAME, message: `Preload data for root component "${rootComponent}"`});
45
- const {
46
- results = {},
47
- errors,
48
- bundles
49
- } = await (0, import_instrumentation.getTracer)().trace({
45
+ const {results = {}, bundles} = await (0, import_instrumentation.getTracer)().trace({
50
46
  name: import_instrumentation.ViewSpan.PreloadData,
51
47
  attributes: {rootComponent}
52
48
  }, async () => {
@@ -54,20 +50,23 @@ function preloadDataViewTransformer(_options, {config, moduleBundler, resourceRe
54
50
  if (!route) {
55
51
  throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
56
52
  }
57
- return await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render({[rootComponent]: {specifier: rootComponent, props: {}}}, route, viewContext.runtimeEnvironment, viewContext.runtimeParams);
58
- });
59
- if (errors) {
60
- for (const err of Object.entries(errors)) {
53
+ try {
54
+ return await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render({[rootComponent]: {specifier: rootComponent, props: {}}}, route, viewContext.runtimeEnvironment, viewContext.runtimeParams);
55
+ } catch (e) {
61
56
  import_diagnostics.logger.warn({
62
57
  label: "preloadDataViewTransformer",
63
- message: `Unexpected error during preload data: ${err[0]}`
64
- }, err[1]);
58
+ message: import_diagnostics.descriptions.APPLICATION.PRELOAD_DATA_ERROR(rootComponent, (0, import_diagnostics.stringifyError)(e))
59
+ });
60
+ return {};
65
61
  }
62
+ });
63
+ const result = results[rootComponent];
64
+ if (!result) {
66
65
  return {};
67
66
  }
68
- const {props, markup, cache: {ttl} = {ttl: void 0}, status} = results[rootComponent];
67
+ const {props, markup, cache: {ttl} = {ttl: void 0}, status} = result || {};
69
68
  import_diagnostics.logger.verbose({label: NAME, message: "response", additionalInfo: props});
70
- markup && (0, import_utils.addHeadMarkup)([results[rootComponent]], stringBuilder);
69
+ markup && (0, import_utils.addHeadMarkup)([result], stringBuilder);
71
70
  metadata.serverData = metadata.serverData || {};
72
71
  Object.assign(metadata.serverData, props);
73
72
  metadata.serverBundles = bundles ? new Set([...allBundles, ...bundles]) : allBundles;
@@ -166,6 +166,7 @@ var FetchController = class {
166
166
  }
167
167
  async fetchWithAgent(rawUrl, init, forwardedHost, coreProxy, span) {
168
168
  let {origin, servername} = coreProxy;
169
+ forwardedHost = (0, import_shared_utils.getHostWithoutPort)(forwardedHost) ?? forwardedHost;
169
170
  const host = coreProxy.host ?? forwardedHost.replace(/^https?:\/\//, "");
170
171
  const ENHANCED_DOMAIN_TLD = ".site.com";
171
172
  const MY_DOMAIN_TLD = ".salesforce.com";
@@ -87,47 +87,24 @@ var Renderer = class {
87
87
  }
88
88
  async renderComponents(components, route, runtimeEnvironment, runtimeParams, serverData = {}, isFirstOf2PassSSR = false, abortController) {
89
89
  const results = {};
90
- const errors = {};
91
90
  const roots = Object.keys(components);
92
91
  const services = (0, import_utils.getServerBootstrapServices)(route);
93
92
  const reevaluateModules = (0, import_shared_utils.getFeatureFlags)().REEVALUATE_MODULES === true;
94
93
  let loader, bootstrapServiceEvaluationMap;
95
94
  try {
96
95
  let lwcEngine, serverBootstrapServices;
97
- ({bootstrapServiceEvaluationMap, loader, lwcEngine, serverBootstrapServices} = await this.createLoader(components, route, serverData, isFirstOf2PassSSR, services, errors, runtimeEnvironment, runtimeParams, abortController));
96
+ ({bootstrapServiceEvaluationMap, loader, lwcEngine, serverBootstrapServices} = await this.createLoader(components, route, serverData, isFirstOf2PassSSR, services, runtimeEnvironment, runtimeParams, abortController));
98
97
  const componentModules = await this.loadAppCode(components, route, roots, loader);
99
- await this.executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, errors, runtimeEnvironment, runtimeParams);
98
+ await this.executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, runtimeEnvironment, runtimeParams);
100
99
  if (!route.bootstrap.ssr) {
101
- if (Object.keys(errors).length) {
102
- return {results, errors};
103
- }
104
100
  return {results, bundles: loader?.getBundles()};
105
101
  }
106
102
  loader?.getFetchController().enableNoOpFetch();
107
103
  for (const component of componentModules) {
108
- if (errors[component.specifier]) {
109
- continue;
110
- }
111
- const {html, error} = await renderToString(lwcEngine.module, component, results[component.specifier].props);
112
- if (error) {
113
- errors[component.specifier] = error;
114
- continue;
115
- }
104
+ const {html} = await renderToString(lwcEngine.module, component, results[component.specifier].props);
116
105
  results[component.specifier].html = html;
117
106
  }
118
- const bundles = loader?.getBundles();
119
- if (Object.keys(errors).length) {
120
- return {results, errors, bundles};
121
- }
122
- return {results, bundles};
123
- } catch (e) {
124
- const error = Object(e);
125
- return {
126
- errors: {
127
- [roots.join(",")]: error.message ?? (0, import_diagnostics.stringifyError)(e)
128
- },
129
- bundles: loader?.getBundles()
130
- };
107
+ return {results, bundles: loader?.getBundles()};
131
108
  } finally {
132
109
  loader?.getFetchController().disableNoOpFetch();
133
110
  loader?.getFetchController().enableFetchKillSwitch();
@@ -162,7 +139,7 @@ var Renderer = class {
162
139
  });
163
140
  });
164
141
  }
165
- async executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, errors, runtimeEnvironment, runtimeParams) {
142
+ async executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, runtimeEnvironment, runtimeParams) {
166
143
  return (0, import_instrumentation.getTracer)().trace({
167
144
  name: import_instrumentation.ViewSpan.ExecuteServices,
168
145
  attributes: {
@@ -189,11 +166,7 @@ var Renderer = class {
189
166
  basePath: runtimeParams.basePath || runtimeEnvironment.basePath,
190
167
  crossRequestCache: this.globalCache
191
168
  };
192
- const {data, error} = await getServerData(component, context, serverData);
193
- if (error) {
194
- errors[component.specifier] = error;
195
- continue;
196
- }
169
+ const {data} = await getServerData(component, context, serverData);
197
170
  if (data) {
198
171
  results[component.specifier] = data;
199
172
  }
@@ -203,7 +176,7 @@ var Renderer = class {
203
176
  }
204
177
  });
205
178
  }
206
- async createLoader(components, route, serverData, isFirstOf2PassSSR, services, errors, runtimeEnvironment, runtimeParams, abortController) {
179
+ async createLoader(components, route, serverData, isFirstOf2PassSSR, services, runtimeEnvironment, runtimeParams, abortController) {
207
180
  return (0, import_instrumentation.getTracer)().trace({
208
181
  name: import_instrumentation.ViewSpan.CreateLoader,
209
182
  attributes: {
@@ -232,10 +205,7 @@ var Renderer = class {
232
205
  const serviceModules = await Promise.all(services.map((specifier) => loader?.load(specifier)));
233
206
  serverBootstrapServices = (0, import_serverBootstrapServices.createServerBootstrapServices)(loader);
234
207
  for (const service of serviceModules) {
235
- const error = await (0, import_serverBootstrapServices.evaluateServerBootstrapModule)(service, serverBootstrapServices.serviceAPI);
236
- if (error) {
237
- errors[service.specifier] = error;
238
- }
208
+ await (0, import_serverBootstrapServices.evaluateServerBootstrapModule)(service, serverBootstrapServices.serviceAPI);
239
209
  }
240
210
  }
241
211
  const ret = {
@@ -301,9 +271,9 @@ function getServerData(component, context, serverData) {
301
271
  Object.assign(serverData, data.props);
302
272
  return {data};
303
273
  } catch (e) {
304
- const message = `Error in "getServerData" for "${component.specifier}": ${(0, import_diagnostics.stringifyError)(e)}`;
305
- import_diagnostics.logger.error(message);
306
- return {error: message};
274
+ if (e instanceof import_diagnostics.LwrError)
275
+ throw e;
276
+ throw new import_diagnostics.LwrApplicationError(`Error in "getServerData" for "${component.specifier}": ${(0, import_diagnostics.stringifyError)(e)}`);
307
277
  }
308
278
  });
309
279
  }
@@ -318,11 +288,12 @@ async function renderToString(engine, component, props) {
318
288
  const html = (0, import_shared_utils.getFeatureFlags)().SSR_COMPILER_ENABLED ? await engine.renderComponent(elementName, moduleDefault, props, "sync") : engine.renderComponent(elementName, moduleDefault, props);
319
289
  return {html};
320
290
  } catch (e) {
291
+ if (e instanceof import_diagnostics.LwrError)
292
+ throw e;
321
293
  const error = Object(e);
322
294
  const message = error.message ?? (0, import_diagnostics.stringifyError)(e);
323
295
  const detailedMessage = error.wcStack ? "An error occurred during server-side rendering for component stack: " + error.wcStack + ". Error was: " + message : `An error occurred during server-side rendering "${component.specifier}": ` + message;
324
- import_diagnostics.logger.error(detailedMessage);
325
- return {error: detailedMessage};
296
+ throw new import_diagnostics.LwrApplicationError(detailedMessage);
326
297
  }
327
298
  });
328
299
  }
@@ -76,9 +76,9 @@ function evaluateServerBootstrapModule(serviceModule, serviceApi) {
76
76
  try {
77
77
  await serviceModule.module.default(serviceApi);
78
78
  } catch (e) {
79
- const message = `An SSR error occurred in bootstrap service "${serviceModule.specifier}": ${(0, import_diagnostics.stringifyError)(e)}`;
80
- import_diagnostics.logger.error(message);
81
- return message;
79
+ if (e instanceof import_diagnostics.LwrError)
80
+ throw e;
81
+ throw new import_diagnostics.LwrApplicationError(`An SSR error occurred in bootstrap service "${serviceModule.specifier}": ${(0, import_diagnostics.stringifyError)(e)}`);
82
82
  }
83
83
  });
84
84
  }
@@ -27,8 +27,6 @@ __export(exports, {
27
27
  SSR_PROPS_ATTR: () => SSR_PROPS_ATTR,
28
28
  addHeadMarkup: () => addHeadMarkup,
29
29
  createHeadMarkup: () => createHeadMarkup,
30
- createSsrErrorMarkup: () => createSsrErrorMarkup,
31
- createSsrErrorMessage: () => createSsrErrorMessage,
32
30
  getLoaderConfig: () => getLoaderConfig,
33
31
  getLoaderId: () => getLoaderId,
34
32
  getLoaderShim: () => getLoaderShim,
@@ -47,18 +45,6 @@ function getRenderTimeout() {
47
45
  const override = process.env.SSR_TIMEOUT;
48
46
  return override ? Number.parseInt(override) : DEFAULT_SSR_TIMEOUT;
49
47
  }
50
- function createSsrErrorMessage(specifier, e, fallback = true) {
51
- const fallbackMsg = fallback ? " Falling back to client-side rendering." : "";
52
- return `Server-side rendering for "${specifier}" failed.${fallbackMsg} Reason: ${(0, import_diagnostics.stringifyError)(e)}`;
53
- }
54
- function createSsrErrorMarkup(errors, basePath) {
55
- let markup = '<div style="font-family:sans-serif;margin:50px;font-size:1.2em;"><h1>500: Server-side rendering failed</h1><p>Reasons:</p><ul>';
56
- Object.entries(errors).forEach(([specifier, reason]) => {
57
- markup += `<li><strong>${specifier}</strong>: ${(0, import_diagnostics.stringifyError)(reason)}</li>`;
58
- });
59
- markup += `</ul><p style="padding-top:1em;">See more information in the browser console. Contact your administrator for assistance.</p></div>`;
60
- return markup;
61
- }
62
48
  async function getLoaderShim(resourceRegistry, runtimeEnvironment, bootstrapConfig) {
63
49
  const {debug} = runtimeEnvironment;
64
50
  const useDebug = debug && !(0, import_shared_utils.isLambdaEnv)();
@@ -61,54 +61,39 @@ var LwcViewProvider = class extends import_base_view_provider.default {
61
61
  properties: viewProperties,
62
62
  render: async (runtimeParams, runtimeEnvironment) => {
63
63
  const {config, moduleBundler, resourceRegistry} = this;
64
- const {debug} = runtimeEnvironment;
65
64
  const element = (0, import_shared_utils.moduleSpecifierToKebabCase)(specifier);
66
65
  return (0, import_instrumentation.getTracer)().trace({
67
66
  name: import_instrumentation.ViewSpan.RenderPage,
68
67
  attributes: {specifier}
69
68
  }, async () => {
70
- const route = this.routes.find((r) => r.id === viewId.id);
71
- if (!route) {
72
- throw new Error(`Unable to resolve configuration for view: ${viewId.id}`);
73
- }
74
- const {
75
- results = {},
76
- errors,
77
- bundles
78
- } = await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render({[specifier]: {specifier, props: {}}}, route, runtimeEnvironment, Object(runtimeParams), void 0, true);
79
- if (errors) {
80
- const errorString = Object.values(errors).join(", ");
81
- if (!debug || (0, import_shared_utils.isLocalDev)() && process.env.SSR_THROW_ERRORS === "true") {
82
- throw new import_diagnostics.LwrApplicationError(import_diagnostics.descriptions.APPLICATION.SSR_ERROR(specifier, errorString));
69
+ try {
70
+ const route = this.routes.find((r) => r.id === viewId.id);
71
+ if (!route) {
72
+ throw new Error(`Unable to resolve configuration for view: ${viewId.id}`);
73
+ }
74
+ const {results = {}, bundles} = await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render({[specifier]: {specifier, props: {}}}, route, runtimeEnvironment, Object(runtimeParams), void 0, true);
75
+ const {html, props, markup, cache, status} = results[specifier] || {};
76
+ if (!html) {
77
+ throw new Error("Failed to render content template component");
83
78
  }
84
- const message = (0, import_utils.createSsrErrorMessage)(specifier, errorString, false);
85
- import_diagnostics.logger.warn(message, errors[specifier]);
79
+ if (markup)
80
+ viewProperties.serverHeadMarkup = (0, import_utils.createHeadMarkup)([results[specifier]]);
86
81
  return {
87
- renderedView: (0, import_utils.createSsrErrorMarkup)(errors, this.runtimeEnvironment.basePath),
82
+ renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
88
83
  metadata: {
89
- serverDebug: {message: debug ? message : void 0},
84
+ serverData: props,
90
85
  customElements: [],
91
- assetReferences: []
92
- }
86
+ assetReferences: [],
87
+ serverBundles: bundles
88
+ },
89
+ cache,
90
+ status
93
91
  };
92
+ } catch (e) {
93
+ if (e instanceof import_diagnostics.LwrError)
94
+ throw e;
95
+ throw new import_diagnostics.LwrApplicationError(import_diagnostics.descriptions.APPLICATION.SSR_ERROR(specifier, (0, import_diagnostics.stringifyError)(e)));
94
96
  }
95
- const {html, props, markup, cache, status} = results[specifier];
96
- if (!html) {
97
- throw new Error(`Failed to render content template component '${specifier}'`);
98
- }
99
- if (markup)
100
- viewProperties.serverHeadMarkup = (0, import_utils.createHeadMarkup)([results[specifier]]);
101
- return {
102
- renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
103
- metadata: {
104
- serverData: props,
105
- customElements: [],
106
- assetReferences: [],
107
- serverBundles: bundles
108
- },
109
- cache,
110
- status
111
- };
112
97
  });
113
98
  }
114
99
  };
@@ -48,12 +48,8 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
48
48
  if (!metadata.serverData) {
49
49
  metadata.serverData = {};
50
50
  }
51
- if (!metadata.serverDebug) {
52
- metadata.serverDebug = {};
53
- }
54
51
  const allBundles = new Set([...metadata.serverBundles ?? []]);
55
- const {customElements, serverData, serverDebug} = metadata;
56
- const {debug} = viewContext.runtimeEnvironment;
52
+ const {customElements, serverData} = metadata;
57
53
  const ssrModules = getComponentsToSSR(customElements, stringBuilder);
58
54
  const rootSpecifiers = Object.values(ssrModules).map((m) => m.specifier);
59
55
  if (!rootSpecifiers.length) {
@@ -62,33 +58,34 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
62
58
  const islands = rootSpecifiers.join(",");
63
59
  let pageTtl;
64
60
  await (0, import_instrumentation.getTracer)().trace({name: import_instrumentation.ViewSpan.RenderIsland, attributes: {specifiers: islands}}, async () => {
65
- const route = routes.find((r) => r.id === viewContext.view.id);
66
- if (!route) {
67
- throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
68
- }
69
- const {
70
- results,
71
- errors,
72
- bundles: islandBundles
73
- } = await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render(ssrModules, route, viewContext.runtimeEnvironment, viewContext.runtimeParams, metadata.serverData, false);
74
- for (const root in results) {
75
- const {html, props, cache} = results[root];
76
- const {tagName, startOffset, endOffset, hydrate} = ssrModules[root];
77
- pageTtl = (0, import_shared_utils.shortestTtl)(cache?.ttl, pageTtl);
78
- if (html) {
79
- let propsAttr = "";
80
- if (hydrate) {
81
- const propsId = (0, import_utils.getPropsId)();
82
- propsAttr = ` ${import_utils.SSR_PROPS_ATTR}="${propsId}"`;
83
- serverData[propsId] = props;
61
+ try {
62
+ const route = routes.find((r) => r.id === viewContext.view.id);
63
+ if (!route) {
64
+ throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
65
+ }
66
+ const {results, bundles: islandBundles} = await (0, import_renderer.getRenderer)(config, moduleBundler, resourceRegistry).render(ssrModules, route, viewContext.runtimeEnvironment, viewContext.runtimeParams, metadata.serverData, false);
67
+ for (const root in results) {
68
+ const {html, props, cache} = results[root] || {};
69
+ const {tagName, startOffset, endOffset, hydrate} = ssrModules[root];
70
+ pageTtl = (0, import_shared_utils.shortestTtl)(cache?.ttl, pageTtl);
71
+ if (html) {
72
+ let propsAttr = "";
73
+ if (hydrate) {
74
+ const propsId = (0, import_utils.getPropsId)();
75
+ propsAttr = ` ${import_utils.SSR_PROPS_ATTR}="${propsId}"`;
76
+ serverData[propsId] = props;
77
+ }
78
+ const [, remain] = html.split(`<${tagName}`);
79
+ stringBuilder.overwrite(startOffset, endOffset, [`<${tagName}`, propsAttr, remain].join(""));
84
80
  }
85
- const [, remain] = html.split(`<${tagName}`);
86
- stringBuilder.overwrite(startOffset, endOffset, [`<${tagName}`, propsAttr, remain].join(""));
87
81
  }
82
+ metadata.serverBundles = islandBundles ? new Set([...allBundles, ...islandBundles]) : allBundles;
83
+ results && (0, import_utils.addHeadMarkup)(Object.values(results), stringBuilder);
84
+ } catch (e) {
85
+ if (e instanceof import_diagnostics.LwrError)
86
+ throw e;
87
+ throw new import_diagnostics.LwrApplicationError(import_diagnostics.descriptions.APPLICATION.SSR_ERROR(islands, (0, import_diagnostics.stringifyError)(e)));
88
88
  }
89
- metadata.serverBundles = islandBundles ? new Set([...allBundles, ...islandBundles]) : allBundles;
90
- results && (0, import_utils.addHeadMarkup)(Object.values(results), stringBuilder);
91
- errors && handleErrors(errors, customElements, islands, debug, serverDebug);
92
89
  });
93
90
  import_diagnostics.logger.verbose({
94
91
  label: "lwcSsrViewTransformer",
@@ -118,22 +115,3 @@ function getComponentsToSSR(customElements, stringBuilder) {
118
115
  }
119
116
  return cmpInfo;
120
117
  }
121
- function handleErrors(errors, customElements, specifiers, debug, serverDebug) {
122
- const allErrors = Object.values(errors).join(", ");
123
- if (!debug || (0, import_shared_utils.isLocalDev)() && process.env.SSR_THROW_ERRORS === "true") {
124
- throw new import_diagnostics.LwrApplicationError(import_diagnostics.descriptions.APPLICATION.SSR_ERROR(specifiers, allErrors));
125
- }
126
- Object.entries(errors).forEach(([specifier, err]) => {
127
- const ce = customElements.find(({tagName}) => specifier === (0, import_shared_utils.kebabCaseToModuleSpecifier)(tagName));
128
- if (ce) {
129
- ce.props === void 0 ? ce.props = {
130
- [import_shared_utils.HYDRATE_DIRECTIVE]: import_shared_utils.HYDRATE_CLIENT_VALUE
131
- } : ce.props[import_shared_utils.HYDRATE_DIRECTIVE] = import_shared_utils.HYDRATE_CLIENT_VALUE;
132
- }
133
- const errMessage = (0, import_utils.createSsrErrorMessage)(specifier, err);
134
- import_diagnostics.logger.warn(errMessage, err);
135
- });
136
- if (debug) {
137
- serverDebug.message = (0, import_utils.createSsrErrorMessage)(specifiers, allErrors);
138
- }
139
- }
@@ -1,4 +1,4 @@
1
- import { logger } from '@lwrjs/diagnostics';
1
+ import { descriptions, logger, stringifyError } from '@lwrjs/diagnostics';
2
2
  import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
3
3
  import { addHeadMarkup } from '../utils.js';
4
4
  import { getRenderer } from '../renderer.js';
@@ -26,7 +26,7 @@ export default function preloadDataViewTransformer(_options, { config, moduleBun
26
26
  return {}; // must be a CSRed rootComponent with preloadData ON
27
27
  }
28
28
  logger.debug({ label: NAME, message: `Preload data for root component "${rootComponent}"` });
29
- const { results = {}, errors, bundles, } = await getTracer().trace({
29
+ const { results = {}, bundles } = await getTracer().trace({
30
30
  name: ViewSpan.PreloadData,
31
31
  attributes: { rootComponent },
32
32
  }, async () => {
@@ -34,23 +34,27 @@ export default function preloadDataViewTransformer(_options, { config, moduleBun
34
34
  if (!route) {
35
35
  throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
36
36
  }
37
- return await getRenderer(config, moduleBundler, resourceRegistry).render({ [rootComponent]: { specifier: rootComponent, props: {} } }, route, viewContext.runtimeEnvironment, viewContext.runtimeParams);
38
- });
39
- // If we find errors just log as warnings since these are SSR errors for a CSR page
40
- if (errors) {
41
- for (const err of Object.entries(errors)) {
37
+ try {
38
+ return await getRenderer(config, moduleBundler, resourceRegistry).render({ [rootComponent]: { specifier: rootComponent, props: {} } }, route, viewContext.runtimeEnvironment, viewContext.runtimeParams);
39
+ }
40
+ catch (e) {
41
+ // If we find errors just log as warnings since these are SSR errors for a CSR page
42
42
  logger.warn({
43
43
  label: 'preloadDataViewTransformer',
44
- message: `Unexpected error during preload data: ${err[0]}`,
45
- }, err[1]);
44
+ message: descriptions.APPLICATION.PRELOAD_DATA_ERROR(rootComponent, stringifyError(e)),
45
+ });
46
+ return {}; // return 0 results
46
47
  }
48
+ });
49
+ const result = results[rootComponent];
50
+ if (!result) {
47
51
  // Returns no data since there was an error loading modules
48
52
  return {};
49
53
  }
50
54
  // Log and process the data response
51
- const { props, markup, cache: { ttl } = { ttl: undefined }, status } = results[rootComponent];
55
+ const { props, markup, cache: { ttl } = { ttl: undefined }, status } = result || {};
52
56
  logger.verbose({ label: NAME, message: 'response', additionalInfo: props });
53
- markup && addHeadMarkup([results[rootComponent]], stringBuilder); // add links to the <head> tag
57
+ markup && addHeadMarkup([result], stringBuilder); // add links to the <head> tag
54
58
  metadata.serverData = metadata.serverData || {}; // create serverData if necessary
55
59
  Object.assign(metadata.serverData, props); // add the preloaded data to serverData for serialization
56
60
  metadata.serverBundles = bundles ? new Set([...allBundles, ...bundles]) : allBundles; // add server bundles for preloadData
@@ -1,7 +1,7 @@
1
1
  import { Pool as ClientPool } from 'undici';
2
2
  import { logger } from '@lwrjs/diagnostics';
3
3
  import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
4
- import { REQUEST_DEPTH_HEADER } from '@lwrjs/shared-utils';
4
+ import { REQUEST_DEPTH_HEADER, getHostWithoutPort } from '@lwrjs/shared-utils';
5
5
  const ROUTE_CORE_HEADER = 'X-SFDC-Route-Core';
6
6
  // a single Lambda only services 1 org, so this cache will not grow too large
7
7
  const CORE_CLIENTS = new Map();
@@ -186,6 +186,7 @@ export class FetchController {
186
186
  }
187
187
  async fetchWithAgent(rawUrl, init, forwardedHost, coreProxy, span) {
188
188
  let { origin, servername } = coreProxy;
189
+ forwardedHost = getHostWithoutPort(forwardedHost) ?? forwardedHost;
189
190
  const host = coreProxy.host ?? forwardedHost.replace(/^https?:\/\//, '');
190
191
  const ENHANCED_DOMAIN_TLD = '.site.com';
191
192
  const MY_DOMAIN_TLD = '.salesforce.com';
@@ -13,7 +13,6 @@ export interface ServerResults extends SsrDataResponse {
13
13
  }
14
14
  export interface RenderResults {
15
15
  results?: Record<string, ServerResults>;
16
- errors?: Record<string, string>;
17
16
  bundles?: Set<BundleDefinition>;
18
17
  }
19
18
  /**
@@ -50,7 +49,7 @@ export declare class Renderer {
50
49
  * @param runtimeEnvironment - environment context
51
50
  * @param runtimeParams - request context
52
51
  * @param serverData - render data TODO serverData is modified (add test?)
53
- * @returns render results and errors per component
52
+ * @returns render results per component
54
53
  */
55
54
  render(components: Record<string, Component>, route: NormalizedLwrRoute | NormalizedLwrErrorRoute, runtimeEnvironment: RuntimeEnvironment, runtimeParams: RuntimeParams, serverData?: ServerData, isFirstOf2PassSSR?: boolean): Promise<RenderResults>;
56
55
  private renderComponents;
@@ -1,6 +1,6 @@
1
1
  // TODO: investigate perf impact W-16056356
2
2
  import { LRUCache } from 'lru-cache';
3
- import { LwrApplicationError, descriptions, logger, stringifyError } from '@lwrjs/diagnostics';
3
+ import { LwrApplicationError, LwrError, descriptions, logger, stringifyError } from '@lwrjs/diagnostics';
4
4
  import { buildEnvironmentContext, getCacheKeyFromJson, getSpecifier, isLambdaEnv, moduleSpecifierToKebabCase, getFeatureFlags, TaskPool, isLocalDev, cookieStringToObject, } from '@lwrjs/shared-utils';
5
5
  import { ViewSpan, cacheCountStore, getTracer } from '@lwrjs/instrumentation';
6
6
  import { getServerBootstrapServices, getRenderTimeout } from './utils.js';
@@ -61,7 +61,7 @@ export class Renderer {
61
61
  * @param runtimeEnvironment - environment context
62
62
  * @param runtimeParams - request context
63
63
  * @param serverData - render data TODO serverData is modified (add test?)
64
- * @returns render results and errors per component
64
+ * @returns render results per component
65
65
  */
66
66
  async render(components, route, runtimeEnvironment, runtimeParams, serverData = {}, isFirstOf2PassSSR) {
67
67
  let result;
@@ -93,7 +93,6 @@ export class Renderer {
93
93
  }
94
94
  async renderComponents(components, route, runtimeEnvironment, runtimeParams, serverData = {}, isFirstOf2PassSSR = false, abortController) {
95
95
  const results = {};
96
- const errors = {};
97
96
  const roots = Object.keys(components);
98
97
  const services = getServerBootstrapServices(route);
99
98
  // For LWR@MRT, module re-evaluation is enabled by default
@@ -111,48 +110,24 @@ export class Renderer {
111
110
  // When `REEVALUATE_MODULES` is enabled, we only have a single context/loader, regardless of env
112
111
  let lwcEngine, serverBootstrapServices;
113
112
  ({ bootstrapServiceEvaluationMap, loader, lwcEngine, serverBootstrapServices } =
114
- await this.createLoader(components, route, serverData, isFirstOf2PassSSR, services, errors, runtimeEnvironment, runtimeParams, abortController));
113
+ await this.createLoader(components, route, serverData, isFirstOf2PassSSR, services, runtimeEnvironment, runtimeParams, abortController));
115
114
  // load root component modules (and dependencies)
116
115
  const componentModules = await this.loadAppCode(components, route, roots, loader);
117
116
  // Execute Services that fetch application data
118
- await this.executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, errors, runtimeEnvironment, runtimeParams);
117
+ await this.executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, runtimeEnvironment, runtimeParams);
119
118
  // exit early when preloading data
120
119
  if (!route.bootstrap.ssr) {
121
- if (Object.keys(errors).length) {
122
- return { results, errors };
123
- }
124
120
  return { results, bundles: loader?.getBundles() };
125
121
  }
126
122
  // Assumed in SINGLE_RENDER mode to enable no-op during renderCmp phase.
127
123
  loader?.getFetchController().enableNoOpFetch();
128
124
  // render components
129
125
  for (const component of componentModules) {
130
- // skip rendering if an error has already occurred for the component
131
- if (errors[component.specifier]) {
132
- continue;
133
- }
134
126
  // eslint-disable-next-line no-await-in-loop
135
- const { html, error } = await renderToString(lwcEngine.module, component, results[component.specifier].props);
136
- if (error) {
137
- errors[component.specifier] = error;
138
- continue;
139
- }
127
+ const { html } = await renderToString(lwcEngine.module, component, results[component.specifier].props);
140
128
  results[component.specifier].html = html;
141
129
  }
142
- const bundles = loader?.getBundles();
143
- if (Object.keys(errors).length) {
144
- return { results, errors, bundles };
145
- }
146
- return { results, bundles };
147
- }
148
- catch (e) {
149
- const error = Object(e);
150
- return {
151
- errors: {
152
- [roots.join(',')]: error.message ?? stringifyError(e),
153
- },
154
- bundles: loader?.getBundles(),
155
- };
130
+ return { results, bundles: loader?.getBundles() };
156
131
  }
157
132
  finally {
158
133
  // Assumed in SINGLE_RENDER mode
@@ -205,7 +180,7 @@ export class Renderer {
205
180
  /**
206
181
  * Run bootstrap services and fetch server data
207
182
  */
208
- async executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, errors, runtimeEnvironment, runtimeParams) {
183
+ async executeDataServices(components, route, serverBootstrapServices, componentModules, serverData, results, runtimeEnvironment, runtimeParams) {
209
184
  return getTracer().trace({
210
185
  name: ViewSpan.ExecuteServices,
211
186
  attributes: {
@@ -237,11 +212,7 @@ export class Renderer {
237
212
  crossRequestCache: this.globalCache,
238
213
  };
239
214
  // eslint-disable-next-line
240
- const { data, error } = await getServerData(component, context, serverData);
241
- if (error) {
242
- errors[component.specifier] = error;
243
- continue;
244
- }
215
+ const { data } = await getServerData(component, context, serverData);
245
216
  if (data) {
246
217
  results[component.specifier] = data;
247
218
  }
@@ -255,7 +226,7 @@ export class Renderer {
255
226
  /**
256
227
  * Create and initialize the loader and LWC engine for SSR
257
228
  */
258
- async createLoader(components, route, serverData, isFirstOf2PassSSR, services, errors, runtimeEnvironment, runtimeParams, abortController) {
229
+ async createLoader(components, route, serverData, isFirstOf2PassSSR, services, runtimeEnvironment, runtimeParams, abortController) {
259
230
  return getTracer().trace({
260
231
  name: ViewSpan.CreateLoader,
261
232
  attributes: {
@@ -301,10 +272,7 @@ export class Renderer {
301
272
  // this is where the loader and server data hooks are set
302
273
  for (const service of serviceModules) {
303
274
  // eslint-disable-next-line
304
- const error = await evaluateServerBootstrapModule(service, serverBootstrapServices.serviceAPI);
305
- if (error) {
306
- errors[service.specifier] = error;
307
- }
275
+ await evaluateServerBootstrapModule(service, serverBootstrapServices.serviceAPI);
308
276
  }
309
277
  }
310
278
  const ret = {
@@ -399,9 +367,9 @@ function getServerData(component, context, serverData) {
399
367
  return { data };
400
368
  }
401
369
  catch (e) {
402
- const message = `Error in "getServerData" for "${component.specifier}": ${stringifyError(e)}`;
403
- logger.error(message);
404
- return { error: message };
370
+ if (e instanceof LwrError)
371
+ throw e;
372
+ throw new LwrApplicationError(`Error in "getServerData" for "${component.specifier}": ${stringifyError(e)}`);
405
373
  }
406
374
  });
407
375
  }
@@ -419,6 +387,8 @@ async function renderToString(engine, component, props) {
419
387
  return { html };
420
388
  }
421
389
  catch (e) {
390
+ if (e instanceof LwrError)
391
+ throw e;
422
392
  const error = Object(e);
423
393
  // add the LWC rendering stack to the error message
424
394
  const message = error.message ?? stringifyError(e);
@@ -428,8 +398,7 @@ async function renderToString(engine, component, props) {
428
398
  '. Error was: ' +
429
399
  message
430
400
  : `An error occurred during server-side rendering "${component.specifier}": ` + message;
431
- logger.error(detailedMessage);
432
- return { error: detailedMessage };
401
+ throw new LwrApplicationError(detailedMessage);
433
402
  }
434
403
  });
435
404
  }
@@ -12,5 +12,5 @@ export declare class ServerBootstrapServices {
12
12
  private registerRequestHooks;
13
13
  }
14
14
  export declare function createServerBootstrapServices(loader: ModuleLoader): ServerBootstrapServices;
15
- export declare function evaluateServerBootstrapModule(serviceModule: any, serviceApi: ServerServiceAPI): Promise<string | undefined>;
15
+ export declare function evaluateServerBootstrapModule(serviceModule: any, serviceApi: ServerServiceAPI): Promise<void>;
16
16
  //# sourceMappingURL=serverBootstrapServices.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
2
- import { logger, stringifyError } from '@lwrjs/diagnostics';
2
+ import { LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
3
3
  export class ServerBootstrapServices {
4
4
  evaluateServerDataHooks(serverData = {}) {
5
5
  // now that we have server data, run the server data hooks
@@ -48,9 +48,9 @@ export function evaluateServerBootstrapModule(serviceModule, serviceApi) {
48
48
  await serviceModule.module.default(serviceApi);
49
49
  }
50
50
  catch (e) {
51
- const message = `An SSR error occurred in bootstrap service "${serviceModule.specifier}": ${stringifyError(e)}`;
52
- logger.error(message);
53
- return message;
51
+ if (e instanceof LwrError)
52
+ throw e;
53
+ throw new LwrApplicationError(`An SSR error occurred in bootstrap service "${serviceModule.specifier}": ${stringifyError(e)}`);
54
54
  }
55
55
  });
56
56
  }
@@ -5,8 +5,6 @@ interface ServerEnvironment extends EnvironmentContext {
5
5
  export declare const SSR_PROPS_ATTR = "data-lwr-props-id";
6
6
  export declare function getPropsId(): string;
7
7
  export declare function getRenderTimeout(): number;
8
- export declare function createSsrErrorMessage(specifier: string, e: any, fallback?: boolean): string;
9
- export declare function createSsrErrorMarkup(errors: Record<string, string>, basePath: string): string;
10
8
  export declare function getLoaderShim(resourceRegistry: PublicResourceRegistry, runtimeEnvironment: RuntimeEnvironment, bootstrapConfig: NormalizedLwrAppBootstrapConfig): Promise<string>;
11
9
  export declare function getLoaderId(config: ClientBootstrapConfig, bootstrapConfig: NormalizedLwrAppBootstrapConfig): string;
12
10
  export declare function getLoaderConfig(bootstrapModule: string, config: ProviderAppConfig, runtimeParams: RuntimeParams, serverData: ServerData): ClientBootstrapConfig & {
package/build/es/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { logger, stringifyError } from '@lwrjs/diagnostics';
1
+ import { logger } from '@lwrjs/diagnostics';
2
2
  import { buildEnvironmentContext, getFeatureFlags, normalizeVersionToUri, isLambdaEnv, getSpecifier, } from '@lwrjs/shared-utils';
3
3
  const DEFAULT_SSR_TIMEOUT = 5000; // 5 seconds, override with process.env.SSR_TIMEOUT
4
4
  export const SSR_PROPS_ATTR = 'data-lwr-props-id';
@@ -9,18 +9,6 @@ export function getRenderTimeout() {
9
9
  const override = process.env.SSR_TIMEOUT;
10
10
  return override ? Number.parseInt(override) : DEFAULT_SSR_TIMEOUT;
11
11
  }
12
- export function createSsrErrorMessage(specifier, e, fallback = true) {
13
- const fallbackMsg = fallback ? ' Falling back to client-side rendering.' : '';
14
- return `Server-side rendering for "${specifier}" failed.${fallbackMsg} Reason: ${stringifyError(e)}`;
15
- }
16
- export function createSsrErrorMarkup(errors, basePath) {
17
- let markup = '<div style="font-family:sans-serif;margin:50px;font-size:1.2em;"><h1>500: Server-side rendering failed</h1><p>Reasons:</p><ul>';
18
- Object.entries(errors).forEach(([specifier, reason]) => {
19
- markup += `<li><strong>${specifier}</strong>: ${stringifyError(reason)}</li>`;
20
- });
21
- markup += `</ul><p style="padding-top:1em;">See more information in the browser console. Contact your administrator for assistance.</p></div>`;
22
- return markup;
23
- }
24
12
  export async function getLoaderShim(resourceRegistry, runtimeEnvironment, bootstrapConfig) {
25
13
  const { debug } = runtimeEnvironment;
26
14
  // debug resources are not available in deployed lambda env
@@ -1,8 +1,8 @@
1
1
  import BaseViewProvider from '@lwrjs/base-view-provider';
2
- import { descriptions, logger, LwrApplicationError } from '@lwrjs/diagnostics';
2
+ import { descriptions, LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
3
3
  import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
4
- import { hashContent, isLocalDev, isSpecifier, moduleSpecifierToKebabCase, slugify, } from '@lwrjs/shared-utils';
5
- import { createHeadMarkup, createSsrErrorMarkup, createSsrErrorMessage } from '../utils.js';
4
+ import { hashContent, isSpecifier, moduleSpecifierToKebabCase, slugify } from '@lwrjs/shared-utils';
5
+ import { createHeadMarkup } from '../utils.js';
6
6
  import { getRenderer } from '../renderer.js';
7
7
  export default class LwcViewProvider extends BaseViewProvider {
8
8
  constructor(_pluginConfig, providerConfig) {
@@ -35,61 +35,44 @@ export default class LwcViewProvider extends BaseViewProvider {
35
35
  render: async (runtimeParams, runtimeEnvironment) => {
36
36
  // SSR the root component (without passing any public properties)
37
37
  const { config, moduleBundler, resourceRegistry } = this;
38
- const { debug } = runtimeEnvironment;
39
38
  const element = moduleSpecifierToKebabCase(specifier);
40
39
  return getTracer().trace({
41
40
  name: ViewSpan.RenderPage,
42
41
  attributes: { specifier },
43
42
  }, async () => {
44
- const route = this.routes.find((r) => r.id === viewId.id);
45
- if (!route) {
46
- throw new Error(`Unable to resolve configuration for view: ${viewId.id}`);
47
- }
48
- const { results = {}, errors, bundles, } = await getRenderer(config, moduleBundler, resourceRegistry).render({ [specifier]: { specifier, props: {} } }, route, runtimeEnvironment, Object(runtimeParams), undefined,
49
- // lets the renderer know this is the first of 2-pass SSR
50
- true);
51
- // Handle errors: throw or return an error page
52
- if (errors) {
53
- const errorString = Object.values(errors).join(', ');
54
- // always throw if debug is off
55
- // throw in local dev mode if SSR_THROW_ERRORS === true
56
- if (!debug || (isLocalDev() && process.env.SSR_THROW_ERRORS === 'true')) {
57
- // 500 error for the page request
58
- throw new LwrApplicationError(descriptions.APPLICATION.SSR_ERROR(specifier, errorString));
43
+ try {
44
+ const route = this.routes.find((r) => r.id === viewId.id);
45
+ if (!route) {
46
+ throw new Error(`Unable to resolve configuration for view: ${viewId.id}`);
47
+ }
48
+ const { results = {}, bundles } = await getRenderer(config, moduleBundler, resourceRegistry).render({ [specifier]: { specifier, props: {} } }, route, runtimeEnvironment, Object(runtimeParams), undefined,
49
+ // lets the renderer know this is the first of 2-pass SSR
50
+ true);
51
+ // Insert the SSRed HTML into the document
52
+ const { html, props, markup, cache, status } = results[specifier] || {};
53
+ if (!html) {
54
+ throw new Error('Failed to render content template component');
59
55
  }
60
- // error page
61
- const message = createSsrErrorMessage(specifier, errorString, false);
62
- logger.warn(message, errors[specifier]); // TODO specific metadata for errors
56
+ if (markup)
57
+ viewProperties.serverHeadMarkup = createHeadMarkup([results[specifier]]); // generate <head> markup
63
58
  return {
64
- // render the errors on the browser page; fallback to CSR is not possible on the 1st pass
65
- renderedView: createSsrErrorMarkup(errors, this.runtimeEnvironment.basePath),
66
- // send an error message to the client if debug mode is on
59
+ // add "lwc:external" to the contentTemplate component to mark it as already processed
60
+ renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
67
61
  metadata: {
68
- serverDebug: { message: debug ? message : undefined },
62
+ serverData: props,
69
63
  customElements: [],
70
64
  assetReferences: [],
65
+ serverBundles: bundles,
71
66
  },
67
+ cache,
68
+ status,
72
69
  };
73
70
  }
74
- // Insert the SSRed HTML into the document
75
- const { html, props, markup, cache, status } = results[specifier];
76
- if (!html) {
77
- throw new Error(`Failed to render content template component '${specifier}'`);
71
+ catch (e) {
72
+ if (e instanceof LwrError)
73
+ throw e;
74
+ throw new LwrApplicationError(descriptions.APPLICATION.SSR_ERROR(specifier, stringifyError(e)));
78
75
  }
79
- if (markup)
80
- viewProperties.serverHeadMarkup = createHeadMarkup([results[specifier]]); // generate <head> markup
81
- return {
82
- // add "lwc:external" to the contentTemplate component to mark it as already processed
83
- renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
84
- metadata: {
85
- serverData: props,
86
- customElements: [],
87
- assetReferences: [],
88
- serverBundles: bundles,
89
- },
90
- cache,
91
- status,
92
- };
93
76
  });
94
77
  },
95
78
  };
@@ -1,7 +1,7 @@
1
- import { descriptions, logger, LwrApplicationError } from '@lwrjs/diagnostics';
1
+ import { descriptions, logger, LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
2
2
  import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
3
- import { HYDRATE_CLIENT_VALUE, HYDRATE_DIRECTIVE, isCsrIsland, isHydrateOnLoad, isLocalDev, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
4
- import { SSR_PROPS_ATTR, addHeadMarkup, getPropsId, createSsrErrorMessage } from '../utils.js';
3
+ import { HYDRATE_DIRECTIVE, isCsrIsland, isHydrateOnLoad, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
4
+ import { SSR_PROPS_ATTR, addHeadMarkup, getPropsId } from '../utils.js';
5
5
  import { getRenderer } from '../renderer.js';
6
6
  /**
7
7
  * This is a view transformer run by the view registry during linking of a page document/route (configured in lwr.config.json[routes]).
@@ -38,12 +38,8 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
38
38
  if (!metadata.serverData) {
39
39
  metadata.serverData = {};
40
40
  }
41
- if (!metadata.serverDebug) {
42
- metadata.serverDebug = {};
43
- }
44
41
  const allBundles = new Set([...(metadata.serverBundles ?? [])]); // make a copy
45
- const { customElements, serverData, serverDebug } = metadata;
46
- const { debug } = viewContext.runtimeEnvironment;
42
+ const { customElements, serverData } = metadata;
47
43
  // Gather all the SSRable custom elements (ie: root components) into 1 list
48
44
  const ssrModules = getComponentsToSSR(customElements, stringBuilder);
49
45
  const rootSpecifiers = Object.values(ssrModules).map((m) => m.specifier);
@@ -54,35 +50,41 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
54
50
  const islands = rootSpecifiers.join(',');
55
51
  let pageTtl;
56
52
  await getTracer().trace({ name: ViewSpan.RenderIsland, attributes: { specifiers: islands } }, async () => {
57
- const route = routes.find((r) => r.id === viewContext.view.id);
58
- if (!route) {
59
- throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
60
- }
61
- const { results, errors, bundles: islandBundles, } = await getRenderer(config, moduleBundler, resourceRegistry).render(ssrModules, route, viewContext.runtimeEnvironment, viewContext.runtimeParams, metadata.serverData, false);
62
- for (const root in results) {
63
- const { html, props, cache } = results[root];
64
- const { tagName, startOffset, endOffset, hydrate } = ssrModules[root];
65
- pageTtl = shortestTtl(cache?.ttl, pageTtl);
66
- if (html) {
67
- // Add the props id to the HTML for the custom element
68
- // eg: <some-cmp> -> <some-cmp data-lwr-props-id="1234">
69
- // Then overwrite the custom element with the SSRed component string
70
- let propsAttr = '';
71
- if (hydrate) {
72
- // Only serialize props for custom elements that are to be hydrated
73
- const propsId = getPropsId();
74
- propsAttr = ` ${SSR_PROPS_ATTR}="${propsId}"`;
75
- serverData[propsId] = props;
53
+ try {
54
+ const route = routes.find((r) => r.id === viewContext.view.id);
55
+ if (!route) {
56
+ throw new Error(`Unable to resolve configuration for view: ${viewContext.view.id}`);
57
+ }
58
+ const { results, bundles: islandBundles } = await getRenderer(config, moduleBundler, resourceRegistry).render(ssrModules, route, viewContext.runtimeEnvironment, viewContext.runtimeParams, metadata.serverData, false);
59
+ for (const root in results) {
60
+ const { html, props, cache } = results[root] || {};
61
+ const { tagName, startOffset, endOffset, hydrate } = ssrModules[root];
62
+ pageTtl = shortestTtl(cache?.ttl, pageTtl);
63
+ if (html) {
64
+ // Add the props id to the HTML for the custom element
65
+ // eg: <some-cmp> -> <some-cmp data-lwr-props-id="1234">
66
+ // Then overwrite the custom element with the SSRed component string
67
+ let propsAttr = '';
68
+ if (hydrate) {
69
+ // Only serialize props for custom elements that are to be hydrated
70
+ const propsId = getPropsId();
71
+ propsAttr = ` ${SSR_PROPS_ATTR}="${propsId}"`;
72
+ serverData[propsId] = props;
73
+ }
74
+ const [, remain] = html.split(`<${tagName}`);
75
+ stringBuilder.overwrite(startOffset, endOffset, [`<${tagName}`, propsAttr, remain].join(''));
76
76
  }
77
- const [, remain] = html.split(`<${tagName}`);
78
- stringBuilder.overwrite(startOffset, endOffset, [`<${tagName}`, propsAttr, remain].join(''));
79
77
  }
78
+ metadata.serverBundles = islandBundles
79
+ ? new Set([...allBundles, ...islandBundles])
80
+ : allBundles;
81
+ results && addHeadMarkup(Object.values(results), stringBuilder);
82
+ }
83
+ catch (e) {
84
+ if (e instanceof LwrError)
85
+ throw e;
86
+ throw new LwrApplicationError(descriptions.APPLICATION.SSR_ERROR(islands, stringifyError(e)));
80
87
  }
81
- metadata.serverBundles = islandBundles
82
- ? new Set([...allBundles, ...islandBundles])
83
- : allBundles;
84
- results && addHeadMarkup(Object.values(results), stringBuilder);
85
- errors && handleErrors(errors, customElements, islands, debug, serverDebug);
86
88
  });
87
89
  logger.verbose({
88
90
  label: 'lwcSsrViewTransformer',
@@ -114,34 +116,4 @@ function getComponentsToSSR(customElements, stringBuilder) {
114
116
  }
115
117
  return cmpInfo;
116
118
  }
117
- function handleErrors(errors, customElements, specifiers, debug, serverDebug) {
118
- const allErrors = Object.values(errors).join(', ');
119
- // always fallback to CSR if debug === true
120
- // throw in local dev mode if SSR_THROW_ERRORS === true
121
- if (!debug || (isLocalDev() && process.env.SSR_THROW_ERRORS === 'true')) {
122
- // 500 error for the page request
123
- throw new LwrApplicationError(descriptions.APPLICATION.SSR_ERROR(specifiers, allErrors));
124
- }
125
- // Fallback to CSR in debug mode or if enabled
126
- Object.entries(errors).forEach(([specifier, err]) => {
127
- const ce = customElements.find(({ tagName }) => specifier === kebabCaseToModuleSpecifier(tagName));
128
- if (ce) {
129
- // Fallback to CSR by adding lwr:hydrate="client-only" to the custom element
130
- // This ENSURES the component's JavaScript gets sent to the client for CSRing
131
- ce.props === undefined
132
- ? (ce.props = {
133
- [HYDRATE_DIRECTIVE]: HYDRATE_CLIENT_VALUE,
134
- })
135
- : (ce.props[HYDRATE_DIRECTIVE] = HYDRATE_CLIENT_VALUE);
136
- }
137
- // Log error with stack details
138
- const errMessage = createSsrErrorMessage(specifier, err);
139
- logger.warn(errMessage, err); // TODO specific metadata for errors
140
- });
141
- // Inform the client of the failing modules without exposing any additional
142
- // details (such as callstack) for security reasons
143
- if (debug) {
144
- serverDebug.message = createSsrErrorMessage(specifiers, allErrors);
145
- }
146
- }
147
119
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.17.2-alpha.2",
7
+ "version": "0.17.2-alpha.4",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -42,17 +42,17 @@
42
42
  "build/**/*.d.ts"
43
43
  ],
44
44
  "dependencies": {
45
- "@lwrjs/config": "0.17.2-alpha.2",
46
- "@lwrjs/diagnostics": "0.17.2-alpha.2",
47
- "@lwrjs/instrumentation": "0.17.2-alpha.2",
48
- "@lwrjs/loader": "0.17.2-alpha.2",
49
- "@lwrjs/shared-utils": "0.17.2-alpha.2",
45
+ "@lwrjs/config": "0.17.2-alpha.4",
46
+ "@lwrjs/diagnostics": "0.17.2-alpha.4",
47
+ "@lwrjs/instrumentation": "0.17.2-alpha.4",
48
+ "@lwrjs/loader": "0.17.2-alpha.4",
49
+ "@lwrjs/shared-utils": "0.17.2-alpha.4",
50
50
  "fs-extra": "^11.2.0",
51
51
  "lru-cache": "^10.4.3",
52
- "undici": "^6.19.8"
52
+ "undici": "^6.21.1"
53
53
  },
54
54
  "devDependencies": {
55
- "@lwrjs/types": "0.17.2-alpha.2",
55
+ "@lwrjs/types": "0.17.2-alpha.4",
56
56
  "jest": "^26.6.3",
57
57
  "memfs": "^4.13.0",
58
58
  "ts-jest": "^26.5.6"
@@ -63,5 +63,5 @@
63
63
  "volta": {
64
64
  "extends": "../../../package.json"
65
65
  },
66
- "gitHead": "739b237f5d7f2c1989142cb505a56cc763f21976"
66
+ "gitHead": "d7fb1605cec0bf9fef18e3daeb17dc28b35a80d3"
67
67
  }