@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.
- package/README.md +14 -64
- package/build/cjs/dataViewTransformer/index.cjs +13 -3
- package/build/cjs/identity.cjs +8 -22
- package/build/cjs/moduleProvider/index.cjs +92 -83
- package/build/cjs/utils/amd-utils.cjs +40 -14
- package/build/cjs/utils/sandbox-vm.cjs +27 -13
- package/build/cjs/utils/sandbox.cjs +5 -10
- package/build/cjs/utils/{ssr-element.cjs → ssr-bootstrap.cjs} +30 -53
- package/build/cjs/utils/ssr-debug.cjs +88 -0
- package/build/cjs/utils/utils.cjs +77 -8
- package/build/cjs/viewProvider/index.cjs +27 -25
- package/build/cjs/viewTransformer/index.cjs +79 -77
- package/build/es/dataViewTransformer/index.js +15 -2
- package/build/es/identity.d.ts +2 -2
- package/build/es/identity.js +8 -6
- package/build/es/moduleProvider/index.js +106 -96
- package/build/es/utils/amd-utils.js +51 -22
- package/build/es/utils/sandbox-vm.d.ts +2 -2
- package/build/es/utils/sandbox-vm.js +33 -14
- package/build/es/utils/sandbox.d.ts +12 -13
- package/build/es/utils/sandbox.js +7 -13
- package/build/es/utils/{ssr-element.d.ts → ssr-bootstrap.d.ts} +10 -7
- package/build/es/utils/{ssr-element.js → ssr-bootstrap.js} +37 -59
- package/build/es/utils/ssr-debug.d.ts +4 -0
- package/build/es/utils/ssr-debug.js +64 -0
- package/build/es/utils/utils.d.ts +15 -5
- package/build/es/utils/utils.js +89 -11
- package/build/es/viewProvider/index.d.ts +3 -2
- package/build/es/viewProvider/index.js +34 -30
- package/build/es/viewTransformer/index.d.ts +8 -8
- package/build/es/viewTransformer/index.js +104 -95
- package/package.json +8 -7
- package/build/cjs/utils/sandbox-worker.cjs +0 -134
- package/build/es/utils/sandbox-worker.d.ts +0 -17
- 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
|
-
- [
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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,
|
|
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);
|
package/build/cjs/identity.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
46
|
-
if (
|
|
47
|
-
return {
|
|
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
|
|
33
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
${
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
127
|
-
|
|
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.
|
|
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,
|
|
154
|
-
const originalSource = createServerBootstrapModule(
|
|
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({
|
|
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,
|
|
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
|
|
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 {
|
|
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 =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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,
|
|
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
|
|
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
|
|
35
|
-
|
|
36
|
-
|
|
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(
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
}
|