@lwrjs/lwc-ssr 0.12.0-alpha.8 → 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.
Files changed (35) hide show
  1. package/README.md +14 -64
  2. package/build/cjs/dataViewTransformer/index.cjs +13 -3
  3. package/build/cjs/identity.cjs +8 -22
  4. package/build/cjs/moduleProvider/index.cjs +92 -83
  5. package/build/cjs/utils/amd-utils.cjs +40 -14
  6. package/build/cjs/utils/sandbox-vm.cjs +27 -13
  7. package/build/cjs/utils/sandbox.cjs +5 -10
  8. package/build/cjs/utils/{ssr-element.cjs → ssr-bootstrap.cjs} +30 -53
  9. package/build/cjs/utils/ssr-debug.cjs +88 -0
  10. package/build/cjs/utils/utils.cjs +77 -8
  11. package/build/cjs/viewProvider/index.cjs +27 -25
  12. package/build/cjs/viewTransformer/index.cjs +79 -77
  13. package/build/es/dataViewTransformer/index.js +15 -2
  14. package/build/es/identity.d.ts +2 -2
  15. package/build/es/identity.js +8 -6
  16. package/build/es/moduleProvider/index.js +106 -96
  17. package/build/es/utils/amd-utils.js +51 -22
  18. package/build/es/utils/sandbox-vm.d.ts +2 -2
  19. package/build/es/utils/sandbox-vm.js +33 -14
  20. package/build/es/utils/sandbox.d.ts +12 -13
  21. package/build/es/utils/sandbox.js +7 -13
  22. package/build/es/utils/{ssr-element.d.ts → ssr-bootstrap.d.ts} +10 -7
  23. package/build/es/utils/{ssr-element.js → ssr-bootstrap.js} +37 -59
  24. package/build/es/utils/ssr-debug.d.ts +4 -0
  25. package/build/es/utils/ssr-debug.js +64 -0
  26. package/build/es/utils/utils.d.ts +15 -5
  27. package/build/es/utils/utils.js +89 -11
  28. package/build/es/viewProvider/index.d.ts +3 -2
  29. package/build/es/viewProvider/index.js +34 -30
  30. package/build/es/viewTransformer/index.d.ts +8 -8
  31. package/build/es/viewTransformer/index.js +104 -95
  32. package/package.json +8 -7
  33. package/build/cjs/utils/sandbox-worker.cjs +0 -134
  34. package/build/es/utils/sandbox-worker.d.ts +0 -17
  35. package/build/es/utils/sandbox-worker.js +0 -132
package/README.md CHANGED
@@ -4,12 +4,12 @@
4
4
  - [What is SSR?](#what-is-ssr)
5
5
  - [Why use SSR?](#why-use-ssr)
6
6
  - [Using SSR with LWR](#using-ssr-with-lwr)
7
- - [Add the SSR package dependency](#add-the-ssr-package-dependency)
8
7
  - [Turn on SSR](#turn-on-ssr)
9
8
  - [Building SSR pages](#building-ssr-pages)
10
9
  - [SSR detection](#ssr-detection)
11
10
  - [Loading data during SSR](#loading-data-during-ssr)
12
11
  - [Caching](#caching)
12
+ - [Timeouts](#timeouts)
13
13
  - [Islands](#islands)
14
14
  - [Client hydration](#client-hydration)
15
15
  - [Skip SSR](#skip-ssr)
@@ -21,7 +21,7 @@
21
21
  - [Slots](#slots)
22
22
  - [Debugging](#debugging)
23
23
  - [Debug logging](#debug-logging)
24
- - [Inspect bundles](#inspect-bundles)
24
+ - [Local dev](#local-dev)
25
25
  - [Diagrams](#diagrams)
26
26
  - [Sequence](#sequence)
27
27
 
@@ -46,19 +46,6 @@ That said, SSR is best used for apps where time-to-content is important, such as
46
46
 
47
47
  Learn how to use SSR in LWR apps.
48
48
 
49
- ### Add the SSR package dependency
50
-
51
- Add SSR capabilities to an LWR app by including `@lwrjs/lwc-ssr` in its _package.json_.
52
-
53
- ```json
54
- // my-app/package.json
55
- {
56
- "dependencies": {
57
- "@lwrjs/lwc-ssr": "latest"
58
- }
59
- }
60
- ```
61
-
62
49
  ### Turn on SSR
63
50
 
64
51
  SSR is activated on a per-route basis by changing `bootstrap.ssr` to `true`.
@@ -232,7 +219,7 @@ Notes:
232
219
 
233
220
  - The `getServerData()` hook can choose to merge the properties from `SsrRequestContext.props` into its return object, or it can ignore/discard them.
234
221
  - The author of `getServerData()` is responsible for validating the `params` and `query` from `SsrRequestContext` before using them.
235
- - The **same** `props` returned by `getServerData()` are passed to the component during server rendering **and** client hydration.
222
+ - The **same** `props` returned by `getServerData()` are passed to the component during server rendering **and** [client hydration](#client-hydration).
236
223
 
237
224
  ### Caching
238
225
 
@@ -245,6 +232,15 @@ There are two other ways to set a TTL on a page document:
245
232
 
246
233
  LWR will use the shortest TTL value from **all** sources to set the `max-age` of the `Cache-control` header on the page.
247
234
 
235
+ ### Timeouts
236
+
237
+ By default, LWR will timeout and return a 500 error if SSR takes longer than 5 seconds. This includes [loading data](#loading-data-during-ssr). The timeout length (in milliseconds) can be overridden by setting the `SSR_TIMEOUT` environment variable before running the app.
238
+
239
+ ```bash
240
+ # set the timeout to 10 seconds
241
+ SSR_TIMEOUT=10000 yarn start
242
+ ```
243
+
248
244
  ## Islands
249
245
 
250
246
  [Islands of interactivity](https://jasonformat.com/islands-architecture/) can be created using the `lwr:hydrate` directive. LWR supports [hydrated](#client-hydration) and [CSR](#skip-ssr) islands.
@@ -283,15 +279,6 @@ Root components can skip SSR by setting the `lwr:hydrate` directive to `client-o
283
279
 
284
280
  Root components which opt-out of SSR will be fully rendered on the client using the [LWC `createElement()` API](https://www.npmjs.com/package/@lwc/engine-dom).
285
281
 
286
- ### Timeouts
287
-
288
- By default, LWR will timeout and return a 500 error if SSR takes longer than 5 seconds. This includes [loading data](#loading-data-during-ssr). The timeout length (in milliseconds) can be overridden by setting the `SSR_TIMEOUT` environment variable before running the app.
289
-
290
- ```bash
291
- # set the timeout to 10 seconds
292
- SSR_TIMEOUT=10000 yarn start
293
- ```
294
-
295
282
  ## Routing
296
283
 
297
284
  LWR provides a Server Router, which is similar to the [Client Router](../router/README.md). The Server Router is fully compatible with SSRed pages, including [islands](#islands). It:
@@ -406,36 +393,6 @@ The LWC SSR process runs in a single synchronous pass. So any asynchronous code
406
393
 
407
394
  Components rendered in synthetic shadow or light DOM can rely on globally defined CSS, but [native shadow DOM blocks global styles](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM#styling_the_shadow_dom) from being applied. Therefore SSRed components must use light DOM, or all of its CSS must be self-contained for native shadow compatibility.
408
395
 
409
- If a page renders both SSRed and CSRed root components in shadow DOM, then [mixed shadow mode](https://developer.salesforce.com/docs/platform/lwc/guide/create-mixed-shadow.html) must be enabled for the route:
410
-
411
- ```html
412
- <!-- my-app/src/content/home.html -->
413
-
414
- <!-- SSRed and hydrated (native shadow) -->
415
- <my-info lwr:hydrate="load"></my-info>
416
-
417
- <!-- CSRed (synthetic shadow) -->
418
- <my-map lwr:hydrate="client-only"></my-map>
419
- ```
420
-
421
- ```json
422
- // my-app/lwr.config.json
423
- {
424
- "routes": [
425
- {
426
- "id": "home",
427
- "path": "/",
428
- "contentTemplate": "$contentDir/home.html",
429
- "bootstrap": {
430
- "ssr": true,
431
- "mixedMode": true,
432
- "syntheticShadow": true
433
- }
434
- }
435
- ]
436
- }
437
- ```
438
-
439
396
  ### Slots
440
397
 
441
398
  Root components may **not** contain [slots](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.create_components_slots), regardless of whether the component is SSRed or CSRed.
@@ -450,16 +407,9 @@ See fine-grained logging with the `LOG_LEVEL` flag:
450
407
  LOG_LEVEL=debug MODE=prod-compat yarn start # start up the LWR server, in any mode
451
408
  ```
452
409
 
453
- ### Inspect bundles
454
-
455
- When SSR fails due to a [portability](#portability), it can be difficult to figure out which component is causing the issue. The broken component can be found by inspecting the module bundle for the page:
456
-
457
- 1. Go to the LWR config for the app (ie: _lwr.config.json_), and turn the [`ssr` flag](#turn-on-ssr) on the broken route **off**.
458
- 2. Start the LWR app and load the route in the browser.
459
- 3. Inspect the page's module bundles for the problematic code. Module bundles are served from _/1/bundle/..._.
460
- 4. When the problematic code is found, scroll up to find the component to which it belongs.
410
+ ### Local dev
461
411
 
462
- 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
+ Coming soon...
463
413
 
464
414
  ## Diagrams
465
415
 
@@ -30,7 +30,7 @@ __export(exports, {
30
30
  var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
31
31
  var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
32
32
  var import_identity = __toModule(require("../identity.cjs"));
33
- var import_ssr_element = __toModule(require("../utils/ssr-element.cjs"));
33
+ var import_ssr_bootstrap = __toModule(require("../utils/ssr-bootstrap.cjs"));
34
34
  var import_utils = __toModule(require("../utils/utils.cjs"));
35
35
  var NAME = "preload-data-transformer";
36
36
  function preloadDataViewTransformer(_options, {config, moduleBundler, resourceRegistry}) {
@@ -43,12 +43,22 @@ function preloadDataViewTransformer(_options, {config, moduleBundler, resourceRe
43
43
  return {};
44
44
  }
45
45
  import_diagnostics.logger.debug({label: NAME, message: `Preload data for root component "${rootComponent}"`});
46
- const {props = {}, cache: {ttl} = {ttl: void 0}} = await (0, import_instrumentation.getTracer)().trace({
46
+ const {results = {}, errors} = await (0, import_instrumentation.getTracer)().trace({
47
47
  name: import_instrumentation.ViewSpan.PreloadData,
48
48
  attributes: {rootComponent}
49
49
  }, async () => {
50
- return await (0, import_ssr_element.runServerBootstrap)({specifier: `${import_identity.LWC_SSR_PREFIX}${viewContext.view.id}/${rootComponent}`, props: {}}, moduleBundler, resourceRegistry, routes, viewContext);
50
+ return await (0, import_ssr_bootstrap.runServerBootstrap)({specifier: `${import_identity.LWC_SSR_PREFIX}${viewContext.view.id}/${rootComponent}`, props: {}}, moduleBundler, resourceRegistry, routes, viewContext);
51
51
  });
52
+ if (errors) {
53
+ for (const err of Object.entries(errors)) {
54
+ import_diagnostics.logger.warn({
55
+ label: "preloadDataViewTransformer",
56
+ message: `Unexpected error during preload data: ${err[0]}`
57
+ }, err[1]);
58
+ }
59
+ return {};
60
+ }
61
+ const {props, cache: {ttl} = {ttl: void 0}} = results[rootComponent];
52
62
  import_diagnostics.logger.verbose({label: NAME, message: "response", additionalInfo: props});
53
63
  metadata.serverData = metadata.serverData || {};
54
64
  Object.assign(metadata.serverData, props);
@@ -1,25 +1,9 @@
1
- var __create = Object.create;
2
1
  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;
7
2
  var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
8
3
  var __export = (target, all) => {
9
4
  for (var name in all)
10
5
  __defProp(target, name, {get: all[name], enumerable: true});
11
6
  };
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
- };
23
7
 
24
8
  // packages/@lwrjs/lwc-ssr/src/identity.ts
25
9
  __markAsModule(exports);
@@ -28,23 +12,25 @@ __export(exports, {
28
12
  SSR_PROPS_ATTR: () => SSR_PROPS_ATTR,
29
13
  getPropsId: () => getPropsId,
30
14
  getSsrServices: () => getSsrServices,
31
- parseSpecifier: () => parseSpecifier
15
+ parseBootstrapSpecifier: () => parseBootstrapSpecifier
32
16
  });
33
- var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
34
17
  var LWC_SSR_PREFIX = "@lwrjs/lwc-ssr/";
35
18
  var SSR_PROPS_ATTR = "data-lwr-props-id";
36
19
  function getPropsId() {
37
20
  return `lwcprops${Math.floor(Math.random() * 65536).toString(16)}`;
38
21
  }
39
- function parseSpecifier(specifier, routes = []) {
22
+ function parseBootstrapSpecifier(specifier, routes = []) {
40
23
  if (specifier.startsWith(LWC_SSR_PREFIX)) {
41
24
  const parts = specifier.replace(LWC_SSR_PREFIX, "");
42
25
  const slash = parts.indexOf("/");
43
26
  if (slash) {
44
27
  const routeId = parts.substring(0, slash);
45
- const rootSpecifier = parts.substring(slash + 1);
46
- if ((0, import_shared_utils.isSpecifier)(rootSpecifier)) {
47
- return {rootSpecifier, route: routes.find((r) => r.id === routeId)};
28
+ const rootSpecifierStr = parts.substring(slash + 1);
29
+ if (rootSpecifierStr) {
30
+ return {
31
+ rootSpecifiers: rootSpecifierStr.split(","),
32
+ route: routes.find((r) => r.id === routeId)
33
+ };
48
34
  }
49
35
  }
50
36
  }
@@ -29,102 +29,111 @@ __export(exports, {
29
29
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
30
30
  var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
31
31
  var import_identity = __toModule(require("../identity.cjs"));
32
- function createServerBootstrapModule(rootSpecifier, isSSR, services) {
33
- let serviceImports = "";
34
- let serviceCalls = "";
35
- services.forEach((service) => {
36
- const importName = (0, import_shared_utils.stringToVariableName)(`service_${service}`);
37
- serviceImports += `
38
- import ${importName} from '${service}';`;
39
- serviceCalls += `
32
+ function createDataCall(rootSpecifier, classImportName) {
33
+ return `
40
34
 
41
- globalThis.trace({
42
- name: '${import_instrumentation.ViewSpan.BootstrapService}',
43
- attributes: {
44
- specifier: '${rootSpecifier}',
45
- serviceSpecifier: '${service}',
35
+ results['${rootSpecifier}'] = { props: context.props['${rootSpecifier}'] }; // props from HTML attributes
36
+ if (${classImportName}.getServerData) {
37
+ await globalThis.trace({
38
+ name: '${import_instrumentation.ViewSpan.GetServerData}',
39
+ attributes: { specifier: '${rootSpecifier}' }
40
+ }, async() => {
41
+ try {
42
+ const data${classImportName} = await ${classImportName}.getServerData({ ...context, props: results['${rootSpecifier}'].props });
43
+ Object.assign(serverData, data${classImportName}.props); // add props to server data
44
+ Object.assign(results['${rootSpecifier}'], { props: data${classImportName}.props, markup: data${classImportName}.markup, cache: data${classImportName}.cache });
45
+ } catch(e) {
46
+ // add the root component specifier to the error message
47
+ errors['${rootSpecifier}'] = 'Error in "getServerData" for "${rootSpecifier}": ' + stringifyError(e);
46
48
  }
49
+ });
50
+ }`;
51
+ }
52
+ function createServiceCall(serviceSpecifier, importName) {
53
+ return `
54
+
55
+ globalThis.trace({
56
+ name: '${import_instrumentation.ViewSpan.BootstrapService}',
57
+ attributes: { serviceSpecifier: '${serviceSpecifier}' }
58
+ }, () => {
59
+ try {
60
+ ${importName}({ serverData });
61
+ } catch(e) {
62
+ // add the service specifier to the error message
63
+ errors['${serviceSpecifier}'] = 'An SSR error occurred in bootstrap service "${serviceSpecifier}": ' + stringifyError(e);
64
+ }
65
+ });`;
66
+ }
67
+ function createSsrCall(rootSpecifier, ctorImportName) {
68
+ return `
69
+
70
+ if (!errors['${rootSpecifier}']) { // skip SSR if getServerData failed
71
+ const existingTaskCount${ctorImportName} = process.getActiveResourcesInfo ? process.getActiveResourcesInfo().length : 0;
72
+ const html${ctorImportName} = globalThis.trace({
73
+ name: '${import_instrumentation.ViewSpan.RenderComponent}',
74
+ attributes: { specifier: '${rootSpecifier}' }
47
75
  }, () => {
48
76
  try {
49
- ${importName}({ serverData });
77
+ return renderComponent('${(0, import_shared_utils.moduleSpecifierToKebabCase)(rootSpecifier)}', ${ctorImportName}, results['${rootSpecifier}'].props || {});
50
78
  } catch(e) {
79
+ // add the LWC rendering stack to the error message
51
80
  const message = e.message || stringifyError(e);
52
- // we need to re-throw with the service specifier in the error message
53
- throw new Error('An SSR error occurred in bootstrap service "${service}": ' + message);
81
+ const error = e.wcStack
82
+ ? 'An error occurred during server-side rendering for component stack: ' + e.wcStack + '. Error was: ' + message
83
+ : 'An error occurred during server-side rendering: ' + message;
84
+ errors['${rootSpecifier}'] = error;
54
85
  }
55
- });`;
56
- });
57
- const ssrCall = isSSR ? `
58
- // 2. render component
59
- result = globalThis.trace({
60
- name: '${import_instrumentation.ViewSpan.RenderComponent}',
61
- attributes: {
62
- specifier: '${rootSpecifier}'
86
+ });
87
+ const currentTaskCount${ctorImportName} = process.getActiveResourcesInfo ? process.getActiveResourcesInfo().length : 0;
88
+ if (currentTaskCount${ctorImportName} - existingTaskCount${ctorImportName} > 0) {
89
+ console.warn('[warn] async tasks encountered while server rendering "${rootSpecifier}"');
63
90
  }
64
- }, () => renderComponent('${(0, import_shared_utils.moduleSpecifierToKebabCase)(rootSpecifier)}', Ctor, props || {}));` : "";
91
+ Object.assign(results['${rootSpecifier}'], { html: html${ctorImportName} });
92
+ }`;
93
+ }
94
+ function createServerBootstrapModule(rootSpecifiers, isSSR, services) {
95
+ let rootImports = "", dataCalls = "", ssrCalls = "";
96
+ rootSpecifiers.forEach((root) => {
97
+ const ctorImportName = (0, import_shared_utils.stringToVariableName)(`Ctor_${root}`);
98
+ const classImportName = (0, import_shared_utils.stringToVariableName)(`root_${root}`);
99
+ rootImports += `
100
+ import ${ctorImportName}, * as ${classImportName} from '${root}';`;
101
+ dataCalls += createDataCall(root, classImportName);
102
+ ssrCalls += isSSR ? createSsrCall(root, ctorImportName) : "";
103
+ });
104
+ let serviceImports = "", serviceCalls = "";
105
+ services.forEach((serviceSpecifier) => {
106
+ const importName = (0, import_shared_utils.stringToVariableName)(`service_${serviceSpecifier}`);
107
+ serviceImports += `
108
+ import ${importName} from '${serviceSpecifier}';`;
109
+ serviceCalls += createServiceCall(serviceSpecifier, importName);
110
+ });
65
111
  return `
66
- import { renderComponent } from '@lwc/engine-server';
67
- import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
112
+ import { renderComponent } from '@lwc/engine-server';${rootImports}${serviceImports}
68
113
 
69
114
  (async () => {
70
- let result, props, markup, cache, serverData = globalThis.LWR?.serverData || {}, existingTaskCount;
71
- // remove the LWR global properties before any customer code is run
115
+ const results = {}; // { rootSpecifier: { html, props, markup, cache } }
116
+ const errors = {}; // { rootSpecifier: error string }
117
+ const serverData = globalThis.LWR?.serverData || {}; // data from view providers
118
+ const context = globalThis.getContext(); // SsrRequestContext
119
+
120
+ // 1. cleanup the LWR global properties before any customer code is run
72
121
  if (globalThis.LWR?.define) {
73
122
  // AMD: support dynamic imports in getServerData
74
- globalThis.LWR = Object.freeze({ define: globalThis.LWR.define });
123
+ globalThis.LWR = Object.freeze({ define: globalThis.LWR.define, env: globalThis.LWR.env });
75
124
  } else {
76
- delete globalThis.LWR; // ESM
77
- }
78
-
79
- try {
80
- // 1. setup page data
81
- const context = globalThis.getContext();
82
- props = context.props;
83
- if (rootComponent.getServerData) {
84
- const data = await globalThis.trace({
85
- name: '${import_instrumentation.ViewSpan.GetServerData}',
86
- attributes: {
87
- specifier: '${rootSpecifier}'
88
- }
89
- }, async() => {
90
- try {
91
- return await rootComponent.getServerData(context)
92
- } catch(e) {
93
- const message = e.message || stringifyError(e);
94
- // we need to re-throw with rootSpecifier in the error message
95
- throw new Error('Error in "getServerData" for "${rootSpecifier}": ' + message);
96
- }
97
- });
98
- props = data.props; // overwrite public props
99
- Object.assign(serverData, data.props); // add props to server data
100
- markup = data.markup;
101
- cache = data.cache;
102
- }${serviceCalls}
103
-
104
- existingTaskCount = process.getActiveResourcesInfo
105
- ? process.getActiveResourcesInfo().length
106
- : 0;${ssrCall}
107
- } catch(e) {
108
- const message = e.message || stringifyError(e);
109
-
110
- // add the LWC rendering stack
111
- const error = e.wcStack ?
112
- 'An error occurred during server-side rendering for component stack: ' + e.wcStack + '. Error was: ' + message :
113
- 'An error occurred during server-side rendering: ' + message;
114
-
115
- // (3) relay error
116
- globalThis.resolver({ error });
117
- }
118
-
119
- const currentTaskCount = process.getActiveResourcesInfo
120
- ? process.getActiveResourcesInfo().length
121
- : 0;
122
- if (currentTaskCount - existingTaskCount > 0) {
123
- console.warn('[warn] async tasks encountered while server rendering "${rootSpecifier}"');
125
+ // ESM
126
+ globalThis.LWR = Object.freeze({ env: globalThis.LWR.env });
124
127
  }
125
128
 
126
- // 3. relay successful results
127
- globalThis.resolver({ result, props, markup, cache });
129
+ // 2. pre-fetch data
130
+ ${dataCalls}
131
+ // 3. execute each SSR bootstrap service
132
+ ${serviceCalls}
133
+ // 4. render components
134
+ ${ssrCalls}
135
+ // 5. relay results
136
+ globalThis.resolver({ results, errors });
128
137
  })()`;
129
138
  }
130
139
  var ServerModuleProvider = class {
@@ -134,7 +143,7 @@ var ServerModuleProvider = class {
134
143
  this.routes = [...config.routes, ...config.errorRoutes];
135
144
  }
136
145
  async getModuleEntry({specifier}) {
137
- if ((0, import_identity.parseSpecifier)(specifier)) {
146
+ if ((0, import_identity.parseBootstrapSpecifier)(specifier)) {
138
147
  const virtualId = `<virtual>/${specifier}`;
139
148
  return {
140
149
  id: `${virtualId}|${this.version}`,
@@ -150,8 +159,8 @@ var ServerModuleProvider = class {
150
159
  if (!moduleEntry) {
151
160
  return;
152
161
  }
153
- const {route, rootSpecifier} = (0, import_identity.parseSpecifier)(specifier, this.routes);
154
- const originalSource = createServerBootstrapModule(rootSpecifier, !!route?.bootstrap.ssr, (0, import_identity.getSsrServices)(route));
162
+ const {route, rootSpecifiers} = (0, import_identity.parseBootstrapSpecifier)(specifier, this.routes);
163
+ const originalSource = createServerBootstrapModule(rootSpecifiers, !!route?.bootstrap.ssr, (0, import_identity.getSsrServices)(route));
155
164
  return {
156
165
  id: moduleEntry.id,
157
166
  namespace,
@@ -29,6 +29,8 @@ __export(exports, {
29
29
  });
30
30
  var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
31
31
  var import_identity = __toModule(require("../identity.cjs"));
32
+ var import_fs_extra = __toModule(require("fs-extra"));
33
+ var import_url = __toModule(require("url"));
32
34
  var LWC_SPECIFIERS = {csr: "lwc", ssr: "@lwc/engine-server"};
33
35
  async function readableToString(readable) {
34
36
  let result = "";
@@ -82,17 +84,19 @@ async function getCode(runtimeEnvironment, serverData, lwrVersion, bundleSpecifi
82
84
  const loaderShimSource2 = await getLoaderShim(resourceRegistry, runtimeEnvironment);
83
85
  const lwrConfigString = JSON.stringify(getLwrConfig(bundleSpecifier, lwrVersion, serverData));
84
86
  const lwcSpecifier = includedModules.find((m) => m.startsWith(`${LWC_SPECIFIERS.ssr}/v`));
87
+ const info = (0, import_identity.parseBootstrapSpecifier)(bundleSpecifier);
88
+ const rootCmpSpecifiers = info ? info.rootSpecifiers.join(",") : bundleSpecifier;
85
89
  return [
86
90
  GLOBALTHIS_LWR,
87
91
  `Object.assign(globalThis.LWR, ${lwrConfigString});`,
88
- `Object.assign(globalThis.LWR, { onError: (err) => globalThis.resolver({ error: err.message })});`,
92
+ `Object.assign(globalThis.LWR, { onError: (err) => globalThis.resolver({ errors: { '${rootCmpSpecifiers}': err.message}})});`,
89
93
  loaderShimSource2 ? loaderShimSource2 : "",
90
94
  lwcSpecifier ? aliasLwcEngine(lwcSpecifier, LWC_SPECIFIERS) : ""
91
95
  ];
92
96
  }
93
97
  async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
94
98
  if ((0, import_shared_utils.getFeatureFlags)().SSR_STATIC_BUNDLES) {
95
- return buildBundle(specifier, moduleBundler, routes, {...runtimeEnvironment, debug: false}, runtimeParams);
99
+ return buildBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams);
96
100
  }
97
101
  return bundle(specifier, moduleBundler, {
98
102
  ...runtimeEnvironment,
@@ -100,8 +104,28 @@ async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, r
100
104
  }, runtimeParams, {
101
105
  appendExcludes: false,
102
106
  exclude: ["lwc"]
107
+ }).then(async (bundle2) => {
108
+ bundle2.code = await appendFileBasedExternals(bundle2.code, bundle2.bundleRecord.dynamicImports, bundle2.bundleRecord.imports, new Set(), new Set());
109
+ return bundle2;
103
110
  });
104
111
  }
112
+ async function appendFileBasedExternals(bundleCode, dynamicImports = [], imports = [], visitedBundles, visitedExternals) {
113
+ for (const {specifier, external, externalSrc} of [...imports, ...dynamicImports]) {
114
+ if (!visitedBundles.has(specifier) && (!external || !externalSrc || !visitedExternals.has(externalSrc))) {
115
+ visitedBundles.add(specifier);
116
+ if (external && externalSrc) {
117
+ visitedExternals.add(externalSrc);
118
+ if (externalSrc && externalSrc.startsWith(import_shared_utils.PROTOCOL_FILE)) {
119
+ const path = (0, import_url.fileURLToPath)(externalSrc);
120
+ const externalBundle = import_fs_extra.default.readFileSync(path, {encoding: "utf-8"}).toString();
121
+ bundleCode = bundleCode.concat(`
122
+ ${externalBundle}`);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ return bundleCode;
128
+ }
105
129
  async function bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams, bundleConfigOverrides) {
106
130
  return await moduleBundler.getModuleBundle({specifier}, runtimeEnvironment, runtimeParams, bundleConfigOverrides);
107
131
  }
@@ -126,8 +150,7 @@ async function bundleImports(bundleCode, dynamicImports = [], imports = [], visi
126
150
  function getBundledCode(runtimeEnvironment, specifier, version, code) {
127
151
  let bundledCode;
128
152
  if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
129
- const versionedSpecifier = (0, import_shared_utils.getSpecifier)({specifier, version});
130
- const aliasCode = (0, import_shared_utils.createAmdAlias)(versionedSpecifier, specifier);
153
+ const aliasCode = (0, import_shared_utils.createAmdAlias)((0, import_shared_utils.getSpecifier)({specifier, version}), specifier);
131
154
  bundledCode = [code, aliasCode].filter(Boolean).join("");
132
155
  } else {
133
156
  bundledCode = code;
@@ -139,18 +162,21 @@ async function getBundleWithImports(specifier, moduleBundler, runtimeEnvironment
139
162
  return await bundleImports(code, bundleRecord.dynamicImports, bundleRecord.imports, new Set(["lwc", specifier]), moduleBundler, runtimeEnvironment, runtimeParams);
140
163
  }
141
164
  async function buildBundle(ssrSpecifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
142
- const {rootSpecifier, route} = (0, import_identity.parseSpecifier)(ssrSpecifier, routes);
165
+ const {rootSpecifiers, route} = (0, import_identity.parseBootstrapSpecifier)(ssrSpecifier, routes);
143
166
  const ssrServices = (0, import_identity.getSsrServices)(route);
144
167
  const serviceBundles = await Promise.all(ssrServices.map((s) => getBundleWithImports(s, moduleBundler, runtimeEnvironment, runtimeParams)));
145
168
  const serviceCode = serviceBundles.reduce((all, sc) => all + sc, "");
146
- let rootCode = await getBundleWithImports(rootSpecifier, moduleBundler, runtimeEnvironment, runtimeParams);
147
- if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
148
- const aliasSpecifier = (0, import_shared_utils.getSpecifier)({
149
- specifier: rootSpecifier,
150
- version: "version-not-provided"
151
- });
152
- const aliasCode = (0, import_shared_utils.createAmdAlias)(aliasSpecifier, rootSpecifier);
153
- rootCode = [aliasCode, rootCode].join("");
169
+ let rootCode = "";
170
+ for (const rootSpecifier of rootSpecifiers) {
171
+ rootCode += await getBundleWithImports(rootSpecifier, moduleBundler, runtimeEnvironment, runtimeParams);
172
+ if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
173
+ const aliasSpecifier = (0, import_shared_utils.getSpecifier)({
174
+ specifier: rootSpecifier,
175
+ version: "version-not-provided"
176
+ });
177
+ const aliasCode = (0, import_shared_utils.createAmdAlias)(aliasSpecifier, rootSpecifier);
178
+ rootCode = [aliasCode, rootCode].join("");
179
+ }
154
180
  }
155
181
  const {code: lwcEngineCode, version: lwcVersion} = await bundle(LWC_SPECIFIERS.ssr, moduleBundler, runtimeEnvironment, runtimeParams);
156
182
  const {
@@ -159,7 +185,7 @@ async function buildBundle(ssrSpecifier, moduleBundler, routes, runtimeEnvironme
159
185
  version: lwrVersion
160
186
  } = await bundle(ssrSpecifier, moduleBundler, runtimeEnvironment, runtimeParams, {
161
187
  appendExcludes: true,
162
- exclude: [LWC_SPECIFIERS.ssr, rootSpecifier, ...ssrServices]
188
+ exclude: [LWC_SPECIFIERS.ssr, ...rootSpecifiers, ...ssrServices]
163
189
  });
164
190
  const code = serviceCode + rootCode + lwcEngineCode + ssrCode;
165
191
  bundleRecord.includedModules.push(`${LWC_SPECIFIERS.ssr}/v/${(0, import_shared_utils.normalizeVersionToUri)(lwcVersion)}`);
@@ -26,14 +26,13 @@ __markAsModule(exports);
26
26
  __export(exports, {
27
27
  default: () => runCode
28
28
  });
29
- var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
29
+ var import_node_vm = __toModule(require("node:vm"));
30
30
  var import_crypto = __toModule(require("crypto"));
31
31
  var import_url = __toModule(require("url"));
32
- var import_utils = __toModule(require("./utils.cjs"));
33
32
  var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
34
- var import_node_vm = __toModule(require("node:vm"));
35
- function runCode(codes, context, host) {
36
- import_diagnostics.logger.info("running vm sandbox");
33
+ var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
34
+ var import_utils = __toModule(require("./utils.cjs"));
35
+ function runCode(codes, context, options) {
37
36
  return new Promise((resolve, reject) => {
38
37
  let resolver;
39
38
  const p = new Promise((r) => resolver = r);
@@ -42,26 +41,39 @@ function runCode(codes, context, host) {
42
41
  }
43
42
  const tracer = (0, import_instrumentation.getTracer)();
44
43
  const trace = tracer.trace.bind(tracer);
44
+ const {host, requestDepth} = options;
45
+ const fetchEndowment = (0, import_utils.createFetchEndowment)(trace, host, requestDepth);
46
+ const fetchController = new import_utils.FetchController(fetchEndowment);
45
47
  const vmContext = {
46
- AbortController,
47
- crypto: import_crypto.webcrypto,
48
48
  getContext,
49
- trace,
50
- fetch: (0, import_utils.createFetchEndowment)(host),
51
- stringifyError: import_diagnostics.stringifyError,
52
49
  resolver,
50
+ stringifyError: import_diagnostics.stringifyError,
51
+ trace,
52
+ AbortController,
53
+ AbortSignal,
54
+ atob,
55
+ btoa,
56
+ console,
57
+ crypto: import_crypto.webcrypto,
58
+ Headers,
59
+ Intl,
60
+ fetch: fetchController.controlledFetch,
61
+ Request,
62
+ Response,
53
63
  URL: import_url.URL,
54
64
  URLSearchParams: import_url.URLSearchParams,
55
65
  process,
56
66
  setTimeout,
57
67
  clearTimeout,
58
68
  setInterval,
59
- clearInterval
69
+ clearInterval,
70
+ setImmediate,
71
+ clearImmediate
60
72
  };
61
73
  import_node_vm.default.createContext(vmContext);
62
74
  const time = (0, import_utils.getWatchdogTime)();
63
75
  const timerId = (0, import_utils.startWatchdogTimer)(() => {
64
- reject(new Error(`SSR timed out after ${time}ms`));
76
+ reject((0, import_diagnostics.createSingleDiagnosticError)({description: import_diagnostics.descriptions.UNRESOLVABLE.SSR_TIMEOUT(options.bundleSpecifier, time)}, import_diagnostics.LwrUnresolvableError));
65
77
  }, time);
66
78
  try {
67
79
  import_node_vm.default.runInContext(codes.join("\n"), vmContext);
@@ -70,12 +82,14 @@ function runCode(codes, context, host) {
70
82
  resolve(r);
71
83
  }).catch((e) => {
72
84
  import_diagnostics.logger.error(e);
73
- (0, import_utils.stopWatchdogTimer)(timerId);
74
85
  reject(e);
86
+ }).finally(() => {
87
+ fetchController.activateKillSwitch();
75
88
  });
76
89
  } catch (e) {
77
90
  import_diagnostics.logger.error(e);
78
91
  (0, import_utils.stopWatchdogTimer)(timerId);
92
+ fetchController.activateKillSwitch();
79
93
  reject(e);
80
94
  }
81
95
  });
@@ -26,16 +26,11 @@ __markAsModule(exports);
26
26
  __export(exports, {
27
27
  default: () => runCode
28
28
  });
29
- var import_sandbox_worker = __toModule(require("./sandbox-worker.cjs"));
30
29
  var import_sandbox_vm = __toModule(require("./sandbox-vm.cjs"));
31
- var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
32
- var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
33
- function runCode(codes, context, bundleSpecifier, host) {
34
- if (process.env.SSR_GENERATE_CODE) {
35
- (0, import_sandbox_worker.generateWorkerCode)(codes, context, bundleSpecifier, host).catch((err) => import_diagnostics.logger.error(err));
30
+ var import_ssr_debug = __toModule(require("./ssr-debug.cjs"));
31
+ async function runCode(codes, context, options) {
32
+ if (process.env.SSR_DEBUG) {
33
+ return (0, import_ssr_debug.default)(codes, context, options);
36
34
  }
37
- if ((0, import_shared_utils.getFeatureFlags)().SSR_SANDBOX_VM) {
38
- return (0, import_sandbox_vm.default)(codes, context, host);
39
- }
40
- return (0, import_sandbox_worker.default)(codes, context, host);
35
+ return (0, import_sandbox_vm.default)(codes, context, options);
41
36
  }