@lwrjs/lwc-ssr 0.17.2-alpha.9 → 0.18.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/dataViewTransformer/index.cjs +2 -1
- package/build/cjs/fetchController.cjs +24 -22
- package/build/cjs/moduleLoader.cjs +2 -3
- package/build/cjs/renderer.cjs +15 -14
- package/build/cjs/resourceProvider.cjs +94 -0
- package/build/cjs/utils.cjs +0 -52
- package/build/cjs/viewProvider/index.cjs +1 -2
- package/build/cjs/viewTransformer/index.cjs +1 -1
- package/build/es/dataViewTransformer/index.js +3 -2
- package/build/es/fetchController.d.ts +0 -2
- package/build/es/fetchController.js +92 -90
- package/build/es/moduleLoader.js +2 -3
- package/build/es/renderer.js +26 -19
- package/build/es/resourceProvider.d.ts +10 -0
- package/build/es/resourceProvider.js +80 -0
- package/build/es/serverBootstrapServices.js +3 -0
- package/build/es/utils.d.ts +1 -13
- package/build/es/utils.js +0 -66
- package/build/es/viewProvider/index.js +8 -4
- package/build/es/viewTransformer/index.js +4 -3
- package/build/scripts/register-lwc-style.js +5 -0
- package/package.cjs +9 -0
- package/package.json +26 -14
|
@@ -28,6 +28,7 @@ __export(exports, {
|
|
|
28
28
|
});
|
|
29
29
|
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
30
30
|
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
31
|
+
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
31
32
|
var import_utils = __toModule(require("../utils.cjs"));
|
|
32
33
|
var import_renderer = __toModule(require("../renderer.cjs"));
|
|
33
34
|
var NAME = "preload-data-transformer";
|
|
@@ -71,7 +72,7 @@ function preloadDataViewTransformer(_options, {config, moduleBundler, resourceRe
|
|
|
71
72
|
}
|
|
72
73
|
const {props, markup, cache: {ttl} = {ttl: void 0}} = result || {};
|
|
73
74
|
import_diagnostics.logger.verbose({label: NAME, message: "response", additionalInfo: props});
|
|
74
|
-
markup && (0,
|
|
75
|
+
markup && (0, import_shared_utils.addHeadMarkup)([result.markup], stringBuilder);
|
|
75
76
|
metadata.serverData = metadata.serverData || {};
|
|
76
77
|
Object.assign(metadata.serverData, props);
|
|
77
78
|
metadata.serverBundles = bundles ? new Set([...allBundles, ...bundles]) : allBundles;
|
|
@@ -30,13 +30,12 @@ var import_undici = __toModule(require("undici"));
|
|
|
30
30
|
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
31
31
|
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
32
32
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
33
|
-
var ROUTE_CORE_HEADER = "X-SFDC-Route-Core";
|
|
34
33
|
var CORE_CLIENTS = new Map();
|
|
35
34
|
var FetchController = class {
|
|
36
35
|
constructor(context) {
|
|
37
36
|
this.controlledFetch = (request, init) => {
|
|
38
37
|
if (this.killSwitchActivated) {
|
|
39
|
-
return this.handleAbortError(request,
|
|
38
|
+
return this.handleAbortError(request, "Kill switch was already enabled");
|
|
40
39
|
}
|
|
41
40
|
if (!this.abortController) {
|
|
42
41
|
this.abortController = new AbortController();
|
|
@@ -49,7 +48,8 @@ var FetchController = class {
|
|
|
49
48
|
};
|
|
50
49
|
const fetchFunction = this.noOpActivated ? this.fetchNoOp(request, updatedInit) : this.fetchEndowment(request, updatedInit);
|
|
51
50
|
const fetchPromise = fetchFunction.catch((error) => {
|
|
52
|
-
|
|
51
|
+
const errorMsg = error.message || error;
|
|
52
|
+
if (error && (errorMsg.startsWith("AbortError") || error?.stack.startsWith("AbortError"))) {
|
|
53
53
|
return this.handleAbortError(request, error);
|
|
54
54
|
} else {
|
|
55
55
|
throw error;
|
|
@@ -59,7 +59,7 @@ var FetchController = class {
|
|
|
59
59
|
};
|
|
60
60
|
this.activateKillSwitch = () => {
|
|
61
61
|
this.killSwitchActivated = true;
|
|
62
|
-
this.abortController?.abort();
|
|
62
|
+
this.abortController?.abort("AbortError: Kill switch enabled");
|
|
63
63
|
this.abortController = void 0;
|
|
64
64
|
};
|
|
65
65
|
this.deactivateKillSwitch = () => {
|
|
@@ -72,10 +72,9 @@ var FetchController = class {
|
|
|
72
72
|
this.noOpActivated = false;
|
|
73
73
|
};
|
|
74
74
|
this.setFetchRequestContext = (context) => {
|
|
75
|
-
const {abortController, host, headers,
|
|
75
|
+
const {abortController, host, headers, coreProxy} = context;
|
|
76
76
|
this.host = host;
|
|
77
77
|
this.headers = headers;
|
|
78
|
-
this.requestDepth = requestDepth;
|
|
79
78
|
this.coreProxy = coreProxy;
|
|
80
79
|
this.abortController = abortController;
|
|
81
80
|
};
|
|
@@ -85,7 +84,7 @@ var FetchController = class {
|
|
|
85
84
|
this.fetchEndowment = this.createFetchEndowment();
|
|
86
85
|
}
|
|
87
86
|
handleAbortError(request, error) {
|
|
88
|
-
const message =
|
|
87
|
+
const message = `${String(request)} request was killed. Either the request timed out or it was dispatched during SSR. Async processes are not supported during SSR. For more information, see: https://developer.salesforce.com/docs/platform/lwr/guide/lwr-configure-component-ssr.html.`;
|
|
89
88
|
import_diagnostics.logger.warn({label: `Server-side Rendering`, message}, error);
|
|
90
89
|
return Promise.resolve(new Response(message, {status: 500}));
|
|
91
90
|
}
|
|
@@ -94,30 +93,23 @@ var FetchController = class {
|
|
|
94
93
|
if (!init?.signal) {
|
|
95
94
|
resolve(this.handleAbortError(request, new Error("RequestInit was not setup as expected")));
|
|
96
95
|
} else if (init.signal.aborted) {
|
|
97
|
-
resolve(this.handleAbortError(request, new Error("Request was aborted")));
|
|
96
|
+
resolve(this.handleAbortError(request, new Error("Request was already aborted")));
|
|
98
97
|
} else {
|
|
99
98
|
const abortHandler = (err) => {
|
|
100
99
|
init?.signal?.removeEventListener("abort", abortHandler);
|
|
101
|
-
resolve(this.handleAbortError(request, err));
|
|
100
|
+
resolve(this.handleAbortError(request, new Error("Not allowed: Request was dispatched during SSR", {cause: err})));
|
|
102
101
|
};
|
|
103
102
|
init.signal.addEventListener("abort", abortHandler);
|
|
104
103
|
}
|
|
105
104
|
});
|
|
106
105
|
}
|
|
107
106
|
createFetchEndowment() {
|
|
108
|
-
return (request, init) => {
|
|
109
|
-
const {host: forwardedOrigin = "",
|
|
107
|
+
return (request, init = {}) => {
|
|
108
|
+
const {host: forwardedOrigin = "", coreProxy} = this;
|
|
110
109
|
const origin = coreProxy?.origin && coreProxy.origin.startsWith("http") ? coreProxy.origin : forwardedOrigin;
|
|
111
110
|
const {finalRequest, finalUrl} = this.getFinalRequest(request, origin);
|
|
112
|
-
const finalInit = {
|
|
113
|
-
...init,
|
|
114
|
-
headers: {
|
|
115
|
-
...init?.headers,
|
|
116
|
-
[import_shared_utils.REQUEST_DEPTH_HEADER]: String(requestDepth)
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
111
|
if (coreProxy || forwardedOrigin && finalUrl.startsWith(forwardedOrigin)) {
|
|
120
|
-
|
|
112
|
+
init.headers[import_shared_utils.ROUTE_CORE_HEADER] = "true";
|
|
121
113
|
}
|
|
122
114
|
const proxyStr = coreProxy ? JSON.stringify(coreProxy) : "none";
|
|
123
115
|
const hasCookies = this.headers && this.headers.Cookie ? "yes" : "no";
|
|
@@ -140,15 +132,25 @@ var FetchController = class {
|
|
|
140
132
|
span.setAttributes({statusCode: res.status});
|
|
141
133
|
return res;
|
|
142
134
|
};
|
|
135
|
+
const addErrorToSpan = (err) => {
|
|
136
|
+
span.setAttributes({error: (0, import_diagnostics.stringifyError)(err)});
|
|
137
|
+
};
|
|
138
|
+
init.headers = {...init.headers, ...(0, import_shared_utils.getTraceHeaders)({}, span)};
|
|
143
139
|
if (coreProxy) {
|
|
144
|
-
return this.fetchWithAgent(finalUrl,
|
|
140
|
+
return this.fetchWithAgent(finalUrl, init, forwardedOrigin, coreProxy, span).then((res) => addInfoToSpan(res)).catch((err) => {
|
|
145
141
|
const {finalRequest: cdnRequest, finalUrl: cdnUrl} = this.getFinalRequest(request, forwardedOrigin);
|
|
146
142
|
import_diagnostics.logger.warn(`Fetching data directly from Core failed, retrying through CDN: ${cdnUrl} Error is: ${err.message || err}`);
|
|
147
143
|
span.setAttributes({fetchType: "cdnFallback"});
|
|
148
|
-
return fetch(cdnRequest,
|
|
144
|
+
return fetch(cdnRequest, init).then((res) => addInfoToSpan(res)).catch((e) => {
|
|
145
|
+
addErrorToSpan(e);
|
|
146
|
+
throw e;
|
|
147
|
+
});
|
|
149
148
|
});
|
|
150
149
|
}
|
|
151
|
-
return fetch(finalRequest,
|
|
150
|
+
return fetch(finalRequest, init).then((res) => addInfoToSpan(res)).catch((e) => {
|
|
151
|
+
addErrorToSpan(e);
|
|
152
|
+
throw e;
|
|
153
|
+
});
|
|
152
154
|
});
|
|
153
155
|
};
|
|
154
156
|
}
|
|
@@ -41,7 +41,7 @@ function createModuleLoader(config, resourceRegistry, bundleRegistry, runtimeEnv
|
|
|
41
41
|
}
|
|
42
42
|
async function createAMDModuleLoader(config, resourceRegistry, bundleRegistry, runtimeEnvironment, runtimeParams, serverData, bootstrapConfig, abortController) {
|
|
43
43
|
const loaderConfig = (0, import_utils.getLoaderConfig)(BOOTSTRAP_SPECIFIER, config, runtimeParams, serverData);
|
|
44
|
-
const {context, controller} = createContext(loaderConfig, runtimeParams,
|
|
44
|
+
const {context, controller} = createContext(loaderConfig, runtimeParams, abortController);
|
|
45
45
|
const contextKeyMap = new Map(Object.keys(context).map((key) => [key, true]));
|
|
46
46
|
let run;
|
|
47
47
|
context.LWR.customInit = async (lwr) => {
|
|
@@ -218,10 +218,9 @@ function isValidResolveResponse(res) {
|
|
|
218
218
|
async function createESMModuleLoader() {
|
|
219
219
|
throw new Error("ESM support coming soon.");
|
|
220
220
|
}
|
|
221
|
-
function createContext(LWR, runtimeParams,
|
|
221
|
+
function createContext(LWR, runtimeParams, abortController) {
|
|
222
222
|
const fetchController = new import_fetchController.FetchController({
|
|
223
223
|
host: runtimeParams.host,
|
|
224
|
-
requestDepth: runtimeParams.requestDepth,
|
|
225
224
|
coreProxy: runtimeParams.coreProxy,
|
|
226
225
|
abortController
|
|
227
226
|
});
|
package/build/cjs/renderer.cjs
CHANGED
|
@@ -67,8 +67,9 @@ var Renderer = class {
|
|
|
67
67
|
const abortController = new AbortController();
|
|
68
68
|
const timeout = new Promise((_, reject) => {
|
|
69
69
|
timerId = setTimeout(() => {
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const message = import_diagnostics.descriptions.APPLICATION.SSR_TIMEOUT(route.id, (0, import_utils.getRenderTimeout)());
|
|
71
|
+
abortController.abort(`AbortError: ${message}`);
|
|
72
|
+
reject(new import_diagnostics.LwrApplicationError(message));
|
|
72
73
|
}, (0, import_utils.getRenderTimeout)());
|
|
73
74
|
});
|
|
74
75
|
result = await this.pendingRenders.execute(async () => {
|
|
@@ -229,13 +230,13 @@ var Renderer = class {
|
|
|
229
230
|
}
|
|
230
231
|
resetFetchController(fetchController, runtimeParams, route, abortController) {
|
|
231
232
|
fetchController.disableFetchKillSwitch();
|
|
233
|
+
const baseHeaders = {
|
|
234
|
+
[import_shared_utils.REQUEST_DEPTH_HEADER]: runtimeParams.requestDepth ?? "0",
|
|
235
|
+
...(0, import_shared_utils.getTraceHeaders)(runtimeParams)
|
|
236
|
+
};
|
|
232
237
|
fetchController.setFetchRequestContext({
|
|
233
238
|
host: runtimeParams.host,
|
|
234
|
-
|
|
235
|
-
headers: route.bootstrap.includeCookiesForSSR ? {
|
|
236
|
-
Cookie: runtimeParams.cookie,
|
|
237
|
-
"True-Client-IP": runtimeParams.trueClientIP
|
|
238
|
-
} : {"True-Client-IP": runtimeParams.trueClientIP},
|
|
239
|
+
headers: route.bootstrap.includeCookiesForSSR ? {Cookie: runtimeParams.cookie, ...baseHeaders} : baseHeaders,
|
|
239
240
|
coreProxy: runtimeParams.coreProxy,
|
|
240
241
|
abortController
|
|
241
242
|
});
|
|
@@ -267,14 +268,13 @@ function getServerData(component, context, serverData) {
|
|
|
267
268
|
return (0, import_instrumentation.getTracer)().trace({
|
|
268
269
|
name: import_instrumentation.ViewSpan.GetServerData,
|
|
269
270
|
attributes: {specifier: component.specifier}
|
|
270
|
-
}, async () => {
|
|
271
|
+
}, async (span) => {
|
|
271
272
|
try {
|
|
272
273
|
const data = await component.module.getServerData(context);
|
|
273
274
|
Object.assign(serverData, data.props);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
throw new import_diagnostics.LwrStatusError(void 0, code, location ? {location} : void 0);
|
|
275
|
+
if (data.warnings) {
|
|
276
|
+
const warnings = data.warnings.map((w) => (0, import_diagnostics.stringifyError)(w)).join(", ");
|
|
277
|
+
span.setAttributes({warnings});
|
|
278
278
|
}
|
|
279
279
|
return data;
|
|
280
280
|
} catch (e) {
|
|
@@ -289,14 +289,15 @@ function getServerData(component, context, serverData) {
|
|
|
289
289
|
});
|
|
290
290
|
}
|
|
291
291
|
async function renderToString(engine, component, props) {
|
|
292
|
+
const isSSRv2 = (0, import_shared_utils.getFeatureFlags)().SSR_COMPILER_ENABLED || false;
|
|
292
293
|
return (0, import_instrumentation.getTracer)().trace({
|
|
293
294
|
name: import_instrumentation.ViewSpan.RenderComponent,
|
|
294
|
-
attributes: {specifier: component.specifier}
|
|
295
|
+
attributes: {specifier: component.specifier, isSSRv2}
|
|
295
296
|
}, async () => {
|
|
296
297
|
try {
|
|
297
298
|
const elementName = (0, import_shared_utils.moduleSpecifierToKebabCase)(component.specifier);
|
|
298
299
|
const moduleDefault = component.module.default;
|
|
299
|
-
const html =
|
|
300
|
+
const html = isSSRv2 ? await engine.renderComponent(elementName, moduleDefault, props, elementName, false, "sync") : engine.renderComponent(elementName, moduleDefault, props);
|
|
300
301
|
return {html};
|
|
301
302
|
} catch (e) {
|
|
302
303
|
if (e instanceof import_diagnostics.LwrError)
|
|
@@ -0,0 +1,94 @@
|
|
|
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/resourceProvider.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
default: () => resourceProvider_default
|
|
28
|
+
});
|
|
29
|
+
var import_path = __toModule(require("path"));
|
|
30
|
+
var import_rollup = __toModule(require("rollup"));
|
|
31
|
+
var import_plugin_node_resolve = __toModule(require("@rollup/plugin-node-resolve"));
|
|
32
|
+
var import_plugin_terser = __toModule(require("@rollup/plugin-terser"));
|
|
33
|
+
var import_config = __toModule(require("@lwrjs/config"));
|
|
34
|
+
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
35
|
+
var import_package = __toModule(require("@lwrjs/lwc-ssr/package"));
|
|
36
|
+
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
37
|
+
var banner = `/**
|
|
38
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
39
|
+
* All rights reserved.
|
|
40
|
+
* SPDX-License-Identifier: MIT
|
|
41
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
42
|
+
*/
|
|
43
|
+
/* LWC SSR Client Utils v${import_config.LWC_VERSION} */`;
|
|
44
|
+
var SsrResourceProvider = class {
|
|
45
|
+
constructor(_config, context) {
|
|
46
|
+
this.name = "lwc-ssr-client-utils";
|
|
47
|
+
this.ssrUtilsName = "register-lwc-style.js";
|
|
48
|
+
this.versionCache = new Map();
|
|
49
|
+
this.context = context;
|
|
50
|
+
}
|
|
51
|
+
async getResource(resource, environment) {
|
|
52
|
+
const {specifier, version = import_config.LWC_VERSION} = resource;
|
|
53
|
+
if (specifier !== this.ssrUtilsName || version !== import_config.LWC_VERSION) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const cacheKey = `${specifier}_${version}`;
|
|
57
|
+
if (this.versionCache.has(cacheKey)) {
|
|
58
|
+
return this.versionCache.get(cacheKey);
|
|
59
|
+
}
|
|
60
|
+
const {output} = await (0, import_instrumentation.getTracer)().trace({
|
|
61
|
+
name: import_instrumentation.BundleSpan.Rollup,
|
|
62
|
+
attributes: {specifier}
|
|
63
|
+
}, async () => {
|
|
64
|
+
const bundler = await (0, import_rollup.rollup)({
|
|
65
|
+
input: import_path.default.join(import_package.rootPath, "build", "scripts", specifier),
|
|
66
|
+
plugins: [
|
|
67
|
+
(0, import_plugin_node_resolve.nodeResolve)({
|
|
68
|
+
extensions: [".js"],
|
|
69
|
+
modulesOnly: true,
|
|
70
|
+
modulePaths: ["node_modules/@lwc"]
|
|
71
|
+
}),
|
|
72
|
+
(0, import_plugin_terser.default)({
|
|
73
|
+
output: {
|
|
74
|
+
comments: (_, comment) => comment.value.includes("LWC SSR Client Utils")
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
return bundler.generate({format: "iife", banner});
|
|
80
|
+
});
|
|
81
|
+
const resourceDef = {
|
|
82
|
+
specifier,
|
|
83
|
+
version,
|
|
84
|
+
type: "application/javascript",
|
|
85
|
+
inline: true,
|
|
86
|
+
src: await this.context.resourceRegistry.resolveResourceUri({specifier, version}, environment),
|
|
87
|
+
content: output[0].code,
|
|
88
|
+
integrity: (0, import_shared_utils.createIntegrityHash)(output[0].code)
|
|
89
|
+
};
|
|
90
|
+
this.versionCache.set(cacheKey, resourceDef);
|
|
91
|
+
return resourceDef;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var resourceProvider_default = SsrResourceProvider;
|
package/build/cjs/utils.cjs
CHANGED
|
@@ -25,8 +25,6 @@ var __toModule = (module2) => {
|
|
|
25
25
|
__markAsModule(exports);
|
|
26
26
|
__export(exports, {
|
|
27
27
|
SSR_PROPS_ATTR: () => SSR_PROPS_ATTR,
|
|
28
|
-
addHeadMarkup: () => addHeadMarkup,
|
|
29
|
-
createHeadMarkup: () => createHeadMarkup,
|
|
30
28
|
getLoaderConfig: () => getLoaderConfig,
|
|
31
29
|
getLoaderId: () => getLoaderId,
|
|
32
30
|
getLoaderShim: () => getLoaderShim,
|
|
@@ -35,7 +33,6 @@ __export(exports, {
|
|
|
35
33
|
getServerBootstrapServices: () => getServerBootstrapServices,
|
|
36
34
|
mergeWarnings: () => mergeWarnings
|
|
37
35
|
});
|
|
38
|
-
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
39
36
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
40
37
|
var DEFAULT_SSR_TIMEOUT = 5e3;
|
|
41
38
|
var SSR_PROPS_ATTR = "data-lwr-props-id";
|
|
@@ -120,52 +117,3 @@ function mergeWarnings(metadata, warnings = []) {
|
|
|
120
117
|
metadata.serverDebug.warnings = metadata.serverDebug.warnings || [];
|
|
121
118
|
metadata.serverDebug.warnings.push(...warnings);
|
|
122
119
|
}
|
|
123
|
-
function createMetaTags(meta) {
|
|
124
|
-
return meta.reduce((metaStr, {name, content, httpEquiv}) => {
|
|
125
|
-
if (!name && !content && !httpEquiv)
|
|
126
|
-
return metaStr;
|
|
127
|
-
const nameStr = name ? ` name="${name}"` : "", httpEquivStr = httpEquiv ? ` http-equiv="${httpEquiv}"` : "", contentStr = content ? ` content="${content}"` : "";
|
|
128
|
-
return metaStr + `<meta${nameStr}${httpEquivStr}${contentStr}>
|
|
129
|
-
`;
|
|
130
|
-
}, "");
|
|
131
|
-
}
|
|
132
|
-
function createScriptTags(scripts) {
|
|
133
|
-
return scripts.reduce((scriptStr, {body}) => scriptStr + `<script type="application/ld+json">${body}</script>
|
|
134
|
-
`, "");
|
|
135
|
-
}
|
|
136
|
-
function createLinkTags(links) {
|
|
137
|
-
return links.reduce((linkStr, {href, rel, as, fetchpriority}) => {
|
|
138
|
-
const relStr = rel ? ` rel="${rel}"` : "", asStr = as ? ` as="${as}"` : "", fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : "";
|
|
139
|
-
return linkStr + `<link href="${href}"${relStr}${asStr}${fetchStr}>
|
|
140
|
-
`;
|
|
141
|
-
}, "");
|
|
142
|
-
}
|
|
143
|
-
function createStyleTags(styles) {
|
|
144
|
-
return styles.reduce((styleStr, {body, id}) => {
|
|
145
|
-
const idStr = id ? ` id="${id}"` : "";
|
|
146
|
-
return styleStr + `<style type="text/css"${idStr}>${body}</style>
|
|
147
|
-
`;
|
|
148
|
-
}, "");
|
|
149
|
-
}
|
|
150
|
-
function createHeadMarkup(results) {
|
|
151
|
-
let hasTitle = false;
|
|
152
|
-
return results.reduce((str, {markup: {title, scripts = [], meta = [], links = [], styles = []} = {}}) => {
|
|
153
|
-
if (title && !hasTitle) {
|
|
154
|
-
hasTitle = true;
|
|
155
|
-
str += `<title>${title}</title>
|
|
156
|
-
`;
|
|
157
|
-
}
|
|
158
|
-
return str + createMetaTags(meta) + createScriptTags(scripts) + createLinkTags(links) + createStyleTags(styles);
|
|
159
|
-
}, "");
|
|
160
|
-
}
|
|
161
|
-
function addHeadMarkup(results, stringBuilder) {
|
|
162
|
-
const headMarkup = createHeadMarkup(Object.values(results));
|
|
163
|
-
if (headMarkup) {
|
|
164
|
-
const headIndex = stringBuilder.original.indexOf("</head>");
|
|
165
|
-
if (headIndex >= 0) {
|
|
166
|
-
stringBuilder.prependLeft(headIndex, headMarkup);
|
|
167
|
-
} else {
|
|
168
|
-
import_diagnostics.logger.error("Adding markup during server-side rendering failed. Could not find the </head> tag.");
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
@@ -30,7 +30,6 @@ var import_base_view_provider = __toModule(require("@lwrjs/base-view-provider"))
|
|
|
30
30
|
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
31
31
|
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
32
32
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
33
|
-
var import_utils = __toModule(require("../utils.cjs"));
|
|
34
33
|
var import_renderer = __toModule(require("../renderer.cjs"));
|
|
35
34
|
var LwcViewProvider = class extends import_base_view_provider.default {
|
|
36
35
|
constructor(_pluginConfig, providerConfig) {
|
|
@@ -77,7 +76,7 @@ var LwcViewProvider = class extends import_base_view_provider.default {
|
|
|
77
76
|
throw new Error("Failed to render content template component");
|
|
78
77
|
}
|
|
79
78
|
if (markup)
|
|
80
|
-
viewProperties.serverHeadMarkup = (0,
|
|
79
|
+
viewProperties.serverHeadMarkup = (0, import_shared_utils.createHeadMarkup)([markup]);
|
|
81
80
|
return {
|
|
82
81
|
renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
|
|
83
82
|
metadata: {
|
|
@@ -85,7 +85,7 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
85
85
|
}
|
|
86
86
|
(0, import_utils.mergeWarnings)(metadata, warnings);
|
|
87
87
|
metadata.serverBundles = islandBundles ? new Set([...allBundles, ...islandBundles]) : allBundles;
|
|
88
|
-
results && (0,
|
|
88
|
+
results && (0, import_shared_utils.addHeadMarkup)(Object.values(results).map((r) => r.markup), stringBuilder);
|
|
89
89
|
} catch (e) {
|
|
90
90
|
if (e instanceof import_diagnostics.LwrError)
|
|
91
91
|
throw e;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { descriptions, logger, LwrStatusError, stringifyError } from '@lwrjs/diagnostics';
|
|
2
2
|
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
3
|
-
import { addHeadMarkup
|
|
3
|
+
import { addHeadMarkup } from '@lwrjs/shared-utils';
|
|
4
|
+
import { mergeWarnings } from '../utils.js';
|
|
4
5
|
import { getRenderer } from '../renderer.js';
|
|
5
6
|
const NAME = 'preload-data-transformer';
|
|
6
7
|
/**
|
|
@@ -56,7 +57,7 @@ export default function preloadDataViewTransformer(_options, { config, moduleBun
|
|
|
56
57
|
// Log and process the data response
|
|
57
58
|
const { props, markup, cache: { ttl } = { ttl: undefined } } = result || {};
|
|
58
59
|
logger.verbose({ label: NAME, message: 'response', additionalInfo: props });
|
|
59
|
-
markup && addHeadMarkup([result], stringBuilder); // add links to the <head> tag
|
|
60
|
+
markup && addHeadMarkup([result.markup], stringBuilder); // add links to the <head> tag
|
|
60
61
|
metadata.serverData = metadata.serverData || {}; // create serverData if necessary
|
|
61
62
|
Object.assign(metadata.serverData, props); // add the preloaded data to serverData for serialization
|
|
62
63
|
metadata.serverBundles = bundles ? new Set([...allBundles, ...bundles]) : allBundles; // add server bundles for preloadData
|
|
@@ -2,7 +2,6 @@ import type { DirectToCoreProxy } from '@lwrjs/types';
|
|
|
2
2
|
export type FetchFunction = (request: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response>;
|
|
3
3
|
export type FetchRequestContext = {
|
|
4
4
|
host?: string;
|
|
5
|
-
requestDepth?: number;
|
|
6
5
|
headers?: HeadersInit | undefined;
|
|
7
6
|
coreProxy?: DirectToCoreProxy;
|
|
8
7
|
abortController?: AbortController;
|
|
@@ -22,7 +21,6 @@ export declare class FetchController {
|
|
|
22
21
|
private abortController;
|
|
23
22
|
private headers;
|
|
24
23
|
private host;
|
|
25
|
-
private requestDepth;
|
|
26
24
|
private coreProxy;
|
|
27
25
|
fetchEndowment: FetchFunction;
|
|
28
26
|
constructor(context: FetchRequestContext);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Pool as ClientPool } from 'undici';
|
|
2
|
-
import { logger } from '@lwrjs/diagnostics';
|
|
2
|
+
import { logger, stringifyError } from '@lwrjs/diagnostics';
|
|
3
3
|
import { getTracer, ViewSpan } from '@lwrjs/instrumentation';
|
|
4
|
-
import {
|
|
5
|
-
const ROUTE_CORE_HEADER = 'X-SFDC-Route-Core';
|
|
4
|
+
import { ROUTE_CORE_HEADER, getTraceHeaders, toHostname } from '@lwrjs/shared-utils';
|
|
6
5
|
// a single Lambda only services 1 org, so this cache will not grow too large
|
|
7
6
|
const CORE_CLIENTS = new Map();
|
|
8
7
|
/**
|
|
@@ -15,72 +14,79 @@ const CORE_CLIENTS = new Map();
|
|
|
15
14
|
* Any new fetch calls (i.e. from other async function calls) would be immediately aborted.
|
|
16
15
|
*/
|
|
17
16
|
export class FetchController {
|
|
17
|
+
killSwitchActivated;
|
|
18
|
+
noOpActivated;
|
|
19
|
+
abortController;
|
|
20
|
+
headers;
|
|
21
|
+
host;
|
|
22
|
+
coreProxy;
|
|
23
|
+
fetchEndowment;
|
|
18
24
|
constructor(context) {
|
|
19
|
-
this.controlledFetch = (request, init) => {
|
|
20
|
-
if (this.killSwitchActivated) {
|
|
21
|
-
return this.handleAbortError(request, undefined);
|
|
22
|
-
}
|
|
23
|
-
if (!this.abortController) {
|
|
24
|
-
this.abortController = new AbortController();
|
|
25
|
-
}
|
|
26
|
-
const signal = this.abortController?.signal;
|
|
27
|
-
// Ensure the init object exists and then add the signal to it.
|
|
28
|
-
const updatedInit = {
|
|
29
|
-
...init,
|
|
30
|
-
headers: { ...init?.headers, ...this.headers },
|
|
31
|
-
signal,
|
|
32
|
-
};
|
|
33
|
-
const fetchFunction = this.noOpActivated
|
|
34
|
-
? this.fetchNoOp(request, updatedInit)
|
|
35
|
-
: this.fetchEndowment(request, updatedInit);
|
|
36
|
-
const fetchPromise = fetchFunction.catch((error) => {
|
|
37
|
-
// Check if the error is an AbortError
|
|
38
|
-
if (error && error?.stack.startsWith('AbortError')) {
|
|
39
|
-
return this.handleAbortError(request, error);
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
// Re-throw the error if it's not an AbortError
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
return fetchPromise;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* After SSR is complete the kill switch will abort any pending fetch requests.
|
|
50
|
-
*/
|
|
51
|
-
this.activateKillSwitch = () => {
|
|
52
|
-
this.killSwitchActivated = true;
|
|
53
|
-
this.abortController?.abort();
|
|
54
|
-
this.abortController = undefined;
|
|
55
|
-
};
|
|
56
|
-
this.deactivateKillSwitch = () => {
|
|
57
|
-
this.killSwitchActivated = false;
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* During SSR renderComponent (which is synchronous) Do not even call any fetch requests
|
|
61
|
-
* since they would not complete before SSR is done.
|
|
62
|
-
*/
|
|
63
|
-
this.activateNoOp = () => {
|
|
64
|
-
this.noOpActivated = true;
|
|
65
|
-
};
|
|
66
|
-
this.deactivateNoOp = () => {
|
|
67
|
-
this.noOpActivated = false;
|
|
68
|
-
};
|
|
69
|
-
this.setFetchRequestContext = (context) => {
|
|
70
|
-
const { abortController, host, headers, requestDepth, coreProxy } = context;
|
|
71
|
-
this.host = host;
|
|
72
|
-
this.headers = headers;
|
|
73
|
-
this.requestDepth = requestDepth;
|
|
74
|
-
this.coreProxy = coreProxy;
|
|
75
|
-
this.abortController = abortController;
|
|
76
|
-
};
|
|
77
25
|
this.killSwitchActivated = false;
|
|
78
26
|
this.noOpActivated = false;
|
|
79
27
|
this.setFetchRequestContext(context);
|
|
80
28
|
this.fetchEndowment = this.createFetchEndowment();
|
|
81
29
|
}
|
|
30
|
+
controlledFetch = (request, init) => {
|
|
31
|
+
if (this.killSwitchActivated) {
|
|
32
|
+
return this.handleAbortError(request, 'Kill switch was already enabled');
|
|
33
|
+
}
|
|
34
|
+
if (!this.abortController) {
|
|
35
|
+
this.abortController = new AbortController();
|
|
36
|
+
}
|
|
37
|
+
const signal = this.abortController?.signal;
|
|
38
|
+
// Ensure the init object exists and then add the signal to it.
|
|
39
|
+
const updatedInit = {
|
|
40
|
+
...init,
|
|
41
|
+
headers: { ...init?.headers, ...this.headers },
|
|
42
|
+
signal,
|
|
43
|
+
};
|
|
44
|
+
const fetchFunction = this.noOpActivated
|
|
45
|
+
? this.fetchNoOp(request, updatedInit)
|
|
46
|
+
: this.fetchEndowment(request, updatedInit);
|
|
47
|
+
const fetchPromise = fetchFunction.catch((error) => {
|
|
48
|
+
// Check if the error is an AbortError
|
|
49
|
+
const errorMsg = error.message || error;
|
|
50
|
+
if (error && (errorMsg.startsWith('AbortError') || error?.stack.startsWith('AbortError'))) {
|
|
51
|
+
return this.handleAbortError(request, error);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Re-throw the error if it's not an AbortError
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return fetchPromise;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* After SSR is complete the kill switch will abort any pending fetch requests.
|
|
62
|
+
*/
|
|
63
|
+
activateKillSwitch = () => {
|
|
64
|
+
this.killSwitchActivated = true;
|
|
65
|
+
this.abortController?.abort('AbortError: Kill switch enabled');
|
|
66
|
+
this.abortController = undefined;
|
|
67
|
+
};
|
|
68
|
+
deactivateKillSwitch = () => {
|
|
69
|
+
this.killSwitchActivated = false;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* During SSR renderComponent (which is synchronous) Do not even call any fetch requests
|
|
73
|
+
* since they would not complete before SSR is done.
|
|
74
|
+
*/
|
|
75
|
+
activateNoOp = () => {
|
|
76
|
+
this.noOpActivated = true;
|
|
77
|
+
};
|
|
78
|
+
deactivateNoOp = () => {
|
|
79
|
+
this.noOpActivated = false;
|
|
80
|
+
};
|
|
81
|
+
setFetchRequestContext = (context) => {
|
|
82
|
+
const { abortController, host, headers, coreProxy } = context;
|
|
83
|
+
this.host = host;
|
|
84
|
+
this.headers = headers;
|
|
85
|
+
this.coreProxy = coreProxy;
|
|
86
|
+
this.abortController = abortController;
|
|
87
|
+
};
|
|
82
88
|
handleAbortError(request, error) {
|
|
83
|
-
const message =
|
|
89
|
+
const message = `${String(request)} request was killed. Either the request timed out or it was dispatched during SSR. Async processes are not supported during SSR. For more information, see: https://developer.salesforce.com/docs/platform/lwr/guide/lwr-configure-component-ssr.html.`;
|
|
84
90
|
logger.warn({ label: `Server-side Rendering`, message }, error);
|
|
85
91
|
// Return a response to indicate kill switch
|
|
86
92
|
return Promise.resolve(new Response(message, { status: 500 }));
|
|
@@ -97,35 +103,28 @@ export class FetchController {
|
|
|
97
103
|
}
|
|
98
104
|
else if (init.signal.aborted) {
|
|
99
105
|
// The request was already aborted go ahead and return the abort error
|
|
100
|
-
resolve(this.handleAbortError(request, new Error('Request was aborted')));
|
|
106
|
+
resolve(this.handleAbortError(request, new Error('Request was already aborted')));
|
|
101
107
|
}
|
|
102
108
|
else {
|
|
103
109
|
// Wait until fetches are aborted to resolve with an abort error
|
|
104
110
|
const abortHandler = (err) => {
|
|
105
111
|
init?.signal?.removeEventListener('abort', abortHandler);
|
|
106
112
|
// Resolve the fetch
|
|
107
|
-
resolve(this.handleAbortError(request, err));
|
|
113
|
+
resolve(this.handleAbortError(request, new Error('Not allowed: Request was dispatched during SSR', { cause: err })));
|
|
108
114
|
};
|
|
109
115
|
init.signal.addEventListener('abort', abortHandler);
|
|
110
116
|
}
|
|
111
117
|
});
|
|
112
118
|
}
|
|
113
119
|
createFetchEndowment() {
|
|
114
|
-
return (request, init) => {
|
|
115
|
-
const { host: forwardedOrigin = '',
|
|
120
|
+
return (request, init = {}) => {
|
|
121
|
+
const { host: forwardedOrigin = '', coreProxy } = this;
|
|
116
122
|
// The Direct-to-Core proxy origin takes precedence over the Forwarded host
|
|
117
123
|
const origin = coreProxy?.origin && coreProxy.origin.startsWith('http') ? coreProxy.origin : forwardedOrigin;
|
|
118
124
|
const { finalRequest, finalUrl } = this.getFinalRequest(request, origin);
|
|
119
|
-
const finalInit = {
|
|
120
|
-
...init,
|
|
121
|
-
headers: {
|
|
122
|
-
...init?.headers,
|
|
123
|
-
[REQUEST_DEPTH_HEADER]: String(requestDepth),
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
125
|
if (coreProxy || (forwardedOrigin && finalUrl.startsWith(forwardedOrigin))) {
|
|
127
126
|
// hint for the CDN that the request is targeted to Core
|
|
128
|
-
|
|
127
|
+
init.headers[ROUTE_CORE_HEADER] = 'true';
|
|
129
128
|
}
|
|
130
129
|
const proxyStr = coreProxy ? JSON.stringify(coreProxy) : 'none';
|
|
131
130
|
const hasCookies = this.headers && this.headers.Cookie ? 'yes' : 'no';
|
|
@@ -156,17 +155,33 @@ export class FetchController {
|
|
|
156
155
|
span.setAttributes({ statusCode: res.status });
|
|
157
156
|
return res;
|
|
158
157
|
};
|
|
158
|
+
const addErrorToSpan = (err) => {
|
|
159
|
+
// add fetch errors to the trace
|
|
160
|
+
span.setAttributes({ error: stringifyError(err) });
|
|
161
|
+
};
|
|
162
|
+
// add tracing headers based on span values
|
|
163
|
+
init.headers = { ...init.headers, ...getTraceHeaders({}, span) };
|
|
159
164
|
if (coreProxy) {
|
|
160
|
-
return this.fetchWithAgent(finalUrl,
|
|
165
|
+
return this.fetchWithAgent(finalUrl, init, forwardedOrigin, coreProxy, span)
|
|
161
166
|
.then((res) => addInfoToSpan(res))
|
|
162
167
|
.catch((err) => {
|
|
163
168
|
const { finalRequest: cdnRequest, finalUrl: cdnUrl } = this.getFinalRequest(request, forwardedOrigin);
|
|
164
169
|
logger.warn(`Fetching data directly from Core failed, retrying through CDN: ${cdnUrl} Error is: ${err.message || err}`);
|
|
165
170
|
span.setAttributes({ fetchType: 'cdnFallback' });
|
|
166
|
-
return fetch(cdnRequest,
|
|
171
|
+
return fetch(cdnRequest, init)
|
|
172
|
+
.then((res) => addInfoToSpan(res))
|
|
173
|
+
.catch((e) => {
|
|
174
|
+
addErrorToSpan(e);
|
|
175
|
+
throw e;
|
|
176
|
+
});
|
|
167
177
|
});
|
|
168
178
|
}
|
|
169
|
-
return fetch(finalRequest,
|
|
179
|
+
return fetch(finalRequest, init)
|
|
180
|
+
.then((res) => addInfoToSpan(res))
|
|
181
|
+
.catch((e) => {
|
|
182
|
+
addErrorToSpan(e);
|
|
183
|
+
throw e;
|
|
184
|
+
});
|
|
170
185
|
});
|
|
171
186
|
};
|
|
172
187
|
}
|
|
@@ -259,19 +274,6 @@ export class FetchController {
|
|
|
259
274
|
values.forEach((v) => headers.append(key, v));
|
|
260
275
|
}
|
|
261
276
|
return new Response(body, { status: res.statusCode, headers });
|
|
262
|
-
// If we want to fallback to CDN for certain status codes
|
|
263
|
-
// if (!fetchRes.ok) {
|
|
264
|
-
// throw new Error('Failed with status code: ' + fetchRes.status);
|
|
265
|
-
// }
|
|
266
|
-
// return {
|
|
267
|
-
// ...res,
|
|
268
|
-
// url: origin + path,
|
|
269
|
-
// ok: res.statusCode < 400,
|
|
270
|
-
// status: res.statusCode,
|
|
271
|
-
// redirected: res.statusCode >= 300 && res.statusCode < 400,
|
|
272
|
-
// text: res.body.text.bind(res.body),
|
|
273
|
-
// json: res.body.json.bind(res.body),
|
|
274
|
-
// } as unknown as Response;
|
|
275
277
|
});
|
|
276
278
|
}
|
|
277
279
|
}
|
package/build/es/moduleLoader.js
CHANGED
|
@@ -13,7 +13,7 @@ export function createModuleLoader(config, resourceRegistry, bundleRegistry, run
|
|
|
13
13
|
async function createAMDModuleLoader(config, resourceRegistry, bundleRegistry, runtimeEnvironment, runtimeParams, serverData, bootstrapConfig, abortController) {
|
|
14
14
|
// creating a render context to avoid polluting globals
|
|
15
15
|
const loaderConfig = getLoaderConfig(BOOTSTRAP_SPECIFIER, config, runtimeParams, serverData);
|
|
16
|
-
const { context, controller } = createContext(loaderConfig, runtimeParams,
|
|
16
|
+
const { context, controller } = createContext(loaderConfig, runtimeParams, abortController);
|
|
17
17
|
const contextKeyMap = new Map(Object.keys(context).map((key) => [key, true]));
|
|
18
18
|
// attaching custom init to delay bootstrap module evaluation
|
|
19
19
|
let run;
|
|
@@ -238,10 +238,9 @@ async function createESMModuleLoader() {
|
|
|
238
238
|
* @param runtimeParams - request parameters
|
|
239
239
|
* @returns a `globalThis` object
|
|
240
240
|
*/
|
|
241
|
-
function createContext(LWR, runtimeParams,
|
|
241
|
+
function createContext(LWR, runtimeParams, abortController) {
|
|
242
242
|
const fetchController = new FetchController({
|
|
243
243
|
host: runtimeParams.host,
|
|
244
|
-
requestDepth: runtimeParams.requestDepth,
|
|
245
244
|
coreProxy: runtimeParams.coreProxy,
|
|
246
245
|
abortController,
|
|
247
246
|
});
|
package/build/es/renderer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// TODO: investigate perf impact W-16056356
|
|
2
2
|
import { LRUCache } from 'lru-cache';
|
|
3
3
|
import { LwrApplicationError, LwrError, LwrStatusError, descriptions, logger, stringifyError, } from '@lwrjs/diagnostics';
|
|
4
|
-
import {
|
|
4
|
+
import { REQUEST_DEPTH_HEADER, TaskPool, buildEnvironmentContext, cookieStringToObject, getCacheKeyFromJson, getFeatureFlags, getSpecifier, getTraceHeaders, isLambdaEnv, isLocalDev, moduleSpecifierToKebabCase, } from '@lwrjs/shared-utils';
|
|
5
5
|
import { ViewSpan, cacheCountStore, getTracer } from '@lwrjs/instrumentation';
|
|
6
6
|
import { getServerBootstrapServices, getRenderTimeout } from './utils.js';
|
|
7
7
|
import { createModuleLoader } from './moduleLoader.js';
|
|
@@ -22,8 +22,13 @@ export function getRenderer(config, bundleRegistry, resourceRegistry) {
|
|
|
22
22
|
return singleton;
|
|
23
23
|
}
|
|
24
24
|
export class Renderer {
|
|
25
|
+
config;
|
|
26
|
+
bundleRegistry;
|
|
27
|
+
resourceRegistry;
|
|
28
|
+
contextPerEnv;
|
|
29
|
+
pendingRenders;
|
|
30
|
+
globalCache = {};
|
|
25
31
|
constructor(config, bundleRegistry, resourceRegistry) {
|
|
26
|
-
this.globalCache = {};
|
|
27
32
|
this.config = config;
|
|
28
33
|
this.bundleRegistry = bundleRegistry;
|
|
29
34
|
this.resourceRegistry = resourceRegistry;
|
|
@@ -71,8 +76,9 @@ export class Renderer {
|
|
|
71
76
|
const abortController = new AbortController();
|
|
72
77
|
const timeout = new Promise((_, reject) => {
|
|
73
78
|
timerId = setTimeout(() => {
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
const message = descriptions.APPLICATION.SSR_TIMEOUT(route.id, getRenderTimeout());
|
|
80
|
+
abortController.abort(`AbortError: ${message}`);
|
|
81
|
+
reject(new LwrApplicationError(message));
|
|
76
82
|
}, getRenderTimeout());
|
|
77
83
|
});
|
|
78
84
|
result = (await this.pendingRenders.execute(async () => {
|
|
@@ -301,15 +307,15 @@ export class Renderer {
|
|
|
301
307
|
resetFetchController(fetchController, runtimeParams, route, abortController) {
|
|
302
308
|
// Re-enable fetch that was disabled at the end of the previous page render via `enableFetchKillSwitch`
|
|
303
309
|
fetchController.disableFetchKillSwitch();
|
|
310
|
+
const baseHeaders = {
|
|
311
|
+
[REQUEST_DEPTH_HEADER]: runtimeParams.requestDepth ?? '0',
|
|
312
|
+
...getTraceHeaders(runtimeParams),
|
|
313
|
+
};
|
|
304
314
|
fetchController.setFetchRequestContext({
|
|
305
315
|
host: runtimeParams.host,
|
|
306
|
-
requestDepth: runtimeParams.requestDepth,
|
|
307
316
|
headers: route.bootstrap.includeCookiesForSSR
|
|
308
|
-
? {
|
|
309
|
-
|
|
310
|
-
'True-Client-IP': runtimeParams.trueClientIP,
|
|
311
|
-
}
|
|
312
|
-
: { 'True-Client-IP': runtimeParams.trueClientIP },
|
|
317
|
+
? { Cookie: runtimeParams.cookie, ...baseHeaders }
|
|
318
|
+
: baseHeaders,
|
|
313
319
|
coreProxy: runtimeParams.coreProxy,
|
|
314
320
|
abortController,
|
|
315
321
|
});
|
|
@@ -362,15 +368,13 @@ function getServerData(component, context, serverData) {
|
|
|
362
368
|
return getTracer().trace({
|
|
363
369
|
name: ViewSpan.GetServerData,
|
|
364
370
|
attributes: { specifier: component.specifier },
|
|
365
|
-
}, async () => {
|
|
371
|
+
}, async (span) => {
|
|
366
372
|
try {
|
|
367
373
|
const data = await component.module.getServerData(context);
|
|
368
374
|
Object.assign(serverData, data.props);
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const { code, location } = dataRes.status;
|
|
373
|
-
throw new LwrStatusError(undefined, code, location ? { location } : undefined);
|
|
375
|
+
if (data.warnings) {
|
|
376
|
+
const warnings = data.warnings.map((w) => stringifyError(w)).join(', ');
|
|
377
|
+
span.setAttributes({ warnings });
|
|
374
378
|
}
|
|
375
379
|
return data;
|
|
376
380
|
}
|
|
@@ -388,15 +392,18 @@ function getServerData(component, context, serverData) {
|
|
|
388
392
|
});
|
|
389
393
|
}
|
|
390
394
|
async function renderToString(engine, component, props) {
|
|
395
|
+
const isSSRv2 = getFeatureFlags().SSR_COMPILER_ENABLED || false;
|
|
391
396
|
return getTracer().trace({
|
|
392
397
|
name: ViewSpan.RenderComponent,
|
|
393
|
-
attributes: { specifier: component.specifier },
|
|
398
|
+
attributes: { specifier: component.specifier, isSSRv2 },
|
|
394
399
|
}, async () => {
|
|
395
400
|
try {
|
|
396
401
|
const elementName = moduleSpecifierToKebabCase(component.specifier);
|
|
397
402
|
const moduleDefault = component.module.default;
|
|
398
|
-
const html =
|
|
399
|
-
?
|
|
403
|
+
const html = isSSRv2
|
|
404
|
+
? // serverSideRenderComponent(tagName: string, Component: ComponentWithGenerateMarkup, props: Properties = {}, styleDedupePrefix = '', styleDedupeIsEnabled = false, mode: CompilationMode = DEFAULT_SSR_MODE / 'sync'
|
|
405
|
+
await engine.renderComponent(elementName, moduleDefault, props, elementName, false, // true, re-enable with W-18004123
|
|
406
|
+
'sync')
|
|
400
407
|
: engine.renderComponent(elementName, moduleDefault, props);
|
|
401
408
|
return { html };
|
|
402
409
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderContext, ResourceDefinition, ResourceIdentifier, ResourceProvider, RuntimeEnvironment } from '@lwrjs/types';
|
|
2
|
+
export default class SsrResourceProvider implements ResourceProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
private ssrUtilsName;
|
|
5
|
+
private versionCache;
|
|
6
|
+
private context;
|
|
7
|
+
constructor(_config: any, context: ProviderContext);
|
|
8
|
+
getResource<T extends ResourceIdentifier, R extends RuntimeEnvironment>(resource: T, environment: R): Promise<ResourceDefinition | undefined>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=resourceProvider.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { rollup } from 'rollup';
|
|
3
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
4
|
+
import terser from '@rollup/plugin-terser';
|
|
5
|
+
import { LWC_VERSION } from '@lwrjs/config';
|
|
6
|
+
import { BundleSpan, getTracer } from '@lwrjs/instrumentation';
|
|
7
|
+
import { rootPath } from '@lwrjs/lwc-ssr/package';
|
|
8
|
+
import { createIntegrityHash } from '@lwrjs/shared-utils';
|
|
9
|
+
/**
|
|
10
|
+
* Provide an IIFE script resource containing @lwc/ssr-client-utils#register-lwc-style.js
|
|
11
|
+
* This script performs style de-duping for components which are SSR compiled.
|
|
12
|
+
* It must be included in the <head> section of every page which uses the SSR compiler.
|
|
13
|
+
* If the script is not included, only the first instance of each SSRed component will be styled!
|
|
14
|
+
* The @lwc/ssr-client-utils package is a peer dependency so LWR is not tied to an LWC version.
|
|
15
|
+
*/
|
|
16
|
+
const banner = `/**
|
|
17
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
18
|
+
* All rights reserved.
|
|
19
|
+
* SPDX-License-Identifier: MIT
|
|
20
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
21
|
+
*/
|
|
22
|
+
/* LWC SSR Client Utils v${LWC_VERSION} */`;
|
|
23
|
+
export default class SsrResourceProvider {
|
|
24
|
+
name = 'lwc-ssr-client-utils';
|
|
25
|
+
ssrUtilsName = 'register-lwc-style.js';
|
|
26
|
+
versionCache = new Map();
|
|
27
|
+
context;
|
|
28
|
+
constructor(_config, context) {
|
|
29
|
+
this.context = context;
|
|
30
|
+
}
|
|
31
|
+
async getResource(resource, environment) {
|
|
32
|
+
// validate identifier
|
|
33
|
+
const { specifier, version = LWC_VERSION } = resource;
|
|
34
|
+
if (specifier !== this.ssrUtilsName || version !== LWC_VERSION) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// check cache
|
|
38
|
+
const cacheKey = `${specifier}_${version}`;
|
|
39
|
+
if (this.versionCache.has(cacheKey)) {
|
|
40
|
+
return this.versionCache.get(cacheKey);
|
|
41
|
+
}
|
|
42
|
+
// generate script resource
|
|
43
|
+
const { output } = await getTracer().trace({
|
|
44
|
+
name: BundleSpan.Rollup,
|
|
45
|
+
attributes: { specifier },
|
|
46
|
+
}, async () => {
|
|
47
|
+
const bundler = await rollup({
|
|
48
|
+
input: path.join(rootPath, 'build', 'scripts', specifier),
|
|
49
|
+
plugins: [
|
|
50
|
+
nodeResolve({
|
|
51
|
+
// import from @lwc/ssr-client-utils
|
|
52
|
+
extensions: ['.js'],
|
|
53
|
+
modulesOnly: true,
|
|
54
|
+
modulePaths: ['node_modules/@lwc'],
|
|
55
|
+
}),
|
|
56
|
+
terser({
|
|
57
|
+
output: {
|
|
58
|
+
comments: (_, comment) => comment.value.includes('LWC SSR Client Utils'),
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
return bundler.generate({ format: 'iife', banner });
|
|
64
|
+
});
|
|
65
|
+
// assemble resource definition
|
|
66
|
+
const resourceDef = {
|
|
67
|
+
specifier,
|
|
68
|
+
version,
|
|
69
|
+
type: 'application/javascript',
|
|
70
|
+
inline: true,
|
|
71
|
+
src: await this.context.resourceRegistry.resolveResourceUri({ specifier, version }, environment),
|
|
72
|
+
content: output[0].code,
|
|
73
|
+
integrity: createIntegrityHash(output[0].code),
|
|
74
|
+
};
|
|
75
|
+
// cache and return
|
|
76
|
+
this.versionCache.set(cacheKey, resourceDef);
|
|
77
|
+
return resourceDef;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=resourceProvider.js.map
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
2
2
|
import { LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
|
|
3
3
|
export class ServerBootstrapServices {
|
|
4
|
+
serverDataCallbacks;
|
|
5
|
+
requestHooks;
|
|
6
|
+
_serviceAPI;
|
|
4
7
|
evaluateServerDataHooks(serverData = {}) {
|
|
5
8
|
// now that we have server data, run the server data hooks
|
|
6
9
|
for (const serverDataHook of this.serverDataCallbacks) {
|
package/build/es/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientBootstrapConfig, EnvironmentContext,
|
|
1
|
+
import type { ClientBootstrapConfig, EnvironmentContext, NormalizedLwrAppBootstrapConfig, NormalizedLwrErrorRoute, NormalizedLwrRoute, ProviderAppConfig, PublicResourceRegistry, RenderedViewMetadata, RuntimeEnvironment, RuntimeParams, ServerData } from '@lwrjs/types';
|
|
2
2
|
interface ServerEnvironment extends EnvironmentContext {
|
|
3
3
|
SSR: boolean;
|
|
4
4
|
}
|
|
@@ -12,17 +12,5 @@ export declare function getLoaderConfig(bootstrapModule: string, config: Provide
|
|
|
12
12
|
};
|
|
13
13
|
export declare function getServerBootstrapServices(route: NormalizedLwrRoute | NormalizedLwrErrorRoute): string[];
|
|
14
14
|
export declare function mergeWarnings(metadata: RenderedViewMetadata, warnings?: (Error | string)[]): void;
|
|
15
|
-
/**
|
|
16
|
-
* Serialize SsrDataResponse.markup into an HTML string
|
|
17
|
-
* @param results An array of responses from getServerData hooks
|
|
18
|
-
* @returns A string of HTML generated from markup metadata
|
|
19
|
-
*/
|
|
20
|
-
export declare function createHeadMarkup(results: SsrDataResponse[]): string;
|
|
21
|
-
/**
|
|
22
|
-
* Serialize SsrDataResponse.markup into HTML, then add it to the <head> of a base doc
|
|
23
|
-
* @param results An array of responses from getServerData hooks
|
|
24
|
-
* @param stringBuilder The string builder for a base document
|
|
25
|
-
*/
|
|
26
|
-
export declare function addHeadMarkup(results: SsrDataResponse[], stringBuilder: LwrStringBuilder): void;
|
|
27
15
|
export {};
|
|
28
16
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/es/utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { logger } from '@lwrjs/diagnostics';
|
|
2
1
|
import { buildEnvironmentContext, getFeatureFlags, normalizeVersionToUri, isLambdaEnv, getSpecifier, } from '@lwrjs/shared-utils';
|
|
3
2
|
const DEFAULT_SSR_TIMEOUT = 5000; // 5 seconds, override with process.env.SSR_TIMEOUT
|
|
4
3
|
export const SSR_PROPS_ATTR = 'data-lwr-props-id';
|
|
@@ -98,69 +97,4 @@ export function mergeWarnings(metadata, warnings = []) {
|
|
|
98
97
|
metadata.serverDebug.warnings = metadata.serverDebug.warnings || [];
|
|
99
98
|
metadata.serverDebug.warnings.push(...warnings);
|
|
100
99
|
}
|
|
101
|
-
/** SSR HEAD MARKUP UTILS */
|
|
102
|
-
function createMetaTags(meta) {
|
|
103
|
-
return meta.reduce((metaStr, { name, content, httpEquiv }) => {
|
|
104
|
-
if (!name && !content && !httpEquiv)
|
|
105
|
-
return metaStr; // do not create empty <meta> tags
|
|
106
|
-
const nameStr = name ? ` name="${name}"` : '', httpEquivStr = httpEquiv ? ` http-equiv="${httpEquiv}"` : '', contentStr = content ? ` content="${content}"` : '';
|
|
107
|
-
return metaStr + `<meta${nameStr}${httpEquivStr}${contentStr}>\n`;
|
|
108
|
-
}, '');
|
|
109
|
-
}
|
|
110
|
-
function createScriptTags(scripts) {
|
|
111
|
-
return scripts.reduce((scriptStr, { body }) => scriptStr + `<script type="application/ld+json">${body}</script>\n`, '');
|
|
112
|
-
}
|
|
113
|
-
function createLinkTags(links) {
|
|
114
|
-
return links.reduce((linkStr, { href, rel, as, fetchpriority }) => {
|
|
115
|
-
const relStr = rel ? ` rel="${rel}"` : '', asStr = as ? ` as="${as}"` : '', fetchStr = fetchpriority ? ` fetchpriority="${fetchpriority}"` : '';
|
|
116
|
-
return linkStr + `<link href="${href}"${relStr}${asStr}${fetchStr}>\n`;
|
|
117
|
-
}, '');
|
|
118
|
-
}
|
|
119
|
-
function createStyleTags(styles) {
|
|
120
|
-
return styles.reduce((styleStr, { body, id }) => {
|
|
121
|
-
const idStr = id ? ` id="${id}"` : '';
|
|
122
|
-
return styleStr + `<style type="text/css"${idStr}>${body}</style>\n`;
|
|
123
|
-
}, '');
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Serialize SsrDataResponse.markup into an HTML string
|
|
127
|
-
* @param results An array of responses from getServerData hooks
|
|
128
|
-
* @returns A string of HTML generated from markup metadata
|
|
129
|
-
*/
|
|
130
|
-
export function createHeadMarkup(results) {
|
|
131
|
-
// Loop through the <title>, <script>, <meta>, and <link> tag information
|
|
132
|
-
// Create an HTML string for each tag
|
|
133
|
-
let hasTitle = false;
|
|
134
|
-
return results.reduce((str, { markup: { title, scripts = [], meta = [], links = [], styles = [] } = {} }) => {
|
|
135
|
-
if (title && !hasTitle) {
|
|
136
|
-
// first <title> wins
|
|
137
|
-
hasTitle = true;
|
|
138
|
-
str += `<title>${title}</title>\n`;
|
|
139
|
-
}
|
|
140
|
-
return (str +
|
|
141
|
-
createMetaTags(meta) +
|
|
142
|
-
createScriptTags(scripts) +
|
|
143
|
-
createLinkTags(links) +
|
|
144
|
-
createStyleTags(styles));
|
|
145
|
-
}, '');
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Serialize SsrDataResponse.markup into HTML, then add it to the <head> of a base doc
|
|
149
|
-
* @param results An array of responses from getServerData hooks
|
|
150
|
-
* @param stringBuilder The string builder for a base document
|
|
151
|
-
*/
|
|
152
|
-
export function addHeadMarkup(results, stringBuilder) {
|
|
153
|
-
// Create HTML tags for each item in the SsrDataResponse.markup bag
|
|
154
|
-
const headMarkup = createHeadMarkup(Object.values(results));
|
|
155
|
-
if (headMarkup) {
|
|
156
|
-
// Add all the links to the <head> section of the base document
|
|
157
|
-
const headIndex = stringBuilder.original.indexOf('</head>');
|
|
158
|
-
if (headIndex >= 0) {
|
|
159
|
-
stringBuilder.prependLeft(headIndex, headMarkup);
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
logger.error('Adding markup during server-side rendering failed. Could not find the </head> tag.');
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
100
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import BaseViewProvider from '@lwrjs/base-view-provider';
|
|
2
2
|
import { descriptions, LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
|
|
3
3
|
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
4
|
-
import { hashContent, isSpecifier, moduleSpecifierToKebabCase, slugify } from '@lwrjs/shared-utils';
|
|
5
|
-
import { createHeadMarkup } from '../utils.js';
|
|
4
|
+
import { createHeadMarkup, hashContent, isSpecifier, moduleSpecifierToKebabCase, slugify, } from '@lwrjs/shared-utils';
|
|
6
5
|
import { getRenderer } from '../renderer.js';
|
|
7
6
|
export default class LwcViewProvider extends BaseViewProvider {
|
|
7
|
+
name = 'ssr-view-provider';
|
|
8
|
+
moduleBundler;
|
|
9
|
+
resourceRegistry;
|
|
10
|
+
routes;
|
|
11
|
+
runtimeEnvironment;
|
|
12
|
+
config;
|
|
8
13
|
constructor(_pluginConfig, providerConfig) {
|
|
9
14
|
super();
|
|
10
|
-
this.name = 'ssr-view-provider';
|
|
11
15
|
this.moduleBundler = providerConfig.moduleBundler;
|
|
12
16
|
this.resourceRegistry = providerConfig.resourceRegistry;
|
|
13
17
|
this.routes = [...providerConfig.config.routes, ...providerConfig.config.errorRoutes];
|
|
@@ -54,7 +58,7 @@ export default class LwcViewProvider extends BaseViewProvider {
|
|
|
54
58
|
throw new Error('Failed to render content template component');
|
|
55
59
|
}
|
|
56
60
|
if (markup)
|
|
57
|
-
viewProperties.serverHeadMarkup = createHeadMarkup([
|
|
61
|
+
viewProperties.serverHeadMarkup = createHeadMarkup([markup]); // generate <head> markup
|
|
58
62
|
return {
|
|
59
63
|
// add "lwc:external" to the contentTemplate component to mark it as already processed
|
|
60
64
|
renderedView: html.replace(`<${element}`, `<${element} lwc:external`),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { descriptions, logger, LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
|
|
2
2
|
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
3
|
-
import { HYDRATE_DIRECTIVE, isCsrIsland, isHydrateOnLoad, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
|
|
4
|
-
import { SSR_PROPS_ATTR,
|
|
3
|
+
import { HYDRATE_DIRECTIVE, addHeadMarkup, isCsrIsland, isHydrateOnLoad, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
|
|
4
|
+
import { SSR_PROPS_ATTR, getPropsId, mergeWarnings } from '../utils.js';
|
|
5
5
|
import { getRenderer } from '../renderer.js';
|
|
6
6
|
/**
|
|
7
7
|
* This is a view transformer run by the view registry during linking of a page document/route (configured in lwr.config.json[routes]).
|
|
@@ -79,7 +79,8 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
|
|
|
79
79
|
metadata.serverBundles = islandBundles
|
|
80
80
|
? new Set([...allBundles, ...islandBundles])
|
|
81
81
|
: allBundles;
|
|
82
|
-
results &&
|
|
82
|
+
results &&
|
|
83
|
+
addHeadMarkup(Object.values(results).map((r) => r.markup), stringBuilder);
|
|
83
84
|
}
|
|
84
85
|
catch (e) {
|
|
85
86
|
if (e instanceof LwrError)
|
package/package.cjs
ADDED
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.18.0",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -29,39 +29,51 @@
|
|
|
29
29
|
"./dataViewTransformer": {
|
|
30
30
|
"import": "./build/es/dataViewTransformer/index.js",
|
|
31
31
|
"require": "./build/cjs/dataViewTransformer/index.cjs"
|
|
32
|
-
}
|
|
32
|
+
},
|
|
33
|
+
"./resourceProvider": {
|
|
34
|
+
"import": "./build/es/resourceProvider.js",
|
|
35
|
+
"require": "./build/cjs/resourceProvider.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./package": "./package.cjs"
|
|
33
38
|
},
|
|
34
39
|
"scripts": {
|
|
35
|
-
"build": "tsc -b",
|
|
40
|
+
"build": "tsc -b && shx cp -R ./src/scripts ./build",
|
|
36
41
|
"clean": "rimraf build node_modules",
|
|
37
42
|
"test": "jest"
|
|
38
43
|
},
|
|
39
44
|
"files": [
|
|
40
45
|
"build/**/*.js",
|
|
41
46
|
"build/**/*.cjs",
|
|
42
|
-
"build/**/*.d.ts"
|
|
47
|
+
"build/**/*.d.ts",
|
|
48
|
+
"package.cjs"
|
|
43
49
|
],
|
|
44
50
|
"dependencies": {
|
|
45
|
-
"@lwrjs/config": "0.
|
|
46
|
-
"@lwrjs/diagnostics": "0.
|
|
47
|
-
"@lwrjs/instrumentation": "0.
|
|
48
|
-
"@lwrjs/loader": "0.
|
|
49
|
-
"@lwrjs/shared-utils": "0.
|
|
51
|
+
"@lwrjs/config": "0.18.0",
|
|
52
|
+
"@lwrjs/diagnostics": "0.18.0",
|
|
53
|
+
"@lwrjs/instrumentation": "0.18.0",
|
|
54
|
+
"@lwrjs/loader": "0.18.0",
|
|
55
|
+
"@lwrjs/shared-utils": "0.18.0",
|
|
56
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
57
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
50
58
|
"fs-extra": "^11.2.0",
|
|
51
59
|
"lru-cache": "^10.4.3",
|
|
60
|
+
"rollup": "^2.79.2",
|
|
52
61
|
"undici": "^6.21.1"
|
|
53
62
|
},
|
|
54
63
|
"devDependencies": {
|
|
55
|
-
"@lwrjs/types": "0.
|
|
56
|
-
"jest": "
|
|
64
|
+
"@lwrjs/types": "0.18.0",
|
|
65
|
+
"jest": "29.7.0",
|
|
57
66
|
"memfs": "^4.13.0",
|
|
58
|
-
"ts-jest": "^
|
|
67
|
+
"ts-jest": "^29.2.6"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@lwc/ssr-client-utils": ">= 8.16"
|
|
59
71
|
},
|
|
60
72
|
"engines": {
|
|
61
|
-
"node": ">=
|
|
73
|
+
"node": ">=20.0.0"
|
|
62
74
|
},
|
|
63
75
|
"volta": {
|
|
64
76
|
"extends": "../../../package.json"
|
|
65
77
|
},
|
|
66
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "763c7c558ea75fe34a91162c9793de63e55f1d2f"
|
|
67
79
|
}
|