@lwrjs/lwc-ssr 0.11.0-alpha.8 → 0.11.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.
package/README.md CHANGED
@@ -22,6 +22,8 @@
22
22
  - [Debug logging](#debug-logging)
23
23
  - [Breakpoints](#breakpoints)
24
24
  - [Inspect bundles](#inspect-bundles)
25
+ - [Diagrams](#diagrams)
26
+ - [Sequence](#sequence)
25
27
 
26
28
  ## Overview
27
29
 
@@ -136,12 +138,16 @@ type GetServerDataHook = (context: SsrRequestContext) => Promise<SsrDataResponse
136
138
  interface SsrRequestContext {
137
139
  // props from template attributes
138
140
  props: Json;
141
+ // URL for the request
142
+ url: string;
139
143
  // values from a parameterized route defined in lwr.config.json
140
144
  params: { [key: string]: string };
141
145
  // search parameters from the request URL
142
- query: { [key: string]: string };
146
+ query: { [key: string]: undefined | string | string[] };
143
147
  // locale string for the request, eg: 'en-US'
144
148
  locale: string;
149
+ // base path for the request, eg: '/shop'
150
+ basePath: string;
145
151
  }
146
152
 
147
153
  interface SsrDataResponse {
@@ -403,3 +409,34 @@ When SSR fails due to a [portability](#portability), it can be difficult to figu
403
409
  4. When the problematic code is found, scroll up to find the component to which it belongs.
404
410
 
405
411
  For example, if SSR fails with this error:`ReferenceError: window is not defined`, then turn off SSR and search the module bundles for prohibited usages of the `window` object.
412
+
413
+ ## Diagrams
414
+
415
+ ### Sequence
416
+
417
+ ```mermaid
418
+ sequenceDiagram
419
+ %% SSR with Data
420
+ actor client as Client
421
+ box LWR-Node
422
+ participant registry as View Registry
423
+ participant transformer as SSR View<br>Transformer
424
+ participant sandbox as SSR Sandbox
425
+ end
426
+ client ->> registry: Requests a page
427
+ registry ->> registry: Generates an HTML base document from layout and content templates
428
+ registry ->> transformer: Sends the base document to get islands processed
429
+ loop For each non-client-only island
430
+ transformer ->> sandbox: Sends the island to be SSRed
431
+ sandbox ->> sandbox: Runs the component's getServerData hook
432
+ sandbox ->> sandbox: Runs the route's SSR bootstrap services
433
+ sandbox ->> sandbox: Converts the island to HTML via LWC SSR
434
+ sandbox ->> transformer: Returns the HTML for the island
435
+ transformer ->> transformer: Replaces the island's HTML element with its SSRed HTML
436
+ end
437
+ transformer -->> registry: Return
438
+ registry ->> registry: Serializes the serverData into the base document
439
+ registry -->> client: Responds with the base document
440
+ client ->> client: Runs the route's SSR bootstrap services
441
+ client ->> client: Hydrates SSRed islands with serialized serverData
442
+ ```
@@ -28,38 +28,68 @@ __export(exports, {
28
28
  default: () => moduleProvider_default
29
29
  });
30
30
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
31
+ var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
31
32
  var import_identity = __toModule(require("../identity.cjs"));
32
33
  function createSsrBootstrapModule(rootSpecifier, services) {
33
34
  let serviceImports = "";
34
35
  let serviceCalls = "";
35
36
  services.forEach((service) => {
36
- const importName = `service_${service.replace(/\//gi, "_").replace(/@/gi, "")}`;
37
+ const importName = (0, import_shared_utils.stringToVariableName)(`service_${service}`);
37
38
  serviceImports += `
38
39
  import ${importName} from '${service}';`;
39
40
  serviceCalls += `
40
- ${importName}();`;
41
+
42
+ globalThis.trace({
43
+ name: '${import_instrumentation.ViewSpan.BootstrapService}',
44
+ attributes: {
45
+ specifier: '${rootSpecifier}',
46
+ serviceSpecifier: '${service}',
47
+ }
48
+ }, () => {
49
+ try {
50
+ ${importName}({ serverData });
51
+ } catch(e) {
52
+ const message = e.message || e;
53
+ // we need to re-throw with the service specifier in the error message
54
+ throw new Error('An SSR error occurred in bootstrap service "${service}": ' + message);
55
+ }
56
+ });`;
41
57
  });
42
58
  return `
43
59
  import { renderComponent } from '@lwc/engine-server';
44
60
  import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
45
61
 
46
62
  (async () => {
47
- let result, props, markup, existingTaskCount;
63
+ let result, props, markup, serverData = globalThis.LWR?.serverData || {}, existingTaskCount;
64
+ // remove the LWR global properties before any customer code is run
65
+ if (globalThis.LWR?.define) {
66
+ // AMD: support dynamic imports in getServerData
67
+ globalThis.LWR = Object.freeze({ define: globalThis.LWR.define });
68
+ } else {
69
+ delete globalThis.LWR; // ESM
70
+ }
71
+
48
72
  try {
49
73
  // 1. setup page data
50
74
  const context = globalThis.getContext();
51
75
  props = context.props;
52
76
  if (rootComponent.getServerData) {
53
77
  const data = await globalThis.trace({
54
- name: 'lwr.view.getServerData',
78
+ name: '${import_instrumentation.ViewSpan.GetServerData}',
55
79
  attributes: {
56
80
  specifier: '${rootSpecifier}'
57
81
  }
58
- }, () => rootComponent.getServerData(context));
59
-
82
+ }, async() => {
83
+ try {
84
+ return await rootComponent.getServerData(context)
85
+ } catch(e) {
86
+ const message = e.message || e;
87
+ // we need to re-throw with rootSpecifier in the error message
88
+ throw new Error('Error in "getServerData" for "${rootSpecifier}": ' + message);
89
+ }
90
+ });
60
91
  props = data.props; // overwrite public props
61
- globalThis.LWR = globalThis.LWR || { serverData: {} };
62
- Object.assign(globalThis.LWR.serverData, data.props); // add props to server data
92
+ Object.assign(serverData, data.props); // add props to server data
63
93
  markup = data.markup;
64
94
  }${serviceCalls}
65
95
 
@@ -69,7 +99,7 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
69
99
 
70
100
  // 2. render component
71
101
  result = globalThis.trace({
72
- name: 'lwr.view.renderComponent',
102
+ name: '${import_instrumentation.ViewSpan.RenderComponent}',
73
103
  attributes: {
74
104
  specifier: '${rootSpecifier}'
75
105
  }
@@ -77,8 +107,8 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
77
107
 
78
108
  } catch(e) {
79
109
  const message = e.message || e;
80
- // Relay the LWC rendering stack
81
-
110
+
111
+ // add the LWC rendering stack
82
112
  const error = e.wcStack ?
83
113
  'An error occurred during server-side rendering for component stack: ' + e.wcStack + '. Error was: ' + message :
84
114
  'An error occured during server-side rendering: ' + message;
@@ -90,7 +120,6 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
90
120
  const currentTaskCount = process.getActiveResourcesInfo
91
121
  ? process.getActiveResourcesInfo().length
92
122
  : 0;
93
-
94
123
  if (currentTaskCount - existingTaskCount > 0) {
95
124
  console.warn('[warn] async tasks encountered while server rendering "${rootSpecifier}"');
96
125
  }
@@ -92,7 +92,7 @@ async function getCode(runtimeEnvironment, serverData, lwrVersion, bundleSpecifi
92
92
  }
93
93
  async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
94
94
  if ((0, import_shared_utils.getFeatureFlags)().SSR_STATIC_BUNDLES) {
95
- return buildBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams);
95
+ return buildBundle(specifier, moduleBundler, routes, {...runtimeEnvironment, debug: false}, runtimeParams);
96
96
  }
97
97
  return bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams, {
98
98
  appendExcludes: false,
@@ -102,27 +102,38 @@ async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, r
102
102
  async function bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams, bundleConfigOverrides) {
103
103
  return await moduleBundler.getModuleBundle({specifier}, runtimeEnvironment, runtimeParams, bundleConfigOverrides);
104
104
  }
105
- async function bundleImports(bundleCode, imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
105
+ async function bundleImports(bundleCode, dynamicImports = [], imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
106
106
  for (const {specifier} of imports) {
107
107
  if (!visited.has(specifier)) {
108
108
  visited.add(specifier);
109
109
  const {code, bundleRecord, version} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
110
- let bundledCode;
111
- if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
112
- const versionedSpecifier = (0, import_shared_utils.getSpecifier)({specifier, version});
113
- const aliasCode = (0, import_shared_utils.createAmdAlias)(versionedSpecifier, specifier);
114
- bundledCode = [code, aliasCode].filter(Boolean).join("");
115
- } else {
116
- bundledCode = code;
117
- }
118
- bundleCode = await bundleImports(bundledCode, bundleRecord.imports, visited, moduleBundler, runtimeEnvironment, runtimeParams) + bundleCode;
110
+ const bundledCode = getBundledCode(runtimeEnvironment, specifier, version, code);
111
+ bundleCode = await bundleImports(bundledCode, bundleRecord.dynamicImports, bundleRecord.imports, visited, moduleBundler, runtimeEnvironment, runtimeParams) + bundleCode;
112
+ }
113
+ }
114
+ for (const {specifier} of dynamicImports) {
115
+ if (!visited.has(specifier)) {
116
+ visited.add(specifier);
117
+ const {code, version} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
118
+ bundleCode += getBundledCode(runtimeEnvironment, specifier, version, code);
119
119
  }
120
120
  }
121
121
  return bundleCode;
122
122
  }
123
+ function getBundledCode(runtimeEnvironment, specifier, version, code) {
124
+ let bundledCode;
125
+ if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
126
+ const versionedSpecifier = (0, import_shared_utils.getSpecifier)({specifier, version});
127
+ const aliasCode = (0, import_shared_utils.createAmdAlias)(versionedSpecifier, specifier);
128
+ bundledCode = [code, aliasCode].filter(Boolean).join("");
129
+ } else {
130
+ bundledCode = code;
131
+ }
132
+ return bundledCode;
133
+ }
123
134
  async function getBundleWithImports(specifier, moduleBundler, runtimeEnvironment, runtimeParams) {
124
135
  const {code, bundleRecord} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
125
- return await bundleImports(code, bundleRecord.imports, new Set(["lwc", specifier]), moduleBundler, runtimeEnvironment, runtimeParams);
136
+ return await bundleImports(code, bundleRecord.dynamicImports, bundleRecord.imports, new Set(["lwc", specifier]), moduleBundler, runtimeEnvironment, runtimeParams);
126
137
  }
127
138
  async function buildBundle(ssrSpecifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
128
139
  const {rootSpecifier, route} = (0, import_identity.parseSpecifier)(ssrSpecifier, routes);
@@ -28,11 +28,10 @@ __export(exports, {
28
28
  });
29
29
  var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
30
30
  var import_near_membrane_node = __toModule(require("@locker/near-membrane-node"));
31
- var import_node_fetch = __toModule(require("node-fetch"));
32
31
  var import_crypto = __toModule(require("crypto"));
33
32
  var import_url = __toModule(require("url"));
34
33
  var import_utils = __toModule(require("./utils.cjs"));
35
- function runCode(codes, context) {
34
+ function runCode(codes, context, host) {
36
35
  return new Promise((resolve, reject) => {
37
36
  let resolver;
38
37
  const p = new Promise((r) => resolver = r);
@@ -46,9 +45,10 @@ function runCode(codes, context) {
46
45
  crypto: import_crypto.webcrypto,
47
46
  getContext,
48
47
  trace,
49
- fetch: import_node_fetch.default,
48
+ fetch: (0, import_utils.createFetchEndowment)(host),
50
49
  resolver,
51
50
  URL: import_url.URL,
51
+ URLSearchParams: import_url.URLSearchParams,
52
52
  process,
53
53
  setTimeout,
54
54
  clearTimeout,
@@ -31,17 +31,18 @@ var import_utils = __toModule(require("./utils.cjs"));
31
31
  var HEADER = "/* This module is generated and meant to be used in a Server context */";
32
32
  var WORKER_CODE_SANDBOX_APIS = [
33
33
  `const { parentPort, workerData } = require('worker_threads');`,
34
+ `globalThis.fetch = require('@lwrjs/lwc-ssr/viewTransformer').createFetchEndowment(workerData.host);`,
35
+ `delete workerData.host`,
34
36
  `globalThis.getContext = () => workerData;`,
35
- `globalThis.fetch = require('node-fetch');`,
36
37
  `globalThis.crypto = require('crypto').webcrypto;`,
37
38
  `globalThis.resolver = (...args) => parentPort.postMessage(...args);`,
38
39
  `globalThis.trace = (id, fn) => fn()`
39
40
  ];
40
- function runCode(codes, workerData) {
41
+ function runCode(codes, workerData, host) {
41
42
  const time = (0, import_utils.getWatchdogTime)();
42
43
  const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join("\n");
43
44
  return new Promise((resolve, reject) => {
44
- const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData});
45
+ const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData: {...workerData, host}});
45
46
  const timerId = (0, import_utils.startWatchdogTimer)(() => {
46
47
  worker.terminate();
47
48
  reject(new Error(`SSR timed out after ${time}ms`));
@@ -29,9 +29,9 @@ __export(exports, {
29
29
  var import_sandbox_worker = __toModule(require("./sandbox-worker.cjs"));
30
30
  var import_sandbox_locker = __toModule(require("./sandbox-locker.cjs"));
31
31
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
32
- function runCode(codes, context) {
32
+ function runCode(codes, context, host) {
33
33
  if ((0, import_shared_utils.getFeatureFlags)().SSR_SANDBOX_WORKER) {
34
- return (0, import_sandbox_worker.default)(codes, context);
34
+ return (0, import_sandbox_worker.default)(codes, context, host);
35
35
  }
36
- return (0, import_sandbox_locker.default)(codes, context);
36
+ return (0, import_sandbox_locker.default)(codes, context, host);
37
37
  }
@@ -29,9 +29,9 @@ __export(exports, {
29
29
  var import_amd_utils = __toModule(require("./amd-utils.cjs"));
30
30
  var import_sandbox = __toModule(require("./sandbox.cjs"));
31
31
  var import_perf_hooks = __toModule(require("perf_hooks"));
32
- var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
32
+ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
33
33
  var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
34
- var SSR_FLAG = "process.env.SSR = true;";
34
+ var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
35
35
  var EMIT_WIRES = `globalThis.lwcRuntimeFlags = { ENABLE_WIRE_SYNC_EMIT: true };`;
36
36
  async function ssrElement({
37
37
  specifier,
@@ -52,10 +52,18 @@ async function ssrElement({
52
52
  }) : await (0, import_amd_utils.getBundle)(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams);
53
53
  const context = {
54
54
  props: templateProps,
55
+ url: runtimeParams.url,
55
56
  params: runtimeParams.params || {},
56
57
  query: runtimeParams.query || {},
57
- locale: runtimeParams.locale || runtimeEnvironment.defaultLocale
58
+ locale: runtimeParams.locale || runtimeEnvironment.i18n.defaultLocale,
59
+ basePath: runtimeParams.basePath || runtimeEnvironment.basePath
60
+ };
61
+ const environment = {
62
+ SSR: true,
63
+ ...(0, import_shared_utils.buildEnvironmentContext)(runtimeParams)
58
64
  };
65
+ const environmentCode = `process.env = ${JSON.stringify(environment)}`;
66
+ const host = runtimeParams.host;
59
67
  const startTime = import_perf_hooks.performance.now();
60
68
  return (0, import_instrumentation.getTracer)().trace({
61
69
  name: import_instrumentation.ViewSpan.ServerSideRender,
@@ -64,14 +72,14 @@ async function ssrElement({
64
72
  }
65
73
  }, async () => {
66
74
  const {result, props, markup, cache, error} = format === "amd" ? await (0, import_sandbox.default)([
67
- SSR_FLAG,
68
75
  EMIT_WIRES,
76
+ environmentCode,
69
77
  ...await (0, import_amd_utils.getCode)(runtimeEnvironment, serverData, version.replace(/\./g, "_"), bundleSpecifier, bundleRecord.includedModules, resourceRegistry),
70
78
  code
71
- ], context) : await (0, import_sandbox.default)([SSR_FLAG, EMIT_WIRES, code], context);
79
+ ], context, host) : await (0, import_sandbox.default)([EMIT_WIRES, environmentCode, code], context, host);
72
80
  const endTime = import_perf_hooks.performance.now();
73
81
  const timeDiff = endTime - startTime;
74
- import_shared_utils.logger.info(`[Server-side Rendering] ${specifier} in ${Math.round(timeDiff)} ms`);
82
+ import_diagnostics.logger.info(`[Server-side Rendering] ${specifier} in ${Math.round(timeDiff)} ms`);
75
83
  if (error)
76
84
  throw new Error(error);
77
85
  return {html: result, props, markup, cache};
@@ -1,17 +1,36 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
2
7
  var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
3
8
  var __export = (target, all) => {
4
9
  for (var name in all)
5
10
  __defProp(target, name, {get: all[name], enumerable: true});
6
11
  };
12
+ var __exportStar = (target, module2, desc) => {
13
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
14
+ for (let key of __getOwnPropNames(module2))
15
+ if (!__hasOwnProp.call(target, key) && key !== "default")
16
+ __defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
17
+ }
18
+ return target;
19
+ };
20
+ var __toModule = (module2) => {
21
+ return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
22
+ };
7
23
 
8
24
  // packages/@lwrjs/lwc-ssr/src/utils/utils.ts
9
25
  __markAsModule(exports);
10
26
  __export(exports, {
27
+ createFetchEndowment: () => createFetchEndowment,
28
+ createSsrErrorMessage: () => createSsrErrorMessage,
11
29
  getWatchdogTime: () => getWatchdogTime,
12
30
  startWatchdogTimer: () => startWatchdogTimer,
13
31
  stopWatchdogTimer: () => stopWatchdogTimer
14
32
  });
33
+ var import_node_fetch = __toModule(require("node-fetch"));
15
34
  var DEFAULT_SSR_TIMEOUT = 5e3;
16
35
  function getWatchdogTime() {
17
36
  const override = process.env.SSR_TIMEOUT;
@@ -23,3 +42,18 @@ function startWatchdogTimer(callback, time) {
23
42
  function stopWatchdogTimer(timerId) {
24
43
  clearTimeout(timerId);
25
44
  }
45
+ function createFetchEndowment(host) {
46
+ if (!host) {
47
+ return import_node_fetch.default;
48
+ }
49
+ return (url, init) => {
50
+ const urlStr = typeof url === "string" ? url : url.toString();
51
+ if (urlStr.startsWith("/")) {
52
+ return (0, import_node_fetch.default)(host + url, init);
53
+ }
54
+ return (0, import_node_fetch.default)(url, init);
55
+ };
56
+ }
57
+ function createSsrErrorMessage(specifier, e) {
58
+ return `Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: ${e.message || e}`;
59
+ }
@@ -27,9 +27,12 @@ __export(exports, {
27
27
  default: () => viewProvider_default
28
28
  });
29
29
  var import_base_view_provider = __toModule(require("@lwrjs/base-view-provider"));
30
+ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
31
+ var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
30
32
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
31
33
  var import_identity = __toModule(require("../identity.cjs"));
32
34
  var import_ssr_element = __toModule(require("../utils/ssr-element.cjs"));
35
+ var import_utils = __toModule(require("../utils/utils.cjs"));
33
36
  var LwcViewProvider = class extends import_base_view_provider.default {
34
37
  constructor(pluginConfig, providerConfig) {
35
38
  super();
@@ -42,13 +45,11 @@ var LwcViewProvider = class extends import_base_view_provider.default {
42
45
  async initialize() {
43
46
  return;
44
47
  }
45
- async getView(viewId, runtimeParams = {}) {
48
+ async getView(viewId) {
46
49
  const specifier = viewId.contentTemplate?.component;
47
50
  if (!specifier || !(0, import_shared_utils.isSpecifier)(specifier)) {
48
51
  return;
49
52
  }
50
- const {moduleBundler, resourceRegistry, runtimeEnvironment} = this;
51
- const {html: renderedView, props} = await (0, import_ssr_element.ssrElement)({specifier: `${import_identity.LWC_SSR_PREFIX}${viewId.id}/${specifier}`, props: {}}, moduleBundler, resourceRegistry, this.routes, {runtimeEnvironment, runtimeParams});
52
53
  return {
53
54
  name: specifier,
54
55
  slug: (0, import_shared_utils.slugify)(specifier),
@@ -56,10 +57,41 @@ var LwcViewProvider = class extends import_base_view_provider.default {
56
57
  originalSource: specifier,
57
58
  filePath: specifier,
58
59
  viewId,
59
- render: async () => ({
60
- renderedView,
61
- metadata: {serverData: props, customElements: [], assetReferences: []}
62
- })
60
+ render: async (runtimeParams) => {
61
+ const {moduleBundler, resourceRegistry, runtimeEnvironment} = this;
62
+ const debug = runtimeParams.query?.debug !== void 0;
63
+ const element = (0, import_shared_utils.moduleSpecifierToKebabCase)(specifier);
64
+ return (0, import_instrumentation.getTracer)().trace({
65
+ name: import_instrumentation.ViewSpan.RenderPage,
66
+ attributes: {specifier}
67
+ }, async () => {
68
+ try {
69
+ const {html, props} = await (0, import_ssr_element.ssrElement)({specifier: `${import_identity.LWC_SSR_PREFIX}${viewId.id}/${specifier}`, props: {}}, moduleBundler, resourceRegistry, this.routes, {
70
+ runtimeEnvironment: {...runtimeEnvironment, debug},
71
+ runtimeParams
72
+ });
73
+ return {
74
+ renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
75
+ metadata: {serverData: props, customElements: [], assetReferences: []}
76
+ };
77
+ } catch (e) {
78
+ if (debug || (0, import_shared_utils.getFeatureFlags)().SSR_WITH_CSR_FALLBACK) {
79
+ const message = (0, import_utils.createSsrErrorMessage)(specifier, e);
80
+ import_diagnostics.logger.warn(message, e.stack);
81
+ return {
82
+ renderedView: `<${element} ${import_shared_utils.HYDRATE_DIRECTIVE}="${import_shared_utils.HYDRATE_CLIENT_VALUE}"></${element}>`,
83
+ metadata: {
84
+ serverDebug: {message: debug ? message : void 0},
85
+ customElements: [],
86
+ assetReferences: []
87
+ }
88
+ };
89
+ } else {
90
+ throw e;
91
+ }
92
+ }
93
+ });
94
+ }
63
95
  };
64
96
  }
65
97
  };
@@ -24,25 +24,34 @@ var __toModule = (module2) => {
24
24
  // packages/@lwrjs/lwc-ssr/src/viewTransformer/index.ts
25
25
  __markAsModule(exports);
26
26
  __export(exports, {
27
+ createFetchEndowment: () => import_utils2.createFetchEndowment,
27
28
  default: () => lwcSsrViewTransformer
28
29
  });
30
+ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
31
+ var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
29
32
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
30
33
  var import_identity = __toModule(require("../identity.cjs"));
31
34
  var import_ssr_element = __toModule(require("../utils/ssr-element.cjs"));
35
+ var import_utils = __toModule(require("../utils/utils.cjs"));
36
+ var import_utils2 = __toModule(require("../utils/utils.cjs"));
32
37
  function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry}) {
33
38
  const routes = [...config.routes, ...config.errorRoutes];
34
39
  return {
35
40
  name: "ssr-lwc-transformer",
36
41
  async link(stringBuilder, viewContext, metadata) {
42
+ const {debug} = viewContext.runtimeEnvironment;
37
43
  if (!viewContext.view.bootstrap?.ssr) {
38
44
  return {};
39
45
  }
40
- import_shared_utils.logger.debug("[lwcSsrViewTransformer] link");
41
- import_shared_utils.logger.verbose("[lwcSsrViewTransformer] link input", stringBuilder);
46
+ import_diagnostics.logger.debug("[lwcSsrViewTransformer] link");
47
+ import_diagnostics.logger.verbose("[lwcSsrViewTransformer] link input", stringBuilder);
42
48
  if (!metadata.serverData) {
43
49
  metadata.serverData = {};
44
50
  }
45
- const {customElements, serverData} = metadata;
51
+ if (!metadata.serverDebug) {
52
+ metadata.serverDebug = {};
53
+ }
54
+ const {customElements, serverData, serverDebug} = metadata;
46
55
  const ssrModules = [];
47
56
  for (const [index, {tagName, location, props}] of customElements.entries()) {
48
57
  const isCsr = (0, import_shared_utils.isCsrIsland)(props);
@@ -50,7 +59,7 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
50
59
  const {startOffset, endOffset} = location;
51
60
  stringBuilder.overwrite(startOffset, endOffset, `<${tagName}></${tagName}>`);
52
61
  }
53
- if (!isCsr && location) {
62
+ if (!isCsr && !props?.["lwc:external"] && location) {
54
63
  const {startOffset, endOffset} = location;
55
64
  const moduleSpecifier = (0, import_shared_utils.kebabCaseToModuleSpecifier)(tagName);
56
65
  ssrModules.push({
@@ -59,46 +68,64 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
59
68
  endOffset,
60
69
  props,
61
70
  tagName,
62
- specifier: `${import_identity.LWC_SSR_PREFIX}${viewContext.view.id}/${moduleSpecifier}`
71
+ bootstrapSpecifier: `${import_identity.LWC_SSR_PREFIX}${viewContext.view.id}/${moduleSpecifier}`,
72
+ specifier: moduleSpecifier
63
73
  });
64
74
  }
65
75
  }
66
- let ssrLinks = "";
67
- let pageTtl;
68
- await Promise.all(ssrModules.map(({index, specifier, tagName, props: rawProps = {}, startOffset, endOffset}) => {
76
+ let ssrLinks = "", pageTtl, debugMessage;
77
+ await Promise.all(ssrModules.map(({
78
+ index,
79
+ bootstrapSpecifier,
80
+ specifier,
81
+ tagName,
82
+ props: rawProps = {},
83
+ startOffset,
84
+ endOffset
85
+ }) => {
69
86
  const hydrate = (0, import_shared_utils.isHydrateOnLoad)(rawProps);
70
87
  const passProps = {...rawProps};
71
88
  delete passProps[import_shared_utils.HYDRATE_DIRECTIVE];
72
- return (0, import_ssr_element.ssrElement)({specifier, props: passProps, serverData}, moduleBundler, resourceRegistry, routes, viewContext).then(({
73
- html,
74
- props = {},
75
- markup: {links = []} = {links: []},
76
- cache: {ttl} = {}
77
- }) => {
78
- pageTtl = (0, import_shared_utils.shortestTtl)(ttl, pageTtl);
79
- let propsAttr = "";
80
- if (hydrate) {
81
- const propsId = (0, import_identity.getPropsId)();
82
- propsAttr = ` ${import_identity.SSR_PROPS_ATTR}="${propsId}"`;
83
- serverData[propsId] = props;
84
- }
85
- const [, remain] = html.split(`<${tagName}`);
86
- html = [`<${tagName}`, propsAttr, remain].join("");
87
- links.forEach(({href, rel, as, fetchpriority}) => {
88
- const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
89
- ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>
89
+ return (0, import_instrumentation.getTracer)().trace({
90
+ name: import_instrumentation.ViewSpan.RenderIsland,
91
+ attributes: {specifier}
92
+ }, async () => {
93
+ return (0, import_ssr_element.ssrElement)({specifier: bootstrapSpecifier, props: passProps, serverData}, moduleBundler, resourceRegistry, routes, viewContext).then(({
94
+ html,
95
+ props = {},
96
+ markup: {links = []} = {links: []},
97
+ cache: {ttl} = {}
98
+ }) => {
99
+ pageTtl = (0, import_shared_utils.shortestTtl)(ttl, pageTtl);
100
+ let propsAttr = "";
101
+ if (hydrate) {
102
+ const propsId = (0, import_identity.getPropsId)();
103
+ propsAttr = ` ${import_identity.SSR_PROPS_ATTR}="${propsId}"`;
104
+ serverData[propsId] = props;
105
+ }
106
+ const [, remain] = html.split(`<${tagName}`);
107
+ html = [`<${tagName}`, propsAttr, remain].join("");
108
+ links.forEach(({href, rel, as, fetchpriority}) => {
109
+ const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
110
+ ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>
90
111
  `;
112
+ });
113
+ stringBuilder.overwrite(startOffset, endOffset, html);
114
+ }).catch((err) => {
115
+ if (debug || (0, import_shared_utils.getFeatureFlags)().SSR_WITH_CSR_FALLBACK) {
116
+ customElements[index].props === void 0 ? customElements[index].props = {
117
+ [import_shared_utils.HYDRATE_DIRECTIVE]: import_shared_utils.HYDRATE_CLIENT_VALUE
118
+ } : customElements[index].props[import_shared_utils.HYDRATE_DIRECTIVE] = import_shared_utils.HYDRATE_CLIENT_VALUE;
119
+ const errMessage = (0, import_utils.createSsrErrorMessage)(specifier, err);
120
+ import_diagnostics.logger.warn(errMessage, err.stack);
121
+ if (debug) {
122
+ debugMessage = errMessage;
123
+ serverDebug.message = debugMessage;
124
+ }
125
+ } else {
126
+ throw err;
127
+ }
91
128
  });
92
- stringBuilder.overwrite(startOffset, endOffset, html);
93
- }).catch((err) => {
94
- if ((0, import_shared_utils.getFeatureFlags)().SSR_WITH_CSR_FALLBACK) {
95
- customElements[index].props === void 0 ? customElements[index].props = {
96
- [import_shared_utils.HYDRATE_DIRECTIVE]: import_shared_utils.HYDRATE_CLIENT_VALUE
97
- } : customElements[index].props[import_shared_utils.HYDRATE_DIRECTIVE] = import_shared_utils.HYDRATE_CLIENT_VALUE;
98
- import_shared_utils.logger.warn(`Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: `, err.stack);
99
- } else {
100
- throw err;
101
- }
102
129
  });
103
130
  }));
104
131
  if (ssrLinks) {
@@ -106,10 +133,10 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
106
133
  if (headIndex >= 0) {
107
134
  stringBuilder.prependLeft(headIndex, ssrLinks);
108
135
  } else {
109
- import_shared_utils.logger.error("Adding links during server-side rendering failed. Could not find the </head> tag.");
136
+ import_diagnostics.logger.error("Adding links during server-side rendering failed. Could not find the </head> tag.");
110
137
  }
111
138
  }
112
- import_shared_utils.logger.verbose("lwcSsrViewTransformer response", stringBuilder);
139
+ import_diagnostics.logger.verbose("lwcSsrViewTransformer response", stringBuilder);
113
140
  return {cache: {ttl: pageTtl}};
114
141
  }
115
142
  };