@lwrjs/lwc-ssr 0.8.0-alpha.8 → 0.9.0-alpha.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 +83 -33
- package/build/cjs/moduleProvider/index.cjs +6 -4
- package/build/cjs/viewTransformer/index.cjs +18 -4
- package/build/cjs/viewTransformer/sandbox-locker.cjs +54 -0
- package/build/cjs/viewTransformer/sandbox-worker.cjs +49 -0
- package/build/cjs/viewTransformer/sandbox.cjs +6 -23
- package/build/cjs/viewTransformer/ssr-element.cjs +16 -15
- package/build/es/moduleProvider/index.d.ts +1 -1
- package/build/es/moduleProvider/index.js +7 -5
- package/build/es/viewTransformer/index.d.ts +1 -1
- package/build/es/viewTransformer/index.js +25 -7
- package/build/es/viewTransformer/sandbox-locker.d.ts +7 -0
- package/build/es/viewTransformer/sandbox-locker.js +29 -0
- package/build/es/viewTransformer/sandbox-worker.d.ts +12 -0
- package/build/es/viewTransformer/sandbox-worker.js +38 -0
- package/build/es/viewTransformer/sandbox.d.ts +3 -5
- package/build/es/viewTransformer/sandbox.js +5 -37
- package/build/es/viewTransformer/ssr-element.d.ts +6 -5
- package/build/es/viewTransformer/ssr-element.js +24 -20
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ SSR is activated on a per-route basis by changing `bootstrap.ssr` to `true`:
|
|
|
41
41
|
|
|
42
42
|
### Building SSR pages
|
|
43
43
|
|
|
44
|
-
When a route with `bootstrap.ssr` is requested, LWR will use [LWC'S `renderComponent()` function](https://rfcs.lwc.dev/rfcs/lwc/0112-server-engine) to SSR each root component on the page. This is done whether the page is generated at runtime, or pre-built using `generateStaticSite()`.
|
|
44
|
+
When a route with `bootstrap.ssr` is requested, LWR will use [LWC'S `renderComponent()` function](https://rfcs.lwc.dev/rfcs/lwc/0112-server-engine) to SSR each **root component** on the page. This is done whether the page is generated at runtime, or pre-built using `generateStaticSite()`.
|
|
45
45
|
|
|
46
46
|
> A "root component" is any lwc in an app route's [content template, layout template](https://github.com/salesforce/lwr-recipes/tree/main/packages/templating#templates), or [`rootComponent` configuration](https://github.com/salesforce/lwr-recipes/blob/main/doc/config.md#routes).
|
|
47
47
|
|
|
@@ -57,72 +57,122 @@ LWR will automatically pass any root component attributes from a [template](http
|
|
|
57
57
|
|
|
58
58
|
#### Limitations
|
|
59
59
|
|
|
60
|
-
There are restrictions on component code for it to successfully render on the server. The `renderComponent()` function executes the [`constructor` and `connectedCallback`](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reference_lifecycle_hooks) of each component.
|
|
60
|
+
There are restrictions on component code for it to successfully render on the server. The `renderComponent()` function executes the [`constructor` and `connectedCallback`](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reference_lifecycle_hooks) of each component. This code must be **portable** or SSR will fail.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
> Code is _portable_ when it can run in a headless environment, where there is no access to DOM APIs (eg: window).
|
|
63
63
|
|
|
64
|
-
###
|
|
64
|
+
### Loading data during SSR
|
|
65
65
|
|
|
66
|
-
Many components depend on external data. LWR provides a `
|
|
66
|
+
Many components depend on external data and resources. LWR provides a `getPageData()` hook for developers to fetch data on the server. During SSR, LWR calls the `getPageData()` hook for each **root component**, then serializes the resulting data into the page document as either [JSON](#json) or [markup](#markup).
|
|
67
67
|
|
|
68
|
-
> **Important**:
|
|
68
|
+
> **Important**: `getPageData()` is **only** run for root components.
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
```ts
|
|
71
|
+
type GetPageDataHook = (context: SsrRequestContext) => Promise<PageDataResponse>;
|
|
72
|
+
|
|
73
|
+
interface SsrRequestContext {
|
|
74
|
+
// existing props from template attributes
|
|
75
|
+
props: Json;
|
|
76
|
+
// values from a parameterized route defined in lwr.config.json
|
|
77
|
+
params: { [key: string]: string };
|
|
78
|
+
// search parameters from the request URL
|
|
79
|
+
query: { [key: string]: string };
|
|
80
|
+
// locale string for the request, eg: 'en-US'
|
|
81
|
+
locale: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface PageDataResponse {
|
|
85
|
+
props?: Json; // JSON serializable properties for the root component
|
|
86
|
+
markup?: {
|
|
87
|
+
// HTML serializable data
|
|
88
|
+
links?: {
|
|
89
|
+
// links to contribute to the <head> markup
|
|
90
|
+
href: string;
|
|
91
|
+
as?: string;
|
|
92
|
+
rel?: string;
|
|
93
|
+
fetchpriority?: 'high' | 'low' | 'auto';
|
|
94
|
+
}[];
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type Json = undefined | null | boolean | number | string | Json[] | { [prop: string]: Json };
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
In LWR, the SSR process runs in a sandbox. This sandbox supports `globalThis.fetch` so developers can use `fetch()` in their `getPageData()` hooks as if the module is being executed in browser.
|
|
102
|
+
|
|
103
|
+
#### JSON
|
|
104
|
+
|
|
105
|
+
Data in `PageDataResponse.props` is serialized into the page document as JSON. LWR passes this data to the component as [public properties](<(https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reactivity_public)>) during both SSR and [client hydration](#client-hydration).
|
|
106
|
+
|
|
107
|
+
#### Markup
|
|
108
|
+
|
|
109
|
+
Data in `PageDataResponse.markup` is serialized into the page document as HTML. LWR adds each `markup.link` returned by `getPageData()` to the `<head>` section of the page document. For example, developers can [preload images](https://developer.chrome.com/blog/link-rel-preload/) to improve a page's performance on the client.
|
|
110
|
+
|
|
111
|
+
#### Example
|
|
112
|
+
|
|
113
|
+
The `getPageData()` hook is exported as a function from a root component module:
|
|
71
114
|
|
|
72
115
|
```ts
|
|
73
116
|
// my-app/src/modules/my/root/root.ts
|
|
74
117
|
import { LightningElement, api } from 'lwc';
|
|
75
|
-
import type {
|
|
118
|
+
import type { SsrRequestContext, PageDataResponse } from '@lwrjs/types';
|
|
76
119
|
|
|
77
120
|
export default class MyRoot extends LightningElement {
|
|
78
121
|
@api data: SomeDataType[] = [];
|
|
79
122
|
}
|
|
80
123
|
|
|
81
|
-
export async function
|
|
124
|
+
export async function getPageData(context: SsrRequestContext): Promise<PageDataResponse> {
|
|
82
125
|
// "/category/books" => context.params = { category: 'books' }
|
|
83
126
|
const category = context.params.category;
|
|
127
|
+
|
|
84
128
|
// page.html template => context.props = { limit: '10' }
|
|
85
129
|
const num = context.props.limit || '25';
|
|
86
130
|
const res = await fetch(`https://www.some-api.com/${category}?lang=${context.locale}&num=${num}`);
|
|
87
131
|
const data = await res.json();
|
|
132
|
+
|
|
88
133
|
return {
|
|
89
134
|
props: {
|
|
90
135
|
// will be passed to the root component as props
|
|
91
136
|
data,
|
|
92
137
|
...context.props, // pass the template props through, if desired
|
|
93
138
|
},
|
|
139
|
+
markup: {
|
|
140
|
+
links: [
|
|
141
|
+
{
|
|
142
|
+
// preload an important image to boost performance
|
|
143
|
+
href: data.thumbnail,
|
|
144
|
+
as: 'image',
|
|
145
|
+
rel: 'preload',
|
|
146
|
+
fetchpriority: 'high',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
94
150
|
};
|
|
95
151
|
}
|
|
96
152
|
```
|
|
97
153
|
|
|
98
|
-
|
|
99
|
-
type GetPropsHook = (context: PropsRequestContext) => Promise<PropsResponse>;
|
|
154
|
+
Notes:
|
|
100
155
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// values from a parameterized route defined in lwr.config.json
|
|
105
|
-
params: { [key: string]: string };
|
|
106
|
-
// search parameters from the request URL
|
|
107
|
-
query: { [key: string]: string };
|
|
108
|
-
// locale string for the request, eg: 'en-US'
|
|
109
|
-
locale: string;
|
|
110
|
-
}
|
|
156
|
+
- The `getPageData()` hook can choose to merge the properties from `SsrRequestContext.props` into its return object, or it can ignore/discard them.
|
|
157
|
+
- The author of `getPageData()` is responsible for validating the `params` and `query` from `SsrRequestContext` before using them.
|
|
158
|
+
- The **same** `props` returned by `getPageData()` are passed to the component during server rendering **and** client hydration.
|
|
111
159
|
|
|
112
|
-
|
|
113
|
-
// serializable props for the root component
|
|
114
|
-
props: Json;
|
|
115
|
-
}
|
|
160
|
+
### Client hydration
|
|
116
161
|
|
|
117
|
-
|
|
118
|
-
```
|
|
162
|
+
When SSRed component HTML reaches the browser, each root component is automatically hydrated. LWR uses the [LWC `hydrateComponent()` API](https://rfcs.lwc.dev/rfcs/lwc/0117-ssr-rehydration) to do so. Hydrating a component starts its component lifecycle and makes it interactive.
|
|
119
163
|
|
|
120
|
-
|
|
164
|
+
### Debugging
|
|
121
165
|
|
|
122
|
-
|
|
123
|
-
- The author of `getProps()` is responsible for validating the `params` and `query` from `PropsRequestContext` before using them.
|
|
124
|
-
- The **same** `props` returned by `getProps()` are passed to the component during server rendering **and** client hydration.
|
|
166
|
+
With the introduction of [@locker/near-membrane-node](https://github.com/salesforce/near-membrane/tree/main/packages/near-membrane-node) sandbox, debugging a module in server side rendering is straightforward:
|
|
125
167
|
|
|
126
|
-
|
|
168
|
+
1. setting a `debugger;` statement in your module
|
|
169
|
+
2. attach node process to the LWR server
|
|
127
170
|
|
|
128
|
-
|
|
171
|
+
```sh
|
|
172
|
+
LOCKER_SB=true yarn lwr:example:debug
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
3. visit intended url(http://localhost:3000/ssr in this example) with a browser
|
|
176
|
+
4. when `debugger;` statement is executed, VS Code would break with the VM tab showing up
|
|
177
|
+
|
|
178
|
+

|
|
@@ -35,19 +35,21 @@ import { renderComponent } from '@lwc/engine-server';
|
|
|
35
35
|
import Ctor, * as rootComponent from '${rootSpecifier}';
|
|
36
36
|
|
|
37
37
|
(async () => {
|
|
38
|
-
// 1. setup
|
|
38
|
+
// 1. setup page data
|
|
39
39
|
const context = globalThis.getContext();
|
|
40
40
|
let props = context.props;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
let markup;
|
|
42
|
+
if (rootComponent.getPageData) {
|
|
43
|
+
const data = await rootComponent.getPageData(context);
|
|
43
44
|
props = data.props; // overwrite public props
|
|
45
|
+
markup = data.markup;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
// 2. render component
|
|
47
49
|
const result = renderComponent('${(0, import_shared_utils.moduleSpecifierToKebabCase)(rootSpecifier)}', Ctor, props || {});
|
|
48
50
|
|
|
49
51
|
// 3. relay results
|
|
50
|
-
globalThis.
|
|
52
|
+
globalThis.resolver({ result, props, markup });
|
|
51
53
|
})()`;
|
|
52
54
|
}
|
|
53
55
|
var LwcSsrModuleProvider = class {
|
|
@@ -54,22 +54,36 @@ function lwcSsrViewTranformer(options, {moduleBundler}) {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
const ssrProps = {};
|
|
57
|
+
let ssrLinks = "";
|
|
57
58
|
await Promise.all(ssrModules.map(({specifier, tagName, props, startOffset, endOffset}) => {
|
|
58
|
-
return (0, import_ssr_element.ssrElement)({specifier, props}, moduleBundler, viewContext).then(({html, props: props2}) => {
|
|
59
|
+
return (0, import_ssr_element.ssrElement)({specifier, props}, moduleBundler, viewContext).then(({html, props: props2, markup: {links = []} = {links: []}}) => {
|
|
59
60
|
if (props2) {
|
|
60
61
|
const propsId = (0, import_identity.getPropsId)();
|
|
61
62
|
ssrProps[propsId] = props2;
|
|
62
63
|
const [, remain] = html.split(`<${tagName}`);
|
|
63
64
|
html = [`<${tagName}`, ` ${import_identity.SSR_PROPS_ATTR}="${propsId}"`, remain].join("");
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
links.forEach(({href, rel, as, fetchpriority}) => {
|
|
67
|
+
const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
|
|
68
|
+
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>
|
|
69
|
+
`;
|
|
70
|
+
});
|
|
71
|
+
stringBuilder.overwrite(startOffset, endOffset, html);
|
|
72
|
+
}).catch((err) => {
|
|
73
|
+
import_shared_utils.logger.warn(`Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: `, err.stack);
|
|
68
74
|
});
|
|
69
75
|
}));
|
|
70
76
|
if (Object.keys(ssrProps).length) {
|
|
71
77
|
stringBuilder.prependLeft(ssrModules[0].startOffset, `<script type="application/javascript">globalThis.LWR = globalThis.LWR || {};globalThis.LWR.${import_identity.SSR_PROPS_KEY} = ${JSON.stringify(ssrProps)};</script>`);
|
|
72
78
|
}
|
|
79
|
+
if (ssrLinks) {
|
|
80
|
+
const headIndex = stringBuilder.original.indexOf("</head>");
|
|
81
|
+
if (headIndex >= 0) {
|
|
82
|
+
stringBuilder.prependLeft(headIndex, ssrLinks);
|
|
83
|
+
} else {
|
|
84
|
+
import_shared_utils.logger.error("Adding links during server-side rendering failed. Could not find the </head> tag.");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
73
87
|
import_shared_utils.logger.verbose("lwcSsrViewTranformer response", stringBuilder);
|
|
74
88
|
}
|
|
75
89
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
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;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
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
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/lwc-ssr/src/viewTransformer/sandbox-locker.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
default: () => runCode
|
|
28
|
+
});
|
|
29
|
+
var import_near_membrane_node = __toModule(require("@locker/near-membrane-node"));
|
|
30
|
+
var import_node_fetch = __toModule(require("node-fetch"));
|
|
31
|
+
function runCode(codes, context) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let resolver;
|
|
34
|
+
const p = new Promise((r) => resolver = r);
|
|
35
|
+
function getContext() {
|
|
36
|
+
return context;
|
|
37
|
+
}
|
|
38
|
+
const endowments = Object.getOwnPropertyDescriptors({
|
|
39
|
+
getContext,
|
|
40
|
+
fetch: import_node_fetch.default,
|
|
41
|
+
resolver,
|
|
42
|
+
process,
|
|
43
|
+
setTimeout,
|
|
44
|
+
clearTimeout
|
|
45
|
+
});
|
|
46
|
+
const ve = (0, import_near_membrane_node.default)(globalThis, {endowments});
|
|
47
|
+
try {
|
|
48
|
+
ve.evaluate(codes.join("\n"));
|
|
49
|
+
p.then(resolve);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
reject(e);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
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;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
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
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/lwc-ssr/src/viewTransformer/sandbox-worker.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
default: () => runCode
|
|
28
|
+
});
|
|
29
|
+
var import_worker_threads = __toModule(require("worker_threads"));
|
|
30
|
+
var HEADER = "/* This module is generated and meant to be used in a Server context */";
|
|
31
|
+
var WORKER_CODE_SANDBOX_APIS = [
|
|
32
|
+
`const { parentPort, workerData } = require('worker_threads');`,
|
|
33
|
+
`globalThis.getContext = () => workerData;`,
|
|
34
|
+
`globalThis.fetch = require('node-fetch');`,
|
|
35
|
+
`globalThis.resolver = (...args) => parentPort.postMessage(...args);`
|
|
36
|
+
];
|
|
37
|
+
function runCode(codes, workerData) {
|
|
38
|
+
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join("\n");
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData});
|
|
41
|
+
worker.on("message", resolve);
|
|
42
|
+
worker.on("error", reject);
|
|
43
|
+
worker.on("exit", (code) => {
|
|
44
|
+
if (code !== 0) {
|
|
45
|
+
reject(new Error(`SSR worker stopped with exit code: ${code}`));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -26,28 +26,11 @@ __markAsModule(exports);
|
|
|
26
26
|
__export(exports, {
|
|
27
27
|
default: () => runCode
|
|
28
28
|
});
|
|
29
|
-
var
|
|
30
|
-
var
|
|
31
|
-
var WORKER_CODE_SANDBOX_APIS = [
|
|
32
|
-
`const { parentPort, workerData } = require('worker_threads');`,
|
|
33
|
-
`globalThis.getContext = () => workerData;`,
|
|
34
|
-
`globalThis.fetch = require('node-fetch');`,
|
|
35
|
-
`globalThis.postMessage = (...args) => parentPort.postMessage(...args);`
|
|
36
|
-
];
|
|
37
|
-
function runCodeOnWorker(codes, workerData) {
|
|
38
|
-
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join("\n");
|
|
39
|
-
return new Promise((resolve) => {
|
|
40
|
-
const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData});
|
|
41
|
-
worker.on("message", resolve);
|
|
42
|
-
worker.on("error", (err) => resolve({error: `SSR worker exited with error: ${err.message}
|
|
43
|
-
${err.stack}`}));
|
|
44
|
-
worker.on("exit", (code) => {
|
|
45
|
-
if (code !== 0) {
|
|
46
|
-
resolve({error: `SSR worker stopped with exit code: ${code}`});
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
}
|
|
29
|
+
var import_sandbox_worker = __toModule(require("./sandbox-worker.cjs"));
|
|
30
|
+
var import_sandbox_locker = __toModule(require("./sandbox-locker.cjs"));
|
|
51
31
|
function runCode(codes, context) {
|
|
52
|
-
|
|
32
|
+
if (process.env.LOCKER_SB === "true") {
|
|
33
|
+
return (0, import_sandbox_locker.default)(codes, context);
|
|
34
|
+
}
|
|
35
|
+
return (0, import_sandbox_worker.default)(codes, context);
|
|
53
36
|
}
|
|
@@ -28,34 +28,35 @@ __export(exports, {
|
|
|
28
28
|
});
|
|
29
29
|
var import_amd_utils = __toModule(require("./amd-utils.cjs"));
|
|
30
30
|
var import_sandbox = __toModule(require("./sandbox.cjs"));
|
|
31
|
-
var
|
|
32
|
-
exclude: [],
|
|
33
|
-
alias: {
|
|
34
|
-
lwc: "@lwc/engine-server"
|
|
35
|
-
}
|
|
36
|
-
};
|
|
31
|
+
var import_perf_hooks = __toModule(require("perf_hooks"));
|
|
37
32
|
async function ssrElement({specifier, props: templateProps}, moduleBundler, {runtimeEnvironment, runtimeParams}) {
|
|
38
|
-
const {format
|
|
33
|
+
const {format} = runtimeEnvironment;
|
|
39
34
|
const {
|
|
40
35
|
bundleRecord,
|
|
41
36
|
code,
|
|
42
37
|
specifier: bundleSpecifier,
|
|
43
38
|
version
|
|
44
|
-
} = await moduleBundler.getModuleBundle({specifier}, {...runtimeEnvironment, bundle:
|
|
39
|
+
} = format === "esm" ? await moduleBundler.getModuleBundle({specifier}, {...runtimeEnvironment, bundle: false}, void 0, {
|
|
40
|
+
exclude: [],
|
|
41
|
+
alias: {
|
|
42
|
+
lwc: "@lwc/engine-server"
|
|
43
|
+
}
|
|
44
|
+
}) : await moduleBundler.getModuleBundle({specifier}, runtimeEnvironment, void 0, {
|
|
45
|
+
exclude: ["lwc"]
|
|
46
|
+
});
|
|
45
47
|
const context = {
|
|
46
48
|
props: templateProps,
|
|
47
49
|
params: runtimeParams.params || {},
|
|
48
50
|
query: runtimeParams.query || {},
|
|
49
51
|
locale: runtimeParams.locale || runtimeEnvironment.defaultLocale
|
|
50
52
|
};
|
|
51
|
-
const
|
|
53
|
+
const startTime = import_perf_hooks.performance.now();
|
|
54
|
+
const {result, props, markup} = format === "amd" ? await (0, import_sandbox.default)([
|
|
52
55
|
...await (0, import_amd_utils.default)(runtimeEnvironment, version.replace(/\./g, "_"), bundleSpecifier, bundleRecord.includedModules),
|
|
53
56
|
code
|
|
54
57
|
], context) : await (0, import_sandbox.default)([code], context);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return {html: result, props};
|
|
60
|
-
}
|
|
58
|
+
const endTime = import_perf_hooks.performance.now();
|
|
59
|
+
const timeDiff = endTime - startTime;
|
|
60
|
+
console.log(`[${specifier} SSR] complete in ${timeDiff} ms`);
|
|
61
|
+
return {html: result, props, markup};
|
|
61
62
|
}
|
|
@@ -8,7 +8,7 @@ import { ModuleCompiled, ModuleEntry, ModuleProvider, ProviderContext, AbstractM
|
|
|
8
8
|
* Create the virtual source for a module which server-side renders the given component.
|
|
9
9
|
* This code is meant to be executed in a worker on the server; it is run from "lwc-ssr/viewTransformer#ssr-element" during linking.
|
|
10
10
|
* The result is posted to the parentPort and the Promise in the main thread resolves.
|
|
11
|
-
* If available,
|
|
11
|
+
* If available, getPageData() is called on the root component to mutate context.props and gather page markup
|
|
12
12
|
* @param rootSpecifier - The specifier for the component to SSR
|
|
13
13
|
* @returns the generated module source
|
|
14
14
|
*/
|
|
@@ -9,7 +9,7 @@ import { LWC_SSR_PREFIX } from '../identity.js';
|
|
|
9
9
|
* Create the virtual source for a module which server-side renders the given component.
|
|
10
10
|
* This code is meant to be executed in a worker on the server; it is run from "lwc-ssr/viewTransformer#ssr-element" during linking.
|
|
11
11
|
* The result is posted to the parentPort and the Promise in the main thread resolves.
|
|
12
|
-
* If available,
|
|
12
|
+
* If available, getPageData() is called on the root component to mutate context.props and gather page markup
|
|
13
13
|
* @param rootSpecifier - The specifier for the component to SSR
|
|
14
14
|
* @returns the generated module source
|
|
15
15
|
*/
|
|
@@ -19,19 +19,21 @@ import { renderComponent } from '@lwc/engine-server';
|
|
|
19
19
|
import Ctor, * as rootComponent from '${rootSpecifier}';
|
|
20
20
|
|
|
21
21
|
(async () => {
|
|
22
|
-
// 1. setup
|
|
22
|
+
// 1. setup page data
|
|
23
23
|
const context = globalThis.getContext();
|
|
24
24
|
let props = context.props;
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
let markup;
|
|
26
|
+
if (rootComponent.getPageData) {
|
|
27
|
+
const data = await rootComponent.getPageData(context);
|
|
27
28
|
props = data.props; // overwrite public props
|
|
29
|
+
markup = data.markup;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
// 2. render component
|
|
31
33
|
const result = renderComponent('${moduleSpecifierToKebabCase(rootSpecifier)}', Ctor, props || {});
|
|
32
34
|
|
|
33
35
|
// 3. relay results
|
|
34
|
-
globalThis.
|
|
36
|
+
globalThis.resolver({ result, props, markup });
|
|
35
37
|
})()`;
|
|
36
38
|
}
|
|
37
39
|
export default class LwcSsrModuleProvider {
|
|
@@ -13,7 +13,7 @@ interface SsrPluginOptions {
|
|
|
13
13
|
* a) It requests a module which SSRs a given custom element, generated by "lwc-ssr/moduleProvider"
|
|
14
14
|
* b) A bundle is created for the generated SSR module (see "./ssr-element")
|
|
15
15
|
* c) The bundle code is run inside a worker (see "./ssr-element"), with context stored in "workerData"
|
|
16
|
-
* d) RootComponent.
|
|
16
|
+
* d) RootComponent.getPageData() is run to preload data and <links>, if available
|
|
17
17
|
* e) The generated SSR module (running the worker) passes the SSRed code string back to the main thread
|
|
18
18
|
* f) The SSRed string is used to overwrite/link each custom element (eg: "<c-app></c-app>") in the document (see "stringBuilder.overwrite")
|
|
19
19
|
* g) A script containing all the serialized properties is added for hydration
|
|
@@ -12,7 +12,7 @@ import { ssrElement } from './ssr-element.js';
|
|
|
12
12
|
* a) It requests a module which SSRs a given custom element, generated by "lwc-ssr/moduleProvider"
|
|
13
13
|
* b) A bundle is created for the generated SSR module (see "./ssr-element")
|
|
14
14
|
* c) The bundle code is run inside a worker (see "./ssr-element"), with context stored in "workerData"
|
|
15
|
-
* d) RootComponent.
|
|
15
|
+
* d) RootComponent.getPageData() is run to preload data and <links>, if available
|
|
16
16
|
* e) The generated SSR module (running the worker) passes the SSRed code string back to the main thread
|
|
17
17
|
* f) The SSRed string is used to overwrite/link each custom element (eg: "<c-app></c-app>") in the document (see "stringBuilder.overwrite")
|
|
18
18
|
* g) A script containing all the serialized properties is added for hydration
|
|
@@ -46,10 +46,12 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
// SSR and gather the properties for each eligible custom element, in parallel
|
|
49
|
+
// SSR and gather the properties and links for each eligible custom element, in parallel
|
|
50
50
|
const ssrProps = {};
|
|
51
|
+
let ssrLinks = '';
|
|
51
52
|
await Promise.all(ssrModules.map(({ specifier, tagName, props, startOffset, endOffset }) => {
|
|
52
|
-
return ssrElement({ specifier, props }, moduleBundler, viewContext)
|
|
53
|
+
return ssrElement({ specifier, props }, moduleBundler, viewContext)
|
|
54
|
+
.then(({ html, props, markup: { links = [] } = { links: [] } }) => {
|
|
53
55
|
if (props) {
|
|
54
56
|
// Add the props id to the HTML for the custom element
|
|
55
57
|
// eg: <some-cmp> -> <some-cmp data-lwr-props-id="1234">
|
|
@@ -58,10 +60,16 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
58
60
|
const [, remain] = html.split(`<${tagName}`);
|
|
59
61
|
html = [`<${tagName}`, ` ${SSR_PROPS_ATTR}="${propsId}"`, remain].join('');
|
|
60
62
|
}
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
links.forEach(({ href, rel, as, fetchpriority }) => {
|
|
64
|
+
// Create HTML <link> strings for each item in the links array
|
|
65
|
+
const relStr = rel ? ` rel="${rel}"` : '', asStr = as ? ` as="${as}"` : '', fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : '';
|
|
66
|
+
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>\n`;
|
|
67
|
+
});
|
|
68
|
+
// Overwrite the custom element with the SSRed component string
|
|
69
|
+
stringBuilder.overwrite(startOffset, endOffset, html);
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
72
|
+
logger.warn(`Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: `, err.stack);
|
|
65
73
|
});
|
|
66
74
|
}));
|
|
67
75
|
if (Object.keys(ssrProps).length) {
|
|
@@ -69,6 +77,16 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
69
77
|
// Append the script before the custom elements; it MUST appear before the AMD shim to avoid timing issues
|
|
70
78
|
stringBuilder.prependLeft(ssrModules[0].startOffset, `<script type="application/javascript">globalThis.LWR = globalThis.LWR || {};globalThis.LWR.${SSR_PROPS_KEY} = ${JSON.stringify(ssrProps)};</script>`);
|
|
71
79
|
}
|
|
80
|
+
if (ssrLinks) {
|
|
81
|
+
// Add all the links to the <head> section of the base document
|
|
82
|
+
const headIndex = stringBuilder.original.indexOf('</head>');
|
|
83
|
+
if (headIndex >= 0) {
|
|
84
|
+
stringBuilder.prependLeft(headIndex, ssrLinks);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
logger.error('Adding links during server-side rendering failed. Could not find the </head> tag.');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
72
90
|
logger.verbose('lwcSsrViewTranformer response', stringBuilder);
|
|
73
91
|
}
|
|
74
92
|
},
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PageDataResponse, SsrRequestContext } from '@lwrjs/types';
|
|
2
|
+
interface SandboxResults extends PageDataResponse {
|
|
3
|
+
result?: string;
|
|
4
|
+
}
|
|
5
|
+
export default function runCode(codes: string[], context: SsrRequestContext): Promise<SandboxResults>;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=sandbox-locker.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import createVirtualEnvironment from '@locker/near-membrane-node';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
export default function runCode(codes, context) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
let resolver;
|
|
6
|
+
const p = new Promise((r) => (resolver = r));
|
|
7
|
+
function getContext() {
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
10
|
+
const endowments = Object.getOwnPropertyDescriptors({
|
|
11
|
+
getContext,
|
|
12
|
+
fetch,
|
|
13
|
+
resolver,
|
|
14
|
+
// for AMD loader ModuleRegistry
|
|
15
|
+
process,
|
|
16
|
+
setTimeout,
|
|
17
|
+
clearTimeout,
|
|
18
|
+
});
|
|
19
|
+
const ve = createVirtualEnvironment(globalThis, { endowments });
|
|
20
|
+
try {
|
|
21
|
+
ve.evaluate(codes.join('\n'));
|
|
22
|
+
p.then(resolve);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
reject(e);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=sandbox-locker.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PageDataResponse, SsrRequestContext } from '@lwrjs/types';
|
|
2
|
+
interface SandboxResults extends PageDataResponse {
|
|
3
|
+
result?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Run the SSR module code in a worker, and return the results to the main thread.
|
|
7
|
+
* @param codes - Code strings which SSR a root component
|
|
8
|
+
* @returns a promise to the SSRed code string, or an error message
|
|
9
|
+
*/
|
|
10
|
+
export default function runCode(codes: string[], workerData: SsrRequestContext): Promise<SandboxResults>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=sandbox-worker.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Worker } from 'worker_threads';
|
|
2
|
+
const HEADER = '/* This module is generated and meant to be used in a Server context */';
|
|
3
|
+
/**
|
|
4
|
+
* Sandbox APIs
|
|
5
|
+
* @param globalThis.getContext
|
|
6
|
+
* function to provide prop request context object with properties such as props, params, and locale
|
|
7
|
+
*
|
|
8
|
+
* @param globalThis.fetch
|
|
9
|
+
* fetch function for external data fetching
|
|
10
|
+
*
|
|
11
|
+
* @param globalThis.postMessage
|
|
12
|
+
* postbacks from sandbox to main thread
|
|
13
|
+
*/
|
|
14
|
+
const WORKER_CODE_SANDBOX_APIS = [
|
|
15
|
+
`const { parentPort, workerData } = require('worker_threads');`,
|
|
16
|
+
`globalThis.getContext = () => workerData;`,
|
|
17
|
+
`globalThis.fetch = require('node-fetch');`,
|
|
18
|
+
`globalThis.resolver = (...args) => parentPort.postMessage(...args);`,
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Run the SSR module code in a worker, and return the results to the main thread.
|
|
22
|
+
* @param codes - Code strings which SSR a root component
|
|
23
|
+
* @returns a promise to the SSRed code string, or an error message
|
|
24
|
+
*/
|
|
25
|
+
export default function runCode(codes, workerData) {
|
|
26
|
+
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join('\n');
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const worker = new Worker(workerCode, { eval: true, workerData });
|
|
29
|
+
worker.on('message', resolve);
|
|
30
|
+
worker.on('error', reject);
|
|
31
|
+
worker.on('exit', (code) => {
|
|
32
|
+
if (code !== 0) {
|
|
33
|
+
reject(new Error(`SSR worker stopped with exit code: ${code}`));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=sandbox-worker.js.map
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
interface SandboxResults {
|
|
1
|
+
import { PageDataResponse, SsrRequestContext } from '@lwrjs/types';
|
|
2
|
+
interface SandboxResults extends PageDataResponse {
|
|
3
3
|
result?: string;
|
|
4
|
-
error?: string;
|
|
5
|
-
props?: Json;
|
|
6
4
|
}
|
|
7
|
-
export default function runCode(codes: string[], context:
|
|
5
|
+
export default function runCode(codes: string[], context: SsrRequestContext): Promise<SandboxResults>;
|
|
8
6
|
export {};
|
|
9
7
|
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -1,41 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Sandbox APIs
|
|
5
|
-
* @param globalThis.getContext
|
|
6
|
-
* function to provide prop request context object with properties such as props, params, and locale
|
|
7
|
-
*
|
|
8
|
-
* @param globalThis.fetch
|
|
9
|
-
* fetch function for external data fetching
|
|
10
|
-
*
|
|
11
|
-
* @param globalThis.postMessage
|
|
12
|
-
* postbacks from sandbox to main thread
|
|
13
|
-
*/
|
|
14
|
-
const WORKER_CODE_SANDBOX_APIS = [
|
|
15
|
-
`const { parentPort, workerData } = require('worker_threads');`,
|
|
16
|
-
`globalThis.getContext = () => workerData;`,
|
|
17
|
-
`globalThis.fetch = require('node-fetch');`,
|
|
18
|
-
`globalThis.postMessage = (...args) => parentPort.postMessage(...args);`,
|
|
19
|
-
];
|
|
20
|
-
/**
|
|
21
|
-
* Run the SSR module code in a worker, and return the results to the main thread.
|
|
22
|
-
* @param codes - Code strings which SSR a root component
|
|
23
|
-
* @returns a promise to the SSRed code string, or an error message
|
|
24
|
-
*/
|
|
25
|
-
function runCodeOnWorker(codes, workerData) {
|
|
26
|
-
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join('\n');
|
|
27
|
-
return new Promise((resolve) => {
|
|
28
|
-
const worker = new Worker(workerCode, { eval: true, workerData });
|
|
29
|
-
worker.on('message', resolve);
|
|
30
|
-
worker.on('error', (err) => resolve({ error: `SSR worker exited with error: ${err.message}\n${err.stack}` }));
|
|
31
|
-
worker.on('exit', (code) => {
|
|
32
|
-
if (code !== 0) {
|
|
33
|
-
resolve({ error: `SSR worker stopped with exit code: ${code}` });
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
}
|
|
1
|
+
import runCodeOnWorker from './sandbox-worker.js';
|
|
2
|
+
import runCodeOnLocker from './sandbox-locker.js';
|
|
38
3
|
export default function runCode(codes, context) {
|
|
4
|
+
if (process.env.LOCKER_SB === 'true') {
|
|
5
|
+
return runCodeOnLocker(codes, context);
|
|
6
|
+
}
|
|
39
7
|
return runCodeOnWorker(codes, context);
|
|
40
8
|
}
|
|
41
9
|
//# sourceMappingURL=sandbox.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type { Json, ModuleBundler, ViewTranformPluginContext } from '@lwrjs/types';
|
|
1
|
+
import type { Json, ModuleBundler, PageDataResponse, ViewTranformPluginContext } from '@lwrjs/types';
|
|
2
|
+
interface SsrResults extends PageDataResponse {
|
|
3
|
+
html: string;
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* Create a bundle for the given SSR module and run the code in a sandbox.
|
|
4
7
|
* @param moduleInfo - specifier: The ID of the module, generated by "lwc-ssr/moduleProvider", which SSRs a component
|
|
@@ -10,8 +13,6 @@ import type { Json, ModuleBundler, ViewTranformPluginContext } from '@lwrjs/type
|
|
|
10
13
|
export declare function ssrElement({ specifier, props: templateProps }: {
|
|
11
14
|
specifier: string;
|
|
12
15
|
props: Json;
|
|
13
|
-
}, moduleBundler: ModuleBundler, { runtimeEnvironment, runtimeParams }: ViewTranformPluginContext): Promise<
|
|
14
|
-
|
|
15
|
-
props: Json;
|
|
16
|
-
}>;
|
|
16
|
+
}, moduleBundler: ModuleBundler, { runtimeEnvironment, runtimeParams }: ViewTranformPluginContext): Promise<SsrResults>;
|
|
17
|
+
export {};
|
|
17
18
|
//# sourceMappingURL=ssr-element.d.ts.map
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import getCode from './amd-utils.js';
|
|
2
2
|
import runCode from './sandbox.js';
|
|
3
|
-
|
|
4
|
-
exclude: [],
|
|
5
|
-
alias: {
|
|
6
|
-
lwc: '@lwc/engine-server', // override the default "@lwc/engine-dom" package
|
|
7
|
-
},
|
|
8
|
-
};
|
|
3
|
+
import { performance } from 'perf_hooks';
|
|
9
4
|
/**
|
|
10
5
|
* Create a bundle for the given SSR module and run the code in a sandbox.
|
|
11
6
|
* @param moduleInfo - specifier: The ID of the module, generated by "lwc-ssr/moduleProvider", which SSRs a component
|
|
@@ -15,12 +10,23 @@ const bundleConfigOverrides = {
|
|
|
15
10
|
* @returns a promise to the SSRed code string
|
|
16
11
|
*/
|
|
17
12
|
export async function ssrElement({ specifier, props: templateProps }, moduleBundler, { runtimeEnvironment, runtimeParams }) {
|
|
18
|
-
const { format
|
|
19
|
-
const { bundleRecord, code, specifier: bundleSpecifier, version, } =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
const { format } = runtimeEnvironment;
|
|
14
|
+
const { bundleRecord, code, specifier: bundleSpecifier, version, } = format === 'esm'
|
|
15
|
+
? await moduleBundler.getModuleBundle({ specifier },
|
|
16
|
+
// Ensure the bundle flag is always off in ESM,
|
|
17
|
+
// otherwise TOO much gets bundled in the module registry
|
|
18
|
+
// in ESM, resulting lwc clashes/duplication
|
|
19
|
+
{ ...runtimeEnvironment, bundle: false }, undefined, {
|
|
20
|
+
exclude: [],
|
|
21
|
+
alias: {
|
|
22
|
+
// override the default "@lwc/engine-dom" package
|
|
23
|
+
lwc: '@lwc/engine-server',
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
: await moduleBundler.getModuleBundle({ specifier }, runtimeEnvironment, undefined, {
|
|
27
|
+
// "lwc" will be defined as an alias to "@lwc/engine-server" in the AMD worker code.
|
|
28
|
+
exclude: ['lwc'],
|
|
29
|
+
});
|
|
24
30
|
// Gather context to send into the SSR sandbox
|
|
25
31
|
const context = {
|
|
26
32
|
props: templateProps,
|
|
@@ -29,18 +35,16 @@ export async function ssrElement({ specifier, props: templateProps }, moduleBund
|
|
|
29
35
|
locale: runtimeParams.locale || runtimeEnvironment.defaultLocale,
|
|
30
36
|
};
|
|
31
37
|
// Get the SSR string and properties bag
|
|
32
|
-
const
|
|
38
|
+
const startTime = performance.now();
|
|
39
|
+
const { result, props, markup } = format === 'amd'
|
|
33
40
|
? await runCode([
|
|
34
41
|
...(await getCode(runtimeEnvironment, version.replace(/\./g, '_'), bundleSpecifier, bundleRecord.includedModules)),
|
|
35
42
|
code,
|
|
36
43
|
], context)
|
|
37
44
|
: await runCode([code], context);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
return { html: result, props };
|
|
44
|
-
}
|
|
45
|
+
const endTime = performance.now();
|
|
46
|
+
const timeDiff = endTime - startTime;
|
|
47
|
+
console.log(`[${specifier} SSR] complete in ${timeDiff} ms`);
|
|
48
|
+
return { html: result, props, markup };
|
|
45
49
|
}
|
|
46
50
|
//# sourceMappingURL=ssr-element.js.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.9.0-alpha.0",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -33,14 +33,16 @@
|
|
|
33
33
|
"build/**/*.d.ts"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@
|
|
37
|
-
"@lwrjs/
|
|
36
|
+
"@locker/near-membrane-node": "^0.11.6",
|
|
37
|
+
"@lwrjs/diagnostics": "0.9.0-alpha.0",
|
|
38
|
+
"@lwrjs/shared-utils": "0.9.0-alpha.0",
|
|
39
|
+
"node-fetch": "^2.6.1"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"@lwrjs/types": "0.
|
|
42
|
+
"@lwrjs/types": "0.9.0-alpha.0"
|
|
41
43
|
},
|
|
42
44
|
"engines": {
|
|
43
45
|
"node": ">=14.15.4 <19"
|
|
44
46
|
},
|
|
45
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "6890d8619b295a49ee1ed8253a372337d83863be"
|
|
46
48
|
}
|