@lwrjs/lwc-ssr 0.11.0-alpha.9 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/moduleProvider/index.cjs +14 -9
- package/build/cjs/utils/amd-utils.cjs +23 -12
- package/build/cjs/utils/sandbox-locker.cjs +3 -3
- package/build/cjs/utils/sandbox-worker.cjs +4 -3
- package/build/cjs/utils/sandbox.cjs +3 -3
- package/build/cjs/utils/ssr-element.cjs +12 -6
- package/build/cjs/utils/utils.cjs +34 -0
- package/build/cjs/viewProvider/index.cjs +35 -5
- package/build/cjs/viewTransformer/index.cjs +48 -38
- package/build/es/moduleProvider/index.js +14 -9
- package/build/es/utils/amd-utils.d.ts +2 -2
- package/build/es/utils/amd-utils.js +29 -13
- package/build/es/utils/sandbox-locker.d.ts +1 -1
- package/build/es/utils/sandbox-locker.js +5 -5
- package/build/es/utils/sandbox-worker.d.ts +1 -1
- package/build/es/utils/sandbox-worker.js +4 -3
- package/build/es/utils/sandbox.d.ts +1 -1
- package/build/es/utils/sandbox.js +3 -3
- package/build/es/utils/ssr-element.d.ts +2 -4
- package/build/es/utils/ssr-element.js +15 -6
- package/build/es/utils/utils.d.ts +3 -0
- package/build/es/utils/utils.js +20 -0
- package/build/es/viewProvider/index.js +41 -6
- package/build/es/viewTransformer/index.d.ts +1 -1
- package/build/es/viewTransformer/index.js +62 -52
- package/package.json +6 -6
|
@@ -40,14 +40,14 @@ import ${importName} from '${service}';`;
|
|
|
40
40
|
serviceCalls += `
|
|
41
41
|
|
|
42
42
|
globalThis.trace({
|
|
43
|
-
name: '${import_instrumentation.ViewSpan.
|
|
43
|
+
name: '${import_instrumentation.ViewSpan.BootstrapService}',
|
|
44
44
|
attributes: {
|
|
45
45
|
specifier: '${rootSpecifier}',
|
|
46
46
|
serviceSpecifier: '${service}',
|
|
47
47
|
}
|
|
48
48
|
}, () => {
|
|
49
49
|
try {
|
|
50
|
-
${importName}();
|
|
50
|
+
${importName}({ serverData });
|
|
51
51
|
} catch(e) {
|
|
52
52
|
const message = e.message || e;
|
|
53
53
|
// we need to re-throw with the service specifier in the error message
|
|
@@ -60,7 +60,15 @@ import { renderComponent } from '@lwc/engine-server';
|
|
|
60
60
|
import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
61
61
|
|
|
62
62
|
(async () => {
|
|
63
|
-
let result, props, markup, existingTaskCount;
|
|
63
|
+
let result, props, markup, serverData = globalThis.LWR?.serverData || {}, existingTaskCount;
|
|
64
|
+
// remove the LWR global properties before any customer code is run
|
|
65
|
+
if (globalThis.LWR?.define) {
|
|
66
|
+
// AMD: support dynamic imports in getServerData
|
|
67
|
+
globalThis.LWR = Object.freeze({ define: globalThis.LWR.define });
|
|
68
|
+
} else {
|
|
69
|
+
delete globalThis.LWR; // ESM
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
try {
|
|
65
73
|
// 1. setup page data
|
|
66
74
|
const context = globalThis.getContext();
|
|
@@ -80,10 +88,8 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
80
88
|
throw new Error('Error in "getServerData" for "${rootSpecifier}": ' + message);
|
|
81
89
|
}
|
|
82
90
|
});
|
|
83
|
-
|
|
84
91
|
props = data.props; // overwrite public props
|
|
85
|
-
|
|
86
|
-
Object.assign(globalThis.LWR.serverData, data.props); // add props to server data
|
|
92
|
+
Object.assign(serverData, data.props); // add props to server data
|
|
87
93
|
markup = data.markup;
|
|
88
94
|
}${serviceCalls}
|
|
89
95
|
|
|
@@ -101,8 +107,8 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
101
107
|
|
|
102
108
|
} catch(e) {
|
|
103
109
|
const message = e.message || e;
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
|
|
111
|
+
// add the LWC rendering stack
|
|
106
112
|
const error = e.wcStack ?
|
|
107
113
|
'An error occurred during server-side rendering for component stack: ' + e.wcStack + '. Error was: ' + message :
|
|
108
114
|
'An error occured during server-side rendering: ' + message;
|
|
@@ -114,7 +120,6 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
114
120
|
const currentTaskCount = process.getActiveResourcesInfo
|
|
115
121
|
? process.getActiveResourcesInfo().length
|
|
116
122
|
: 0;
|
|
117
|
-
|
|
118
123
|
if (currentTaskCount - existingTaskCount > 0) {
|
|
119
124
|
console.warn('[warn] async tasks encountered while server rendering "${rootSpecifier}"');
|
|
120
125
|
}
|
|
@@ -92,7 +92,7 @@ async function getCode(runtimeEnvironment, serverData, lwrVersion, bundleSpecifi
|
|
|
92
92
|
}
|
|
93
93
|
async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
|
|
94
94
|
if ((0, import_shared_utils.getFeatureFlags)().SSR_STATIC_BUNDLES) {
|
|
95
|
-
return buildBundle(specifier, moduleBundler, routes, runtimeEnvironment, runtimeParams);
|
|
95
|
+
return buildBundle(specifier, moduleBundler, routes, {...runtimeEnvironment, debug: false}, runtimeParams);
|
|
96
96
|
}
|
|
97
97
|
return bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams, {
|
|
98
98
|
appendExcludes: false,
|
|
@@ -102,27 +102,38 @@ async function getBundle(specifier, moduleBundler, routes, runtimeEnvironment, r
|
|
|
102
102
|
async function bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams, bundleConfigOverrides) {
|
|
103
103
|
return await moduleBundler.getModuleBundle({specifier}, runtimeEnvironment, runtimeParams, bundleConfigOverrides);
|
|
104
104
|
}
|
|
105
|
-
async function bundleImports(bundleCode, imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
105
|
+
async function bundleImports(bundleCode, dynamicImports = [], imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
106
106
|
for (const {specifier} of imports) {
|
|
107
107
|
if (!visited.has(specifier)) {
|
|
108
108
|
visited.add(specifier);
|
|
109
109
|
const {code, bundleRecord, version} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
bundleCode
|
|
110
|
+
const bundledCode = getBundledCode(runtimeEnvironment, specifier, version, code);
|
|
111
|
+
bundleCode = await bundleImports(bundledCode, bundleRecord.dynamicImports, bundleRecord.imports, visited, moduleBundler, runtimeEnvironment, runtimeParams) + bundleCode;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const {specifier} of dynamicImports) {
|
|
115
|
+
if (!visited.has(specifier)) {
|
|
116
|
+
visited.add(specifier);
|
|
117
|
+
const {code, version} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
118
|
+
bundleCode += getBundledCode(runtimeEnvironment, specifier, version, code);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
return bundleCode;
|
|
122
122
|
}
|
|
123
|
+
function getBundledCode(runtimeEnvironment, specifier, version, code) {
|
|
124
|
+
let bundledCode;
|
|
125
|
+
if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
|
|
126
|
+
const versionedSpecifier = (0, import_shared_utils.getSpecifier)({specifier, version});
|
|
127
|
+
const aliasCode = (0, import_shared_utils.createAmdAlias)(versionedSpecifier, specifier);
|
|
128
|
+
bundledCode = [code, aliasCode].filter(Boolean).join("");
|
|
129
|
+
} else {
|
|
130
|
+
bundledCode = code;
|
|
131
|
+
}
|
|
132
|
+
return bundledCode;
|
|
133
|
+
}
|
|
123
134
|
async function getBundleWithImports(specifier, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
124
135
|
const {code, bundleRecord} = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
125
|
-
return await bundleImports(code, bundleRecord.imports, new Set(["lwc", specifier]), moduleBundler, runtimeEnvironment, runtimeParams);
|
|
136
|
+
return await bundleImports(code, bundleRecord.dynamicImports, bundleRecord.imports, new Set(["lwc", specifier]), moduleBundler, runtimeEnvironment, runtimeParams);
|
|
126
137
|
}
|
|
127
138
|
async function buildBundle(ssrSpecifier, moduleBundler, routes, runtimeEnvironment, runtimeParams) {
|
|
128
139
|
const {rootSpecifier, route} = (0, import_identity.parseSpecifier)(ssrSpecifier, routes);
|
|
@@ -28,11 +28,10 @@ __export(exports, {
|
|
|
28
28
|
});
|
|
29
29
|
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
30
30
|
var import_near_membrane_node = __toModule(require("@locker/near-membrane-node"));
|
|
31
|
-
var import_node_fetch = __toModule(require("node-fetch"));
|
|
32
31
|
var import_crypto = __toModule(require("crypto"));
|
|
33
32
|
var import_url = __toModule(require("url"));
|
|
34
33
|
var import_utils = __toModule(require("./utils.cjs"));
|
|
35
|
-
function runCode(codes, context) {
|
|
34
|
+
function runCode(codes, context, host) {
|
|
36
35
|
return new Promise((resolve, reject) => {
|
|
37
36
|
let resolver;
|
|
38
37
|
const p = new Promise((r) => resolver = r);
|
|
@@ -46,9 +45,10 @@ function runCode(codes, context) {
|
|
|
46
45
|
crypto: import_crypto.webcrypto,
|
|
47
46
|
getContext,
|
|
48
47
|
trace,
|
|
49
|
-
fetch:
|
|
48
|
+
fetch: (0, import_utils.createFetchEndowment)(host),
|
|
50
49
|
resolver,
|
|
51
50
|
URL: import_url.URL,
|
|
51
|
+
URLSearchParams: import_url.URLSearchParams,
|
|
52
52
|
process,
|
|
53
53
|
setTimeout,
|
|
54
54
|
clearTimeout,
|
|
@@ -31,17 +31,18 @@ var import_utils = __toModule(require("./utils.cjs"));
|
|
|
31
31
|
var HEADER = "/* This module is generated and meant to be used in a Server context */";
|
|
32
32
|
var WORKER_CODE_SANDBOX_APIS = [
|
|
33
33
|
`const { parentPort, workerData } = require('worker_threads');`,
|
|
34
|
+
`globalThis.fetch = require('@lwrjs/lwc-ssr/viewTransformer').createFetchEndowment(workerData.host);`,
|
|
35
|
+
`delete workerData.host`,
|
|
34
36
|
`globalThis.getContext = () => workerData;`,
|
|
35
|
-
`globalThis.fetch = require('node-fetch');`,
|
|
36
37
|
`globalThis.crypto = require('crypto').webcrypto;`,
|
|
37
38
|
`globalThis.resolver = (...args) => parentPort.postMessage(...args);`,
|
|
38
39
|
`globalThis.trace = (id, fn) => fn()`
|
|
39
40
|
];
|
|
40
|
-
function runCode(codes, workerData) {
|
|
41
|
+
function runCode(codes, workerData, host) {
|
|
41
42
|
const time = (0, import_utils.getWatchdogTime)();
|
|
42
43
|
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join("\n");
|
|
43
44
|
return new Promise((resolve, reject) => {
|
|
44
|
-
const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData});
|
|
45
|
+
const worker = new import_worker_threads.Worker(workerCode, {eval: true, workerData: {...workerData, host}});
|
|
45
46
|
const timerId = (0, import_utils.startWatchdogTimer)(() => {
|
|
46
47
|
worker.terminate();
|
|
47
48
|
reject(new Error(`SSR timed out after ${time}ms`));
|
|
@@ -29,9 +29,9 @@ __export(exports, {
|
|
|
29
29
|
var import_sandbox_worker = __toModule(require("./sandbox-worker.cjs"));
|
|
30
30
|
var import_sandbox_locker = __toModule(require("./sandbox-locker.cjs"));
|
|
31
31
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
32
|
-
function runCode(codes, context) {
|
|
32
|
+
function runCode(codes, context, host) {
|
|
33
33
|
if ((0, import_shared_utils.getFeatureFlags)().SSR_SANDBOX_WORKER) {
|
|
34
|
-
return (0, import_sandbox_worker.default)(codes, context);
|
|
34
|
+
return (0, import_sandbox_worker.default)(codes, context, host);
|
|
35
35
|
}
|
|
36
|
-
return (0, import_sandbox_locker.default)(codes, context);
|
|
36
|
+
return (0, import_sandbox_locker.default)(codes, context, host);
|
|
37
37
|
}
|
|
@@ -29,9 +29,9 @@ __export(exports, {
|
|
|
29
29
|
var import_amd_utils = __toModule(require("./amd-utils.cjs"));
|
|
30
30
|
var import_sandbox = __toModule(require("./sandbox.cjs"));
|
|
31
31
|
var import_perf_hooks = __toModule(require("perf_hooks"));
|
|
32
|
-
var
|
|
32
|
+
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
33
33
|
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
34
|
-
var
|
|
34
|
+
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
35
35
|
var EMIT_WIRES = `globalThis.lwcRuntimeFlags = { ENABLE_WIRE_SYNC_EMIT: true };`;
|
|
36
36
|
async function ssrElement({
|
|
37
37
|
specifier,
|
|
@@ -55,9 +55,15 @@ async function ssrElement({
|
|
|
55
55
|
url: runtimeParams.url,
|
|
56
56
|
params: runtimeParams.params || {},
|
|
57
57
|
query: runtimeParams.query || {},
|
|
58
|
-
locale: runtimeParams.locale || runtimeEnvironment.defaultLocale,
|
|
58
|
+
locale: runtimeParams.locale || runtimeEnvironment.i18n.defaultLocale,
|
|
59
59
|
basePath: runtimeParams.basePath || runtimeEnvironment.basePath
|
|
60
60
|
};
|
|
61
|
+
const environment = {
|
|
62
|
+
SSR: true,
|
|
63
|
+
...(0, import_shared_utils.buildEnvironmentContext)(runtimeParams)
|
|
64
|
+
};
|
|
65
|
+
const environmentCode = `process.env = ${JSON.stringify(environment)}`;
|
|
66
|
+
const host = runtimeParams.host;
|
|
61
67
|
const startTime = import_perf_hooks.performance.now();
|
|
62
68
|
return (0, import_instrumentation.getTracer)().trace({
|
|
63
69
|
name: import_instrumentation.ViewSpan.ServerSideRender,
|
|
@@ -66,14 +72,14 @@ async function ssrElement({
|
|
|
66
72
|
}
|
|
67
73
|
}, async () => {
|
|
68
74
|
const {result, props, markup, cache, error} = format === "amd" ? await (0, import_sandbox.default)([
|
|
69
|
-
SSR_FLAG,
|
|
70
75
|
EMIT_WIRES,
|
|
76
|
+
environmentCode,
|
|
71
77
|
...await (0, import_amd_utils.getCode)(runtimeEnvironment, serverData, version.replace(/\./g, "_"), bundleSpecifier, bundleRecord.includedModules, resourceRegistry),
|
|
72
78
|
code
|
|
73
|
-
], context) : await (0, import_sandbox.default)([
|
|
79
|
+
], context, host) : await (0, import_sandbox.default)([EMIT_WIRES, environmentCode, code], context, host);
|
|
74
80
|
const endTime = import_perf_hooks.performance.now();
|
|
75
81
|
const timeDiff = endTime - startTime;
|
|
76
|
-
|
|
82
|
+
import_diagnostics.logger.info(`[Server-side Rendering] ${specifier} in ${Math.round(timeDiff)} ms`);
|
|
77
83
|
if (error)
|
|
78
84
|
throw new Error(error);
|
|
79
85
|
return {html: result, props, markup, cache};
|
|
@@ -1,17 +1,36 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
2
7
|
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
3
8
|
var __export = (target, all) => {
|
|
4
9
|
for (var name in all)
|
|
5
10
|
__defProp(target, name, {get: all[name], enumerable: true});
|
|
6
11
|
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
7
23
|
|
|
8
24
|
// packages/@lwrjs/lwc-ssr/src/utils/utils.ts
|
|
9
25
|
__markAsModule(exports);
|
|
10
26
|
__export(exports, {
|
|
27
|
+
createFetchEndowment: () => createFetchEndowment,
|
|
28
|
+
createSsrErrorMessage: () => createSsrErrorMessage,
|
|
11
29
|
getWatchdogTime: () => getWatchdogTime,
|
|
12
30
|
startWatchdogTimer: () => startWatchdogTimer,
|
|
13
31
|
stopWatchdogTimer: () => stopWatchdogTimer
|
|
14
32
|
});
|
|
33
|
+
var import_node_fetch = __toModule(require("node-fetch"));
|
|
15
34
|
var DEFAULT_SSR_TIMEOUT = 5e3;
|
|
16
35
|
function getWatchdogTime() {
|
|
17
36
|
const override = process.env.SSR_TIMEOUT;
|
|
@@ -23,3 +42,18 @@ function startWatchdogTimer(callback, time) {
|
|
|
23
42
|
function stopWatchdogTimer(timerId) {
|
|
24
43
|
clearTimeout(timerId);
|
|
25
44
|
}
|
|
45
|
+
function createFetchEndowment(host) {
|
|
46
|
+
if (!host) {
|
|
47
|
+
return import_node_fetch.default;
|
|
48
|
+
}
|
|
49
|
+
return (url, init) => {
|
|
50
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
51
|
+
if (urlStr.startsWith("/")) {
|
|
52
|
+
return (0, import_node_fetch.default)(host + url, init);
|
|
53
|
+
}
|
|
54
|
+
return (0, import_node_fetch.default)(url, init);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function createSsrErrorMessage(specifier, e) {
|
|
58
|
+
return `Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: ${e.message || e}`;
|
|
59
|
+
}
|
|
@@ -27,9 +27,12 @@ __export(exports, {
|
|
|
27
27
|
default: () => viewProvider_default
|
|
28
28
|
});
|
|
29
29
|
var import_base_view_provider = __toModule(require("@lwrjs/base-view-provider"));
|
|
30
|
+
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
31
|
+
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
30
32
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
31
33
|
var import_identity = __toModule(require("../identity.cjs"));
|
|
32
34
|
var import_ssr_element = __toModule(require("../utils/ssr-element.cjs"));
|
|
35
|
+
var import_utils = __toModule(require("../utils/utils.cjs"));
|
|
33
36
|
var LwcViewProvider = class extends import_base_view_provider.default {
|
|
34
37
|
constructor(pluginConfig, providerConfig) {
|
|
35
38
|
super();
|
|
@@ -56,11 +59,38 @@ var LwcViewProvider = class extends import_base_view_provider.default {
|
|
|
56
59
|
viewId,
|
|
57
60
|
render: async (runtimeParams) => {
|
|
58
61
|
const {moduleBundler, resourceRegistry, runtimeEnvironment} = this;
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const debug = runtimeParams.query?.debug !== void 0;
|
|
63
|
+
const element = (0, import_shared_utils.moduleSpecifierToKebabCase)(specifier);
|
|
64
|
+
return (0, import_instrumentation.getTracer)().trace({
|
|
65
|
+
name: import_instrumentation.ViewSpan.RenderPage,
|
|
66
|
+
attributes: {specifier}
|
|
67
|
+
}, async () => {
|
|
68
|
+
try {
|
|
69
|
+
const {html, props} = await (0, import_ssr_element.ssrElement)({specifier: `${import_identity.LWC_SSR_PREFIX}${viewId.id}/${specifier}`, props: {}}, moduleBundler, resourceRegistry, this.routes, {
|
|
70
|
+
runtimeEnvironment: {...runtimeEnvironment, debug},
|
|
71
|
+
runtimeParams
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
|
|
75
|
+
metadata: {serverData: props, customElements: [], assetReferences: []}
|
|
76
|
+
};
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (debug || (0, import_shared_utils.getFeatureFlags)().SSR_WITH_CSR_FALLBACK) {
|
|
79
|
+
const message = (0, import_utils.createSsrErrorMessage)(specifier, e);
|
|
80
|
+
import_diagnostics.logger.warn(message, e.stack);
|
|
81
|
+
return {
|
|
82
|
+
renderedView: `<${element} ${import_shared_utils.HYDRATE_DIRECTIVE}="${import_shared_utils.HYDRATE_CLIENT_VALUE}"></${element}>`,
|
|
83
|
+
metadata: {
|
|
84
|
+
serverDebug: {message: debug ? message : void 0},
|
|
85
|
+
customElements: [],
|
|
86
|
+
assetReferences: []
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
} else {
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
64
94
|
}
|
|
65
95
|
};
|
|
66
96
|
}
|
|
@@ -24,11 +24,16 @@ var __toModule = (module2) => {
|
|
|
24
24
|
// packages/@lwrjs/lwc-ssr/src/viewTransformer/index.ts
|
|
25
25
|
__markAsModule(exports);
|
|
26
26
|
__export(exports, {
|
|
27
|
+
createFetchEndowment: () => import_utils2.createFetchEndowment,
|
|
27
28
|
default: () => lwcSsrViewTransformer
|
|
28
29
|
});
|
|
30
|
+
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
31
|
+
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
29
32
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
30
33
|
var import_identity = __toModule(require("../identity.cjs"));
|
|
31
34
|
var import_ssr_element = __toModule(require("../utils/ssr-element.cjs"));
|
|
35
|
+
var import_utils = __toModule(require("../utils/utils.cjs"));
|
|
36
|
+
var import_utils2 = __toModule(require("../utils/utils.cjs"));
|
|
32
37
|
function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry}) {
|
|
33
38
|
const routes = [...config.routes, ...config.errorRoutes];
|
|
34
39
|
return {
|
|
@@ -38,8 +43,8 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
38
43
|
if (!viewContext.view.bootstrap?.ssr) {
|
|
39
44
|
return {};
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
import_diagnostics.logger.debug("[lwcSsrViewTransformer] link");
|
|
47
|
+
import_diagnostics.logger.verbose("[lwcSsrViewTransformer] link input", stringBuilder);
|
|
43
48
|
if (!metadata.serverData) {
|
|
44
49
|
metadata.serverData = {};
|
|
45
50
|
}
|
|
@@ -54,7 +59,7 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
54
59
|
const {startOffset, endOffset} = location;
|
|
55
60
|
stringBuilder.overwrite(startOffset, endOffset, `<${tagName}></${tagName}>`);
|
|
56
61
|
}
|
|
57
|
-
if (!isCsr && location) {
|
|
62
|
+
if (!isCsr && !props?.["lwc:external"] && location) {
|
|
58
63
|
const {startOffset, endOffset} = location;
|
|
59
64
|
const moduleSpecifier = (0, import_shared_utils.kebabCaseToModuleSpecifier)(tagName);
|
|
60
65
|
ssrModules.push({
|
|
@@ -81,41 +86,46 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
81
86
|
const hydrate = (0, import_shared_utils.isHydrateOnLoad)(rawProps);
|
|
82
87
|
const passProps = {...rawProps};
|
|
83
88
|
delete passProps[import_shared_utils.HYDRATE_DIRECTIVE];
|
|
84
|
-
return (0,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
return (0, import_instrumentation.getTracer)().trace({
|
|
90
|
+
name: import_instrumentation.ViewSpan.RenderIsland,
|
|
91
|
+
attributes: {specifier}
|
|
92
|
+
}, async () => {
|
|
93
|
+
return (0, import_ssr_element.ssrElement)({specifier: bootstrapSpecifier, props: passProps, serverData}, moduleBundler, resourceRegistry, routes, viewContext).then(({
|
|
94
|
+
html,
|
|
95
|
+
props = {},
|
|
96
|
+
markup: {links = []} = {links: []},
|
|
97
|
+
cache: {ttl} = {}
|
|
98
|
+
}) => {
|
|
99
|
+
pageTtl = (0, import_shared_utils.shortestTtl)(ttl, pageTtl);
|
|
100
|
+
let propsAttr = "";
|
|
101
|
+
if (hydrate) {
|
|
102
|
+
const propsId = (0, import_identity.getPropsId)();
|
|
103
|
+
propsAttr = ` ${import_identity.SSR_PROPS_ATTR}="${propsId}"`;
|
|
104
|
+
serverData[propsId] = props;
|
|
105
|
+
}
|
|
106
|
+
const [, remain] = html.split(`<${tagName}`);
|
|
107
|
+
html = [`<${tagName}`, propsAttr, remain].join("");
|
|
108
|
+
links.forEach(({href, rel, as, fetchpriority}) => {
|
|
109
|
+
const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
|
|
110
|
+
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>
|
|
102
111
|
`;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
});
|
|
113
|
+
stringBuilder.overwrite(startOffset, endOffset, html);
|
|
114
|
+
}).catch((err) => {
|
|
115
|
+
if (debug || (0, import_shared_utils.getFeatureFlags)().SSR_WITH_CSR_FALLBACK) {
|
|
116
|
+
customElements[index].props === void 0 ? customElements[index].props = {
|
|
117
|
+
[import_shared_utils.HYDRATE_DIRECTIVE]: import_shared_utils.HYDRATE_CLIENT_VALUE
|
|
118
|
+
} : customElements[index].props[import_shared_utils.HYDRATE_DIRECTIVE] = import_shared_utils.HYDRATE_CLIENT_VALUE;
|
|
119
|
+
const errMessage = (0, import_utils.createSsrErrorMessage)(specifier, err);
|
|
120
|
+
import_diagnostics.logger.warn(errMessage, err.stack);
|
|
121
|
+
if (debug) {
|
|
122
|
+
debugMessage = errMessage;
|
|
123
|
+
serverDebug.message = debugMessage;
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
throw err;
|
|
115
127
|
}
|
|
116
|
-
}
|
|
117
|
-
throw err;
|
|
118
|
-
}
|
|
128
|
+
});
|
|
119
129
|
});
|
|
120
130
|
}));
|
|
121
131
|
if (ssrLinks) {
|
|
@@ -123,10 +133,10 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
123
133
|
if (headIndex >= 0) {
|
|
124
134
|
stringBuilder.prependLeft(headIndex, ssrLinks);
|
|
125
135
|
} else {
|
|
126
|
-
|
|
136
|
+
import_diagnostics.logger.error("Adding links during server-side rendering failed. Could not find the </head> tag.");
|
|
127
137
|
}
|
|
128
138
|
}
|
|
129
|
-
|
|
139
|
+
import_diagnostics.logger.verbose("lwcSsrViewTransformer response", stringBuilder);
|
|
130
140
|
return {cache: {ttl: pageTtl}};
|
|
131
141
|
}
|
|
132
142
|
};
|
|
@@ -23,14 +23,14 @@ export function createSsrBootstrapModule(rootSpecifier, services) {
|
|
|
23
23
|
serviceImports += `\nimport ${importName} from '${service}';`;
|
|
24
24
|
serviceCalls += `\n
|
|
25
25
|
globalThis.trace({
|
|
26
|
-
name: '${ViewSpan.
|
|
26
|
+
name: '${ViewSpan.BootstrapService}',
|
|
27
27
|
attributes: {
|
|
28
28
|
specifier: '${rootSpecifier}',
|
|
29
29
|
serviceSpecifier: '${service}',
|
|
30
30
|
}
|
|
31
31
|
}, () => {
|
|
32
32
|
try {
|
|
33
|
-
${importName}();
|
|
33
|
+
${importName}({ serverData });
|
|
34
34
|
} catch(e) {
|
|
35
35
|
const message = e.message || e;
|
|
36
36
|
// we need to re-throw with the service specifier in the error message
|
|
@@ -43,7 +43,15 @@ import { renderComponent } from '@lwc/engine-server';
|
|
|
43
43
|
import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
44
44
|
|
|
45
45
|
(async () => {
|
|
46
|
-
let result, props, markup, existingTaskCount;
|
|
46
|
+
let result, props, markup, serverData = globalThis.LWR?.serverData || {}, existingTaskCount;
|
|
47
|
+
// remove the LWR global properties before any customer code is run
|
|
48
|
+
if (globalThis.LWR?.define) {
|
|
49
|
+
// AMD: support dynamic imports in getServerData
|
|
50
|
+
globalThis.LWR = Object.freeze({ define: globalThis.LWR.define });
|
|
51
|
+
} else {
|
|
52
|
+
delete globalThis.LWR; // ESM
|
|
53
|
+
}
|
|
54
|
+
|
|
47
55
|
try {
|
|
48
56
|
// 1. setup page data
|
|
49
57
|
const context = globalThis.getContext();
|
|
@@ -63,10 +71,8 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
63
71
|
throw new Error('Error in "getServerData" for "${rootSpecifier}": ' + message);
|
|
64
72
|
}
|
|
65
73
|
});
|
|
66
|
-
|
|
67
74
|
props = data.props; // overwrite public props
|
|
68
|
-
|
|
69
|
-
Object.assign(globalThis.LWR.serverData, data.props); // add props to server data
|
|
75
|
+
Object.assign(serverData, data.props); // add props to server data
|
|
70
76
|
markup = data.markup;
|
|
71
77
|
}${serviceCalls}
|
|
72
78
|
|
|
@@ -84,8 +90,8 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
84
90
|
|
|
85
91
|
} catch(e) {
|
|
86
92
|
const message = e.message || e;
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
|
|
94
|
+
// add the LWC rendering stack
|
|
89
95
|
const error = e.wcStack ?
|
|
90
96
|
'An error occurred during server-side rendering for component stack: ' + e.wcStack + '. Error was: ' + message :
|
|
91
97
|
'An error occured during server-side rendering: ' + message;
|
|
@@ -97,7 +103,6 @@ import Ctor, * as rootComponent from '${rootSpecifier}';${serviceImports}
|
|
|
97
103
|
const currentTaskCount = process.getActiveResourcesInfo
|
|
98
104
|
? process.getActiveResourcesInfo().length
|
|
99
105
|
: 0;
|
|
100
|
-
|
|
101
106
|
if (currentTaskCount - existingTaskCount > 0) {
|
|
102
107
|
console.warn('[warn] async tasks encountered while server rendering "${rootSpecifier}"');
|
|
103
108
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BundleDefinition,
|
|
1
|
+
import type { BundleDefinition, PublicModuleBundler, PublicResourceRegistry, RuntimeEnvironment, RuntimeParams, ServerData } from '@lwrjs/types';
|
|
2
2
|
import type { Route } from '../identity.js';
|
|
3
|
-
export declare function getCode(runtimeEnvironment: RuntimeEnvironment, serverData:
|
|
3
|
+
export declare function getCode(runtimeEnvironment: RuntimeEnvironment, serverData: ServerData, lwrVersion: string, bundleSpecifier: string, includedModules: string[], resourceRegistry: PublicResourceRegistry): Promise<string[]>;
|
|
4
4
|
type PartialBundleDefinition = Pick<BundleDefinition, 'bundleRecord' | 'code' | 'specifier' | 'version'>;
|
|
5
5
|
export declare function getBundle(specifier: string, // e.g. "@lwrjs/lwc-ssr/home/root/component"
|
|
6
6
|
moduleBundler: PublicModuleBundler, routes: Route[], runtimeEnvironment: RuntimeEnvironment, runtimeParams: RuntimeParams): Promise<PartialBundleDefinition>;
|
|
@@ -77,7 +77,9 @@ export async function getBundle(specifier, // e.g. "@lwrjs/lwc-ssr/home/root/com
|
|
|
77
77
|
moduleBundler, routes, runtimeEnvironment, runtimeParams) {
|
|
78
78
|
if (getFeatureFlags().SSR_STATIC_BUNDLES) {
|
|
79
79
|
// concatenate existing bundles SSGed at build time
|
|
80
|
-
return buildBundle(specifier, moduleBundler, routes,
|
|
80
|
+
return buildBundle(specifier, moduleBundler, routes,
|
|
81
|
+
// debug: false needed to force SSR to not use debug bundles
|
|
82
|
+
{ ...runtimeEnvironment, debug: false }, runtimeParams);
|
|
81
83
|
}
|
|
82
84
|
// create a new SSR bundle
|
|
83
85
|
// "lwc" is aliased as "@lwc/engine-server" in the AMD worker code
|
|
@@ -90,31 +92,45 @@ async function bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParam
|
|
|
90
92
|
return await moduleBundler.getModuleBundle({ specifier }, runtimeEnvironment, runtimeParams, bundleConfigOverrides);
|
|
91
93
|
}
|
|
92
94
|
// Recursively bundle the static imports of a root bundle into a single bundle
|
|
93
|
-
async function bundleImports(bundleCode, imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
95
|
+
async function bundleImports(bundleCode, dynamicImports = [], imports = [], visited, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
94
96
|
for (const { specifier } of imports) {
|
|
95
97
|
if (!visited.has(specifier)) {
|
|
96
98
|
visited.add(specifier);
|
|
97
99
|
// eslint-disable-next-line no-await-in-loop
|
|
98
100
|
const { code, bundleRecord, version } = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
99
|
-
|
|
100
|
-
if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
|
|
101
|
-
const versionedSpecifier = getSpecifier({ specifier, version });
|
|
102
|
-
const aliasCode = createAmdAlias(versionedSpecifier, specifier);
|
|
103
|
-
bundledCode = [code, aliasCode].filter(Boolean).join('');
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
bundledCode = code;
|
|
107
|
-
}
|
|
101
|
+
const bundledCode = getBundledCode(runtimeEnvironment, specifier, version, code);
|
|
108
102
|
bundleCode =
|
|
109
103
|
// eslint-disable-next-line no-await-in-loop
|
|
110
|
-
(await bundleImports(bundledCode, bundleRecord.imports, visited, moduleBundler, runtimeEnvironment, runtimeParams)) + bundleCode;
|
|
104
|
+
(await bundleImports(bundledCode, bundleRecord.dynamicImports, bundleRecord.imports, visited, moduleBundler, runtimeEnvironment, runtimeParams)) + bundleCode;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Pull in one level of dynamic imports
|
|
108
|
+
for (const { specifier } of dynamicImports) {
|
|
109
|
+
if (!visited.has(specifier)) {
|
|
110
|
+
visited.add(specifier);
|
|
111
|
+
// eslint-disable-next-line no-await-in-loop
|
|
112
|
+
const { code, version } = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
113
|
+
// Add Dynamic Code
|
|
114
|
+
bundleCode += getBundledCode(runtimeEnvironment, specifier, version, code);
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
return bundleCode;
|
|
114
118
|
}
|
|
119
|
+
function getBundledCode(runtimeEnvironment, specifier, version, code) {
|
|
120
|
+
let bundledCode;
|
|
121
|
+
if (runtimeEnvironment.featureFlags?.EXPERIMENTAL_UNVERSIONED_ALIASES) {
|
|
122
|
+
const versionedSpecifier = getSpecifier({ specifier, version });
|
|
123
|
+
const aliasCode = createAmdAlias(versionedSpecifier, specifier);
|
|
124
|
+
bundledCode = [code, aliasCode].filter(Boolean).join('');
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
bundledCode = code;
|
|
128
|
+
}
|
|
129
|
+
return bundledCode;
|
|
130
|
+
}
|
|
115
131
|
async function getBundleWithImports(specifier, moduleBundler, runtimeEnvironment, runtimeParams) {
|
|
116
132
|
const { code, bundleRecord } = await bundle(specifier, moduleBundler, runtimeEnvironment, runtimeParams);
|
|
117
|
-
return await bundleImports(code, bundleRecord.imports, new Set(['lwc', specifier]), // visited (lwc is excluded)
|
|
133
|
+
return await bundleImports(code, bundleRecord.dynamicImports, bundleRecord.imports, new Set(['lwc', specifier]), // visited (lwc is excluded)
|
|
118
134
|
moduleBundler, runtimeEnvironment, runtimeParams);
|
|
119
135
|
}
|
|
120
136
|
// Build a SSR bundle for a root component by concatenating:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SsrRequestContext } from '@lwrjs/types';
|
|
2
2
|
import type { SandboxResults } from './sandbox.js';
|
|
3
|
-
export default function runCode(codes: string[], context: SsrRequestContext): Promise<SandboxResults>;
|
|
3
|
+
export default function runCode(codes: string[], context: SsrRequestContext, host?: string): Promise<SandboxResults>;
|
|
4
4
|
//# sourceMappingURL=sandbox-locker.d.ts.map
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { getTracer } from '@lwrjs/instrumentation';
|
|
2
2
|
import createVirtualEnvironment from '@locker/near-membrane-node';
|
|
3
|
-
import fetch from 'node-fetch';
|
|
4
3
|
import { webcrypto as crypto } from 'crypto';
|
|
5
|
-
import { URL } from 'url';
|
|
6
|
-
import { getWatchdogTime, startWatchdogTimer, stopWatchdogTimer } from './utils.js';
|
|
7
|
-
export default function runCode(codes, context) {
|
|
4
|
+
import { URL, URLSearchParams } from 'url';
|
|
5
|
+
import { createFetchEndowment, getWatchdogTime, startWatchdogTimer, stopWatchdogTimer } from './utils.js';
|
|
6
|
+
export default function runCode(codes, context, host) {
|
|
8
7
|
return new Promise((resolve, reject) => {
|
|
9
8
|
let resolver;
|
|
10
9
|
const p = new Promise((r) => (resolver = r));
|
|
@@ -18,9 +17,10 @@ export default function runCode(codes, context) {
|
|
|
18
17
|
crypto,
|
|
19
18
|
getContext,
|
|
20
19
|
trace,
|
|
21
|
-
fetch,
|
|
20
|
+
fetch: createFetchEndowment(host),
|
|
22
21
|
resolver,
|
|
23
22
|
URL,
|
|
23
|
+
URLSearchParams,
|
|
24
24
|
// for AMD loader ModuleRegistry
|
|
25
25
|
process,
|
|
26
26
|
setTimeout,
|
|
@@ -5,5 +5,5 @@ import type { SandboxResults } from './sandbox.js';
|
|
|
5
5
|
* @param codes - Code strings which SSR a root component
|
|
6
6
|
* @returns a promise to the SSRed code string, or an error message
|
|
7
7
|
*/
|
|
8
|
-
export default function runCode(codes: string[], workerData: SsrRequestContext): Promise<SandboxResults>;
|
|
8
|
+
export default function runCode(codes: string[], workerData: SsrRequestContext, host?: string): Promise<SandboxResults>;
|
|
9
9
|
//# sourceMappingURL=sandbox-worker.d.ts.map
|
|
@@ -14,8 +14,9 @@ const HEADER = '/* This module is generated and meant to be used in a Server con
|
|
|
14
14
|
*/
|
|
15
15
|
const WORKER_CODE_SANDBOX_APIS = [
|
|
16
16
|
`const { parentPort, workerData } = require('worker_threads');`,
|
|
17
|
+
`globalThis.fetch = require('@lwrjs/lwc-ssr/viewTransformer').createFetchEndowment(workerData.host);`,
|
|
18
|
+
`delete workerData.host`,
|
|
17
19
|
`globalThis.getContext = () => workerData;`,
|
|
18
|
-
`globalThis.fetch = require('node-fetch');`,
|
|
19
20
|
`globalThis.crypto = require('crypto').webcrypto;`,
|
|
20
21
|
`globalThis.resolver = (...args) => parentPort.postMessage(...args);`,
|
|
21
22
|
// TODO: implement tracing with worker thread
|
|
@@ -26,11 +27,11 @@ const WORKER_CODE_SANDBOX_APIS = [
|
|
|
26
27
|
* @param codes - Code strings which SSR a root component
|
|
27
28
|
* @returns a promise to the SSRed code string, or an error message
|
|
28
29
|
*/
|
|
29
|
-
export default function runCode(codes, workerData) {
|
|
30
|
+
export default function runCode(codes, workerData, host) {
|
|
30
31
|
const time = getWatchdogTime();
|
|
31
32
|
const workerCode = [HEADER, ...WORKER_CODE_SANDBOX_APIS, ...codes].join('\n');
|
|
32
33
|
return new Promise((resolve, reject) => {
|
|
33
|
-
const worker = new Worker(workerCode, { eval: true, workerData });
|
|
34
|
+
const worker = new Worker(workerCode, { eval: true, workerData: { ...workerData, host } });
|
|
34
35
|
const timerId = startWatchdogTimer(() => {
|
|
35
36
|
worker.terminate();
|
|
36
37
|
reject(new Error(`SSR timed out after ${time}ms`));
|
|
@@ -3,5 +3,5 @@ export interface SandboxResults extends SsrDataResponse {
|
|
|
3
3
|
result?: string;
|
|
4
4
|
error?: string;
|
|
5
5
|
}
|
|
6
|
-
export default function runCode(codes: string[], context: SsrRequestContext): Promise<SandboxResults>;
|
|
6
|
+
export default function runCode(codes: string[], context: SsrRequestContext, host?: string): Promise<SandboxResults>;
|
|
7
7
|
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import runCodeOnWorker from './sandbox-worker.js';
|
|
2
2
|
import runCodeOnLocker from './sandbox-locker.js';
|
|
3
3
|
import { getFeatureFlags } from '@lwrjs/shared-utils';
|
|
4
|
-
export default function runCode(codes, context) {
|
|
4
|
+
export default function runCode(codes, context, host) {
|
|
5
5
|
if (getFeatureFlags().SSR_SANDBOX_WORKER) {
|
|
6
|
-
return runCodeOnWorker(codes, context);
|
|
6
|
+
return runCodeOnWorker(codes, context, host);
|
|
7
7
|
}
|
|
8
8
|
// Default to use locker because it works rolled up in MRT
|
|
9
|
-
return runCodeOnLocker(codes, context);
|
|
9
|
+
return runCodeOnLocker(codes, context, host);
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=sandbox.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Json, PublicModuleBundler, PublicResourceRegistry, SsrDataResponse, ViewTransformPluginContext } from '@lwrjs/types';
|
|
1
|
+
import type { Json, PublicModuleBundler, PublicResourceRegistry, ServerData, SsrDataResponse, ViewTransformPluginContext } from '@lwrjs/types';
|
|
2
2
|
import type { Route } from '../identity.js';
|
|
3
3
|
interface SsrResults extends SsrDataResponse {
|
|
4
4
|
html: string;
|
|
@@ -16,9 +16,7 @@ export declare function ssrElement({ specifier, props: templateProps, serverData
|
|
|
16
16
|
props: {
|
|
17
17
|
[prop: string]: Json;
|
|
18
18
|
};
|
|
19
|
-
serverData?:
|
|
20
|
-
[prop: string]: Json;
|
|
21
|
-
};
|
|
19
|
+
serverData?: ServerData;
|
|
22
20
|
}, moduleBundler: PublicModuleBundler, resourceRegistry: PublicResourceRegistry, routes: Route[], { runtimeEnvironment, runtimeParams }: ViewTransformPluginContext): Promise<SsrResults>;
|
|
23
21
|
export {};
|
|
24
22
|
//# sourceMappingURL=ssr-element.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getBundle, getCode } from './amd-utils.js';
|
|
2
2
|
import runCode from './sandbox.js';
|
|
3
3
|
import { performance } from 'perf_hooks';
|
|
4
|
-
import { logger } from '@lwrjs/
|
|
4
|
+
import { logger } from '@lwrjs/diagnostics';
|
|
5
5
|
import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
|
|
6
|
-
|
|
6
|
+
import { buildEnvironmentContext } from '@lwrjs/shared-utils';
|
|
7
7
|
const EMIT_WIRES = `globalThis.lwcRuntimeFlags = { ENABLE_WIRE_SYNC_EMIT: true };`; // Invoke wire adapters immediately after a component is connected
|
|
8
8
|
/**
|
|
9
9
|
* Create a bundle for the given SSR module and run the code in a sandbox.
|
|
@@ -34,9 +34,18 @@ export async function ssrElement({ specifier, props: templateProps, serverData =
|
|
|
34
34
|
url: runtimeParams.url,
|
|
35
35
|
params: runtimeParams.params || {},
|
|
36
36
|
query: runtimeParams.query || {},
|
|
37
|
-
locale: runtimeParams.locale || runtimeEnvironment.defaultLocale,
|
|
37
|
+
locale: runtimeParams.locale || runtimeEnvironment.i18n.defaultLocale,
|
|
38
38
|
basePath: runtimeParams.basePath || runtimeEnvironment.basePath,
|
|
39
39
|
};
|
|
40
|
+
const environment = {
|
|
41
|
+
// Used for import.meta.env.SSR
|
|
42
|
+
// Note: SSR is always true because this script is executed on the server
|
|
43
|
+
SSR: true,
|
|
44
|
+
// Used by `lwr/environment`
|
|
45
|
+
...buildEnvironmentContext(runtimeParams),
|
|
46
|
+
};
|
|
47
|
+
const environmentCode = `process.env = ${JSON.stringify(environment)}`;
|
|
48
|
+
const host = runtimeParams.host;
|
|
40
49
|
// Get the SSR string and properties bag
|
|
41
50
|
const startTime = performance.now();
|
|
42
51
|
return getTracer().trace({
|
|
@@ -47,12 +56,12 @@ export async function ssrElement({ specifier, props: templateProps, serverData =
|
|
|
47
56
|
}, async () => {
|
|
48
57
|
const { result, props, markup, cache, error } = format === 'amd'
|
|
49
58
|
? await runCode([
|
|
50
|
-
SSR_FLAG,
|
|
51
59
|
EMIT_WIRES,
|
|
60
|
+
environmentCode,
|
|
52
61
|
...(await getCode(runtimeEnvironment, serverData, version.replace(/\./g, '_'), bundleSpecifier, bundleRecord.includedModules, resourceRegistry)),
|
|
53
62
|
code,
|
|
54
|
-
], context)
|
|
55
|
-
: await runCode([
|
|
63
|
+
], context, host)
|
|
64
|
+
: await runCode([EMIT_WIRES, environmentCode, code], context, host);
|
|
56
65
|
const endTime = performance.now();
|
|
57
66
|
const timeDiff = endTime - startTime;
|
|
58
67
|
logger.info(`[Server-side Rendering] ${specifier} in ${Math.round(timeDiff)} ms`);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { Response, RequestInfo, RequestInit } from 'node-fetch';
|
|
1
2
|
export declare function getWatchdogTime(): number;
|
|
2
3
|
export declare function startWatchdogTimer(callback: Function, time: number): number;
|
|
3
4
|
export declare function stopWatchdogTimer(timerId: number): void;
|
|
5
|
+
export declare function createFetchEndowment(host?: string): (url: RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
6
|
+
export declare function createSsrErrorMessage(specifier: string, e: Error): string;
|
|
4
7
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/es/utils/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
1
2
|
const DEFAULT_SSR_TIMEOUT = 5000; // 5 seconds, override with process.env.SSR_TIMEOUT
|
|
2
3
|
export function getWatchdogTime() {
|
|
3
4
|
const override = process.env.SSR_TIMEOUT;
|
|
@@ -9,4 +10,23 @@ export function startWatchdogTimer(callback, time) {
|
|
|
9
10
|
export function stopWatchdogTimer(timerId) {
|
|
10
11
|
clearTimeout(timerId);
|
|
11
12
|
}
|
|
13
|
+
export function createFetchEndowment(host) {
|
|
14
|
+
if (!host) {
|
|
15
|
+
// never proxy relative URLs
|
|
16
|
+
return fetch;
|
|
17
|
+
}
|
|
18
|
+
return (url, init) => {
|
|
19
|
+
// handle all stringable types, eg: URL
|
|
20
|
+
const urlStr = typeof url === 'string' ? url : url.toString();
|
|
21
|
+
if (urlStr.startsWith('/')) {
|
|
22
|
+
// proxy relative URLs through the given host
|
|
23
|
+
return fetch(host + url, init);
|
|
24
|
+
}
|
|
25
|
+
// carry on
|
|
26
|
+
return fetch(url, init);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function createSsrErrorMessage(specifier, e) {
|
|
30
|
+
return `Server-side rendering for "${specifier}" failed. Falling back to client-side rendering. Reason: ${e.message || e}`;
|
|
31
|
+
}
|
|
12
32
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import BaseViewProvider from '@lwrjs/base-view-provider';
|
|
2
|
-
import {
|
|
2
|
+
import { logger } from '@lwrjs/diagnostics';
|
|
3
|
+
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
4
|
+
import { HYDRATE_CLIENT_VALUE, HYDRATE_DIRECTIVE, getFeatureFlags, hashContent, isSpecifier, moduleSpecifierToKebabCase, slugify, } from '@lwrjs/shared-utils';
|
|
3
5
|
import { LWC_SSR_PREFIX } from '../identity.js';
|
|
4
6
|
import { ssrElement } from '../utils/ssr-element.js';
|
|
7
|
+
import { createSsrErrorMessage } from '../utils/utils.js';
|
|
5
8
|
export default class LwcViewProvider extends BaseViewProvider {
|
|
6
9
|
constructor(pluginConfig, providerConfig) {
|
|
7
10
|
super();
|
|
@@ -30,11 +33,43 @@ export default class LwcViewProvider extends BaseViewProvider {
|
|
|
30
33
|
render: async (runtimeParams) => {
|
|
31
34
|
// SSR the root component (without passing any public properties)
|
|
32
35
|
const { moduleBundler, resourceRegistry, runtimeEnvironment } = this;
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const debug = runtimeParams.query?.debug !== undefined;
|
|
37
|
+
const element = moduleSpecifierToKebabCase(specifier);
|
|
38
|
+
return getTracer().trace({
|
|
39
|
+
name: ViewSpan.RenderPage,
|
|
40
|
+
attributes: { specifier },
|
|
41
|
+
}, async () => {
|
|
42
|
+
try {
|
|
43
|
+
const { html, props } = await ssrElement({ specifier: `${LWC_SSR_PREFIX}${viewId.id}/${specifier}`, props: {} }, moduleBundler, resourceRegistry, this.routes, {
|
|
44
|
+
runtimeEnvironment: { ...runtimeEnvironment, debug },
|
|
45
|
+
runtimeParams,
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
// add "lwc:external" to the contentTemplate component to mark it as already processed
|
|
49
|
+
renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
|
|
50
|
+
metadata: { serverData: props, customElements: [], assetReferences: [] },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (debug || getFeatureFlags().SSR_WITH_CSR_FALLBACK) {
|
|
55
|
+
// fallback to CSR
|
|
56
|
+
const message = createSsrErrorMessage(specifier, e);
|
|
57
|
+
logger.warn(message, e.stack);
|
|
58
|
+
return {
|
|
59
|
+
renderedView: `<${element} ${HYDRATE_DIRECTIVE}="${HYDRATE_CLIENT_VALUE}"></${element}>`,
|
|
60
|
+
// send an error message to the client if debug mode is on
|
|
61
|
+
metadata: {
|
|
62
|
+
serverDebug: { message: debug ? message : undefined },
|
|
63
|
+
customElements: [],
|
|
64
|
+
assetReferences: [],
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
38
73
|
},
|
|
39
74
|
};
|
|
40
75
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProviderContext, ViewTransformPlugin } from '@lwrjs/types';
|
|
2
|
+
export { createFetchEndowment } from '../utils/utils.js';
|
|
2
3
|
interface SsrPluginOptions {
|
|
3
4
|
shareWorker?: boolean;
|
|
4
5
|
}
|
|
@@ -21,5 +22,4 @@ interface SsrPluginOptions {
|
|
|
21
22
|
* 5. During bootstrap on the client, the "lwr/init" module will hydrate ALL the custom elements on the page
|
|
22
23
|
*/
|
|
23
24
|
export default function lwcSsrViewTransformer(options: SsrPluginOptions, { config, moduleBundler, resourceRegistry }: ProviderContext): ViewTransformPlugin;
|
|
24
|
-
export {};
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logger } from '@lwrjs/diagnostics';
|
|
2
|
+
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
3
|
+
import { HYDRATE_CLIENT_VALUE, HYDRATE_DIRECTIVE, getFeatureFlags, isCsrIsland, isHydrateOnLoad, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
|
|
2
4
|
import { LWC_SSR_PREFIX, SSR_PROPS_ATTR, getPropsId } from '../identity.js';
|
|
3
5
|
import { ssrElement } from '../utils/ssr-element.js';
|
|
6
|
+
import { createSsrErrorMessage } from '../utils/utils.js';
|
|
7
|
+
export { createFetchEndowment } from '../utils/utils.js';
|
|
4
8
|
/**
|
|
5
9
|
* This is a view transformer run by the view registry during linking of a page document/route (configured in lwr.config.json[routes]).
|
|
6
10
|
* If the "ssr" bootstrap flag is on for the route, it will server-side render (SSR) each custom element found in the page HTML.
|
|
@@ -46,7 +50,8 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
|
|
|
46
50
|
const { startOffset, endOffset } = location;
|
|
47
51
|
stringBuilder.overwrite(startOffset, endOffset, `<${tagName}></${tagName}>`);
|
|
48
52
|
}
|
|
49
|
-
if (!isCsr && location) {
|
|
53
|
+
if (!isCsr && !props?.['lwc:external'] && location) {
|
|
54
|
+
// only SSR the custom elements which are NOT CSR islands or lwc:external
|
|
50
55
|
const { startOffset, endOffset } = location;
|
|
51
56
|
const moduleSpecifier = kebabCaseToModuleSpecifier(tagName);
|
|
52
57
|
ssrModules.push({
|
|
@@ -66,57 +71,62 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
|
|
|
66
71
|
const hydrate = isHydrateOnLoad(rawProps);
|
|
67
72
|
const passProps = { ...rawProps };
|
|
68
73
|
delete passProps[HYDRATE_DIRECTIVE];
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
propsAttr =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
74
|
+
return getTracer().trace({
|
|
75
|
+
name: ViewSpan.RenderIsland,
|
|
76
|
+
attributes: { specifier },
|
|
77
|
+
}, async () => {
|
|
78
|
+
return ssrElement({ specifier: bootstrapSpecifier, props: passProps, serverData }, moduleBundler, resourceRegistry, routes, viewContext)
|
|
79
|
+
.then(({ html, props = {}, markup: { links = [] } = { links: [] }, cache: { ttl } = {}, }) => {
|
|
80
|
+
// Keep track of the shortest TTL from all getServerData hooks
|
|
81
|
+
pageTtl = shortestTtl(ttl, pageTtl);
|
|
82
|
+
// Add the props id to the HTML for the custom element
|
|
83
|
+
// eg: <some-cmp> -> <some-cmp data-lwr-props-id="1234">
|
|
84
|
+
let propsAttr = '';
|
|
85
|
+
if (hydrate) {
|
|
86
|
+
// Only serialize props for custom elements that are to be hydrated
|
|
87
|
+
const propsId = getPropsId();
|
|
88
|
+
propsAttr = ` ${SSR_PROPS_ATTR}="${propsId}"`;
|
|
89
|
+
serverData[propsId] = props;
|
|
90
|
+
}
|
|
91
|
+
const [, remain] = html.split(`<${tagName}`);
|
|
92
|
+
html = [`<${tagName}`, propsAttr, remain].join('');
|
|
93
|
+
// Create HTML <link> strings for each item in the links array
|
|
94
|
+
links.forEach(({ href, rel, as, fetchpriority }) => {
|
|
95
|
+
const relStr = rel ? ` rel="${rel}"` : '', asStr = as ? ` as="${as}"` : '', fetchStr = fetchpriority
|
|
96
|
+
? ` fetchpriority="${fetchpriority}"`
|
|
97
|
+
: '';
|
|
98
|
+
ssrLinks += `<link href="${href}"${relStr}${asStr}${fetchStr}>\n`;
|
|
99
|
+
});
|
|
100
|
+
// Overwrite the custom element with the SSRed component string
|
|
101
|
+
stringBuilder.overwrite(startOffset, endOffset, html);
|
|
102
|
+
})
|
|
103
|
+
.catch((err) => {
|
|
104
|
+
// fallback to CSR in debug mode or if enabled
|
|
105
|
+
if (debug || getFeatureFlags().SSR_WITH_CSR_FALLBACK) {
|
|
106
|
+
// Fallback to CSR by adding lwr:hydrate="client-only" to the custom element
|
|
107
|
+
// This ENSURES the component's JavaScript gets sent to the client for CSRing
|
|
108
|
+
customElements[index].props === undefined
|
|
109
|
+
? (customElements[index].props = {
|
|
110
|
+
[HYDRATE_DIRECTIVE]: HYDRATE_CLIENT_VALUE,
|
|
111
|
+
})
|
|
112
|
+
: // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
113
|
+
// @ts-ignore - TS thinks that props may still be undefined
|
|
114
|
+
(customElements[index].props[HYDRATE_DIRECTIVE] =
|
|
115
|
+
HYDRATE_CLIENT_VALUE);
|
|
116
|
+
const errMessage = createSsrErrorMessage(specifier, err);
|
|
117
|
+
// log message w/ stack details
|
|
118
|
+
logger.warn(errMessage, err.stack);
|
|
119
|
+
// Inform the client of the failing modules w/o exposing any additional
|
|
120
|
+
// details (such as callstack) for security reasons
|
|
121
|
+
if (debug) {
|
|
122
|
+
debugMessage = errMessage;
|
|
123
|
+
serverDebug.message = debugMessage;
|
|
124
|
+
}
|
|
115
125
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
126
|
+
else {
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
120
130
|
});
|
|
121
131
|
}));
|
|
122
132
|
if (ssrLinks) {
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.11.0
|
|
7
|
+
"version": "0.11.0",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@locker/near-membrane-node": "^0.13.3",
|
|
46
|
-
"@lwrjs/diagnostics": "0.11.0
|
|
47
|
-
"@lwrjs/instrumentation": "0.11.0
|
|
48
|
-
"@lwrjs/shared-utils": "0.11.0
|
|
46
|
+
"@lwrjs/diagnostics": "0.11.0",
|
|
47
|
+
"@lwrjs/instrumentation": "0.11.0",
|
|
48
|
+
"@lwrjs/shared-utils": "0.11.0",
|
|
49
49
|
"node-fetch": "^2.6.8"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@lwrjs/types": "0.11.0
|
|
52
|
+
"@lwrjs/types": "0.11.0",
|
|
53
53
|
"jest": "^26.6.3",
|
|
54
54
|
"ts-jest": "^26.5.6"
|
|
55
55
|
},
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"volta": {
|
|
60
60
|
"extends": "../../../package.json"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "fbc883ea90a12672ce6f1adc2201144fda8762bd"
|
|
63
63
|
}
|