@lwrjs/lwc-ssr 0.8.0-alpha.9 → 0.8.1
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 +16 -2
- package/build/cjs/moduleProvider/index.cjs +1 -1
- package/build/cjs/viewTransformer/index.cjs +4 -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.js +1 -1
- package/build/es/viewTransformer/index.js +8 -6
- 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 +0 -1
- package/build/es/viewTransformer/sandbox.js +5 -37
- package/build/es/viewTransformer/ssr-element.js +24 -20
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -61,8 +61,6 @@ There are restrictions on component code for it to successfully render on the se
|
|
|
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
|
-
Because of these limitations, the [`@lwrjs/router`](https://github.com/salesforce/lwr-recipes/blob/main/doc/navigation.md) is not yet supported with SSR.
|
|
65
|
-
|
|
66
64
|
### Loading data during SSR
|
|
67
65
|
|
|
68
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).
|
|
@@ -162,3 +160,19 @@ Notes:
|
|
|
162
160
|
### Client hydration
|
|
163
161
|
|
|
164
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.
|
|
163
|
+
|
|
164
|
+
### Debugging
|
|
165
|
+
|
|
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:
|
|
167
|
+
|
|
168
|
+
1. setting a `debugger;` statement in your module
|
|
169
|
+
2. attach node process to the LWR server
|
|
170
|
+
|
|
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
|
+

|
|
@@ -49,7 +49,7 @@ import Ctor, * as rootComponent from '${rootSpecifier}';
|
|
|
49
49
|
const result = renderComponent('${(0, import_shared_utils.moduleSpecifierToKebabCase)(rootSpecifier)}', Ctor, props || {});
|
|
50
50
|
|
|
51
51
|
// 3. relay results
|
|
52
|
-
globalThis.
|
|
52
|
+
globalThis.resolver({ result, props, markup });
|
|
53
53
|
})()`;
|
|
54
54
|
}
|
|
55
55
|
var LwcSsrModuleProvider = class {
|
|
@@ -68,9 +68,9 @@ function lwcSsrViewTranformer(options, {moduleBundler}) {
|
|
|
68
68
|
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>
|
|
69
69
|
`;
|
|
70
70
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
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);
|
|
74
74
|
});
|
|
75
75
|
}));
|
|
76
76
|
if (Object.keys(ssrProps).length) {
|
|
@@ -81,7 +81,7 @@ function lwcSsrViewTranformer(options, {moduleBundler}) {
|
|
|
81
81
|
if (headIndex >= 0) {
|
|
82
82
|
stringBuilder.prependLeft(headIndex, ssrLinks);
|
|
83
83
|
} else {
|
|
84
|
-
|
|
84
|
+
import_shared_utils.logger.error("Adding links during server-side rendering failed. Could not find the </head> tag.");
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
import_shared_utils.logger.verbose("lwcSsrViewTranformer response", stringBuilder);
|
|
@@ -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, markup};
|
|
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
|
}
|
|
@@ -33,7 +33,7 @@ import Ctor, * as rootComponent from '${rootSpecifier}';
|
|
|
33
33
|
const result = renderComponent('${moduleSpecifierToKebabCase(rootSpecifier)}', Ctor, props || {});
|
|
34
34
|
|
|
35
35
|
// 3. relay results
|
|
36
|
-
globalThis.
|
|
36
|
+
globalThis.resolver({ result, props, markup });
|
|
37
37
|
})()`;
|
|
38
38
|
}
|
|
39
39
|
export default class LwcSsrModuleProvider {
|
|
@@ -50,7 +50,8 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
50
50
|
const ssrProps = {};
|
|
51
51
|
let ssrLinks = '';
|
|
52
52
|
await Promise.all(ssrModules.map(({ specifier, tagName, props, startOffset, endOffset }) => {
|
|
53
|
-
return ssrElement({ specifier, props }, moduleBundler, viewContext)
|
|
53
|
+
return ssrElement({ specifier, props }, moduleBundler, viewContext)
|
|
54
|
+
.then(({ html, props, markup: { links = [] } = { links: [] } }) => {
|
|
54
55
|
if (props) {
|
|
55
56
|
// Add the props id to the HTML for the custom element
|
|
56
57
|
// eg: <some-cmp> -> <some-cmp data-lwr-props-id="1234">
|
|
@@ -64,10 +65,11 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
64
65
|
const relStr = rel ? ` rel="${rel}"` : '', asStr = as ? ` as="${as}"` : '', fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : '';
|
|
65
66
|
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>\n`;
|
|
66
67
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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);
|
|
71
73
|
});
|
|
72
74
|
}));
|
|
73
75
|
if (Object.keys(ssrProps).length) {
|
|
@@ -82,7 +84,7 @@ export default function lwcSsrViewTranformer(options, { moduleBundler }) {
|
|
|
82
84
|
stringBuilder.prependLeft(headIndex, ssrLinks);
|
|
83
85
|
}
|
|
84
86
|
else {
|
|
85
|
-
|
|
87
|
+
logger.error('Adding links during server-side rendering failed. Could not find the </head> tag.');
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
logger.verbose('lwcSsrViewTranformer response', stringBuilder);
|
|
@@ -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,7 +1,6 @@
|
|
|
1
1
|
import { PageDataResponse, SsrRequestContext } from '@lwrjs/types';
|
|
2
2
|
interface SandboxResults extends PageDataResponse {
|
|
3
3
|
result?: string;
|
|
4
|
-
error?: string;
|
|
5
4
|
}
|
|
6
5
|
export default function runCode(codes: string[], context: SsrRequestContext): Promise<SandboxResults>;
|
|
7
6
|
export {};
|
|
@@ -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,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, markup };
|
|
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.8.
|
|
7
|
+
"version": "0.8.1",
|
|
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.8.1",
|
|
38
|
+
"@lwrjs/shared-utils": "0.8.1",
|
|
39
|
+
"node-fetch": "^2.6.1"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"@lwrjs/types": "0.8.
|
|
42
|
+
"@lwrjs/types": "0.8.1"
|
|
41
43
|
},
|
|
42
44
|
"engines": {
|
|
43
45
|
"node": ">=14.15.4 <19"
|
|
44
46
|
},
|
|
45
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "171c43556c5624849c8ee6b61ef6de5b65630e38"
|
|
46
48
|
}
|