@lwrjs/lwc-ssr 0.20.1 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
- [Islands](#islands)
|
|
19
19
|
- [Client hydration](#client-hydration)
|
|
20
20
|
- [Skip SSR](#skip-ssr)
|
|
21
|
+
- [Hydrate on visible](#hydrate-on-visible)
|
|
21
22
|
- [Routing](#routing)
|
|
22
23
|
- [Limitations](#limitations)
|
|
23
24
|
- [Portability](#portability)
|
|
@@ -326,6 +327,39 @@ Root components can skip SSR by setting the `lwr:hydrate` directive to `client-o
|
|
|
326
327
|
|
|
327
328
|
Root components which opt-out of SSR will be fully rendered on the client using the [LWC `createElement()` API](https://www.npmjs.com/package/@lwc/engine-dom).
|
|
328
329
|
|
|
330
|
+
### Hydrate on visible
|
|
331
|
+
|
|
332
|
+
Root components can defer hydration until they become visible in the viewport by setting the `lwr:hydrate` directive to `visible`. This creates a performance optimization where components are only hydrated when they're about to be seen by the user:
|
|
333
|
+
|
|
334
|
+
```html
|
|
335
|
+
<!-- my-app/src/content/page.html (contentTemplate) -->
|
|
336
|
+
|
|
337
|
+
<!-- hydrated immediately -->
|
|
338
|
+
<my-header lwr:hydrate></my-header>
|
|
339
|
+
|
|
340
|
+
<!-- hydrated when visible -->
|
|
341
|
+
<my-footer lwr:hydrate="visible"></my-footer>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Components with `lwr:hydrate="visible"` will:
|
|
345
|
+
|
|
346
|
+
- Be server-side rendered normally
|
|
347
|
+
- Have their hydration deferred until they enter the viewport
|
|
348
|
+
- Use the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to detect visibility
|
|
349
|
+
- Automatically hydrate when they become visible with a 100px root margin buffer
|
|
350
|
+
|
|
351
|
+
#### Root Margin
|
|
352
|
+
|
|
353
|
+
The root margin determines how close a component needs to be to the viewport before it starts hydrating. Components will hydrate when they are 100px away from entering the viewport. This provides a buffer to ensure hydration completes before the user sees the component.
|
|
354
|
+
|
|
355
|
+
The root margin is currently set to a fixed value of `100px` in the LWR implementation and is not configurable.
|
|
356
|
+
|
|
357
|
+
This approach is particularly useful for:
|
|
358
|
+
|
|
359
|
+
- Below-the-fold content that users may not scroll to
|
|
360
|
+
- Large components that are expensive to hydrate
|
|
361
|
+
- Progressive enhancement of page interactivity
|
|
362
|
+
|
|
329
363
|
## Routing
|
|
330
364
|
|
|
331
365
|
LWR provides a Server Router, which is similar to the [Client Router](../router/README.md). The Server Router is fully compatible with SSRed pages, including [islands](#islands). It:
|
|
@@ -76,7 +76,8 @@ function lwcSsrViewTransformer(options, {config, moduleBundler, resourceRegistry
|
|
|
76
76
|
let propsAttr = "";
|
|
77
77
|
if (hydrate) {
|
|
78
78
|
const propsId = (0, import_utils.getPropsId)();
|
|
79
|
-
|
|
79
|
+
const hydrateAttr = props && props[import_shared_utils.HYDRATE_DIRECTIVE] ? ` ${import_shared_utils.HYDRATE_DIRECTIVE}="${props[import_shared_utils.HYDRATE_DIRECTIVE]}"` : "";
|
|
80
|
+
propsAttr = ` ${import_utils.SSR_PROPS_ATTR}="${propsId}"${hydrateAttr}`;
|
|
80
81
|
serverData[propsId] = props;
|
|
81
82
|
}
|
|
82
83
|
const [, remain] = html.split(`<${tagName}`);
|
|
@@ -112,9 +113,12 @@ function getComponentsToSSR(customElements, stringBuilder) {
|
|
|
112
113
|
if (!isCsr && !rawProps?.["lwc:external"] && location) {
|
|
113
114
|
const {startOffset, endOffset} = location;
|
|
114
115
|
const specifier = (0, import_shared_utils.kebabCaseToModuleSpecifier)(tagName);
|
|
115
|
-
const
|
|
116
|
+
const isHydrateOnVisible = (0, import_shared_utils.isHydrateVisible)(rawProps);
|
|
117
|
+
const hydrate = (0, import_shared_utils.isHydrateOnLoad)(rawProps) || isHydrateOnVisible;
|
|
116
118
|
const props = {...rawProps};
|
|
117
|
-
|
|
119
|
+
if (!isHydrateOnVisible) {
|
|
120
|
+
delete props[import_shared_utils.HYDRATE_DIRECTIVE];
|
|
121
|
+
}
|
|
118
122
|
cmpInfo[specifier] = {startOffset, endOffset, props, tagName, specifier, hydrate};
|
|
119
123
|
}
|
|
120
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { descriptions, logger, LwrApplicationError, LwrError, stringifyError } from '@lwrjs/diagnostics';
|
|
2
2
|
import { ViewSpan, getTracer } from '@lwrjs/instrumentation';
|
|
3
|
-
import { HYDRATE_DIRECTIVE, addHeadMarkup, isCsrIsland, isHydrateOnLoad, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
|
|
3
|
+
import { HYDRATE_DIRECTIVE, addHeadMarkup, isCsrIsland, isHydrateOnLoad, isHydrateVisible, kebabCaseToModuleSpecifier, shortestTtl, } from '@lwrjs/shared-utils';
|
|
4
4
|
import { SSR_PROPS_ATTR, getPropsId, mergeWarnings } from '../utils.js';
|
|
5
5
|
import { getRenderer } from '../renderer.js';
|
|
6
6
|
/**
|
|
@@ -68,7 +68,10 @@ export default function lwcSsrViewTransformer(options, { config, moduleBundler,
|
|
|
68
68
|
if (hydrate) {
|
|
69
69
|
// Only serialize props for custom elements that are to be hydrated
|
|
70
70
|
const propsId = getPropsId();
|
|
71
|
-
|
|
71
|
+
const hydrateAttr = props && props[HYDRATE_DIRECTIVE]
|
|
72
|
+
? ` ${HYDRATE_DIRECTIVE}="${props[HYDRATE_DIRECTIVE]}"`
|
|
73
|
+
: '';
|
|
74
|
+
propsAttr = ` ${SSR_PROPS_ATTR}="${propsId}"${hydrateAttr}`;
|
|
72
75
|
serverData[propsId] = props;
|
|
73
76
|
}
|
|
74
77
|
const [, remain] = html.split(`<${tagName}`);
|
|
@@ -110,9 +113,13 @@ function getComponentsToSSR(customElements, stringBuilder) {
|
|
|
110
113
|
// Only SSR the custom elements which are NOT CSR islands or lwc:external
|
|
111
114
|
const { startOffset, endOffset } = location;
|
|
112
115
|
const specifier = kebabCaseToModuleSpecifier(tagName);
|
|
113
|
-
const
|
|
116
|
+
const isHydrateOnVisible = isHydrateVisible(rawProps);
|
|
117
|
+
const hydrate = isHydrateOnLoad(rawProps) || isHydrateOnVisible;
|
|
114
118
|
const props = { ...rawProps };
|
|
115
|
-
|
|
119
|
+
// We need to keep the directive for islands that will be hydrated when visibile
|
|
120
|
+
if (!isHydrateOnVisible) {
|
|
121
|
+
delete props[HYDRATE_DIRECTIVE];
|
|
122
|
+
}
|
|
116
123
|
cmpInfo[specifier] = { startOffset, endOffset, props, tagName, specifier, hydrate };
|
|
117
124
|
}
|
|
118
125
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.20.
|
|
7
|
+
"version": "0.20.2",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"package.cjs"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@lwrjs/config": "0.20.
|
|
52
|
-
"@lwrjs/diagnostics": "0.20.
|
|
53
|
-
"@lwrjs/instrumentation": "0.20.
|
|
54
|
-
"@lwrjs/loader": "0.20.
|
|
55
|
-
"@lwrjs/shared-utils": "0.20.
|
|
51
|
+
"@lwrjs/config": "0.20.2",
|
|
52
|
+
"@lwrjs/diagnostics": "0.20.2",
|
|
53
|
+
"@lwrjs/instrumentation": "0.20.2",
|
|
54
|
+
"@lwrjs/loader": "0.20.2",
|
|
55
|
+
"@lwrjs/shared-utils": "0.20.2",
|
|
56
56
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
57
57
|
"@rollup/plugin-terser": "^0.4.4",
|
|
58
58
|
"fs-extra": "^11.2.0",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"undici": "^6.21.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@lwrjs/types": "0.20.
|
|
64
|
+
"@lwrjs/types": "0.20.2",
|
|
65
65
|
"jest": "29.7.0",
|
|
66
66
|
"memfs": "^4.13.0",
|
|
67
67
|
"ts-jest": "^29.2.6"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"volta": {
|
|
76
76
|
"extends": "../../../package.json"
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "be82aca54f9a3b6cd18a4aac86f2f96c0184a930"
|
|
79
79
|
}
|