@lwrjs/client-modules 0.20.3 → 0.20.5

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.
@@ -1,2 +1,2 @@
1
- import{BOOTSTRAP_END as e,INIT as o,INIT_MODULE as t}from"lwr/metrics";import{logOperationStart as r,logOperationEnd as n}from"lwr/profiler";import{hydrateComponent as i,createElement as s}from"lwc";const c="lwr:hydrate",l="visible";function a(e,o,t){i(e,o,t)}function d(e,o,t){const r=f||(f=new IntersectionObserver(((e,o)=>{e.forEach((e=>{if(e.isIntersecting){const t=e.target;o.unobserve(t);const r=p.get(t);if(r){p.delete(t);const{ctor:e,props:o}=r;a(t,e,o)}}}))}),{root:null,rootMargin:"100px"}),f);p.set(e,{ctor:o,props:t}),r.observe(e)}const p=new Map;let f;function u(e){return"IntersectionObserver"in globalThis&&e.getAttribute(c)===l}const m=(()=>{const e=globalThis,{SSREnabled:o}=e.LWR&&e.LWR.env||{};if(!globalThis.performance||!o)return()=>!1;let t=globalThis.performance.now();return()=>{const e=globalThis.performance.now();return e-t>50&&(t=e,!0)}})();function b(e,o){return s(e,{is:o})}function h(e){return e.replace(/\/v\/[a-zA-Z0-9-_.]+$/,"").replace("/","-").replace(/([A-Z])/g,(e=>`-${e.toLowerCase()}`))}const g=/-([a-z])/g;function w(e){return e.replace(g,(e=>e[1].toUpperCase()))}function v(i,s={}){void 0!==globalThis.customElements&&void 0!==globalThis.document?(r({id:o}),(async()=>{let e=0;const o=globalThis.document;for(const[c,l]of i){m()&&await y();const i=++e,p=h(c);if(!o.body.querySelector(p)){r({id:t,specifier:c,specifierIndex:i});const e=b(p,l),s=o.querySelector("[lwr-root]");s?s.appendChild(e):o.body.appendChild(e),n({id:t,specifier:c,specifierIndex:i,metadata:{renderMode:"spa"}});continue}const f=o.querySelectorAll(p);for(const e of f){r({id:t,specifier:c,specifierIndex:i});const o=e.dataset.lwrPropsId;if(o){u(e)?d(e,l,s[o]||{}):a(e,l,s[o]||{}),n({id:t,specifier:c,specifierIndex:i,metadata:{renderMode:"ssr"}});continue}const f=b(p,l);for(const{name:o,value:t}of e.attributes){f.setAttribute(o,t);const e=w(o);e in f&&(f[e]=t)}for(;e.childNodes.length>0;)f.appendChild(e.childNodes[0]);const m=e.parentElement;m&&m.replaceChild(f,e),n({id:t,specifier:c,specifierIndex:i,metadata:{renderMode:"csr"}})}}})(),n({id:o}),r({id:e})):r({id:e})}async function y(){const e=globalThis.scheduler;return function(e){let o,t=e[0],r=1;for(;r<e.length;){const n=e[r],i=e[r+1];if(r+=2,("optionalAccess"===n||"optionalCall"===n)&&null==t)return;"access"===n||"optionalAccess"===n?(o=t,t=i(t)):"call"!==n&&"optionalCall"!==n||(t=i(((...e)=>t.call(o,...e))),o=void 0)}return t}([e,"optionalAccess",e=>e.yield])?e.yield():new Promise((e=>setTimeout(e,0)))}export{c as HYDRATE_DIRECTIVE,l as HYDRATE_VISIBLE_VALUE,w as getPropFromAttrName,v as init,h as toKebabCase};
1
+ import{BOOTSTRAP_END as e,INIT as t,INIT_MODULE as o}from"lwr/metrics";import{logOperationStart as n,logOperationEnd as i}from"lwr/profiler";import{hydrateComponent as r,createElement as s}from"lwc";let c=0;async function l(){const e=function(e){if(!globalThis.performance||!function(){const e=globalThis,{SSREnabled:t}=e.LWR&&e.LWR.env||{};return!!t}())return{shouldYield:!1,timeOfLastYield:e};const t=50,o=globalThis.performance.now();if(o-e>t)return{shouldYield:!0,timeOfLastYield:o};return{shouldYield:!1,timeOfLastYield:e}}(c);e.shouldYield&&(c=e.timeOfLastYield,await async function(){const e=globalThis.scheduler;return function(e){let t,o=e[0],n=1;for(;n<e.length;){const i=e[n],r=e[n+1];if(n+=2,("optionalAccess"===i||"optionalCall"===i)&&null==o)return;"access"===i||"optionalAccess"===i?(t=o,o=r(o)):"call"!==i&&"optionalCall"!==i||(o=r(((...e)=>o.call(t,...e))),t=void 0)}return o}([e,"optionalAccess",e=>e.yield])?e.yield():new Promise((e=>setTimeout(e,0)))}())}const a="lwr:hydrate",d="visible";function f(e,t,o){r(e,t,o)}function p(e,t,o){const n=m||(m=new IntersectionObserver(((e,t)=>{e.forEach((e=>{if(e.isIntersecting){const o=e.target;t.unobserve(o);const n=u.get(o);if(n){u.delete(o);const{ctor:e,props:t}=n;f(o,e,t)}}}))}),{root:null,rootMargin:"100px"}),m);u.set(e,{ctor:t,props:o}),n.observe(e)}const u=new Map;let m;function h(e){return"IntersectionObserver"in globalThis&&e.getAttribute(a)===d}function b(e,t){return s(e,{is:t})}function g(e){return e.replace(/\/v\/[a-zA-Z0-9-_.]+$/,"").replace("/","-").replace(/([A-Z])/g,(e=>`-${e.toLowerCase()}`))}const w=/-([a-z])/g;function v(e){return e.replace(w,(e=>e[1].toUpperCase()))}function y(r,s={}){void 0!==globalThis.customElements&&void 0!==globalThis.document?(n({id:t}),(async()=>{let e=0;const t=globalThis.document;for(const[c,a]of r){await l();const r=++e,d=g(c);if(!t.body.querySelector(d)){n({id:o,specifier:c,specifierIndex:r});const e=b(d,a),s=t.querySelector("[lwr-root]");s?s.appendChild(e):t.body.appendChild(e),i({id:o,specifier:c,specifierIndex:r,metadata:{renderMode:"spa"}});continue}const u=t.querySelectorAll(d);for(const e of u){n({id:o,specifier:c,specifierIndex:r});const t=e.dataset.lwrPropsId;if(t){h(e)?p(e,a,s[t]||{}):f(e,a,s[t]||{}),i({id:o,specifier:c,specifierIndex:r,metadata:{renderMode:"ssr"}});continue}const l=b(d,a);for(const{name:t,value:o}of e.attributes){l.setAttribute(t,o);const e=v(t);e in l&&(l[e]=o)}for(;e.childNodes.length>0;)l.appendChild(e.childNodes[0]);const u=e.parentElement;u&&u.replaceChild(l,e),i({id:o,specifier:c,specifierIndex:r,metadata:{renderMode:"csr"}})}}})(),i({id:t}),n({id:e})):n({id:e})}export{a as HYDRATE_DIRECTIVE,d as HYDRATE_VISIBLE_VALUE,v as getPropFromAttrName,y as init,g as toKebabCase};
2
2
  //# sourceMappingURL=init.js.map
@@ -1,5 +1,6 @@
1
1
  import { BOOTSTRAP_END, INIT, INIT_MODULE } from 'lwr/metrics';
2
2
  import { logOperationStart, logOperationEnd } from 'lwr/profiler';
3
+ import { yieldIfNecessary } from 'lwr/scheduler';
3
4
  // TODO: This is a temporal workaround until https://github.com/salesforce/lwc/pull/2083 is sorted - tmp
4
5
  // eslint-disable-next-line lwr/only-allowed-imports
5
6
  import { createElement } from 'lwc';
@@ -77,28 +78,6 @@ function createVisibilityObserver() {
77
78
  });
78
79
  return visibilityObserver;
79
80
  }
80
- const shouldYield = (() => {
81
- const globalThisLWR = globalThis;
82
- const { SSREnabled } = (globalThisLWR.LWR && globalThisLWR.LWR.env) || {};
83
- // eslint-disable-next-line lwr/no-unguarded-apis
84
- if (!globalThis.performance || !SSREnabled) {
85
- return () => false;
86
- }
87
- // Break up hydration tasks into timed batches.
88
- // Borrowed from https://tinyurl.com/5b4fw7eb
89
- const TASK_BATCH_DURATION = 50;
90
- // eslint-disable-next-line lwr/no-unguarded-apis
91
- let timeOfLastYield = globalThis.performance.now();
92
- return () => {
93
- // eslint-disable-next-line lwr/no-unguarded-apis
94
- const now = globalThis.performance.now();
95
- if (now - timeOfLastYield > TASK_BATCH_DURATION) {
96
- timeOfLastYield = now;
97
- return true;
98
- }
99
- return false;
100
- };
101
- })();
102
81
  function initializeWebComponent(elementName, Ctor) {
103
82
  return createElement(elementName, { is: Ctor });
104
83
  }
@@ -145,11 +124,9 @@ export function init(rootModules, serverData = {}) {
145
124
  // eslint-disable-next-line lwr/no-unguarded-apis
146
125
  const document = globalThis.document;
147
126
  for (const [specifier, ctor] of rootModules) {
148
- if (shouldYield()) {
149
- // Yield to the main thread during long hydration tasks
150
- // eslint-disable-next-line no-await-in-loop
151
- await yieldToMainThread();
152
- }
127
+ // Yield to the main thread during long hydration tasks
128
+ // eslint-disable-next-line no-await-in-loop
129
+ await yieldIfNecessary();
153
130
  const specifierIndex = ++index;
154
131
  const elementName = toKebabCase(specifier);
155
132
  // initialize and inject the root module into the LWR Root or DOM if it is missing
@@ -229,10 +206,4 @@ export function init(rootModules, serverData = {}) {
229
206
  logOperationEnd({ id: INIT });
230
207
  logOperationStart({ id: BOOTSTRAP_END });
231
208
  }
232
- // Allows the browser to yield to the main thread during long-running tasks, improving responsiveness.
233
- async function yieldToMainThread() {
234
- const scheduler = globalThis.scheduler;
235
- // eslint-disable-next-line lwr/no-unguarded-apis
236
- return scheduler?.yield ? scheduler.yield() : new Promise((resolve) => setTimeout(resolve, 0));
237
- }
238
209
  //# sourceMappingURL=init.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Result of checking whether to yield to the main thread
3
+ */
4
+ export interface ShouldYieldResult {
5
+ shouldYield: boolean;
6
+ timeOfLastYield: number;
7
+ }
8
+ /**
9
+ * Reset the internal yield tracking state. Used primarily for testing.
10
+ * @internal
11
+ */
12
+ export declare function resetYieldTracking(): void;
13
+ /**
14
+ * Yields control to the main thread if enough time has elapsed since the last yield.
15
+ * This automatically tracks yield timing internally to break up long-running tasks
16
+ * into batches, improving responsiveness without requiring manual state management.
17
+ *
18
+ * @returns Promise that resolves after yielding (if necessary) to the main thread
19
+ */
20
+ export declare function yieldIfNecessary(): Promise<void>;
21
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1,66 @@
1
+ // Track the time of last yield for scheduler batching
2
+ let timeOfLastYield = 0;
3
+ /**
4
+ * Reset the internal yield tracking state. Used primarily for testing.
5
+ * @internal
6
+ */
7
+ export function resetYieldTracking() {
8
+ timeOfLastYield = 0;
9
+ }
10
+ /**
11
+ * Yields control to the main thread if enough time has elapsed since the last yield.
12
+ * This automatically tracks yield timing internally to break up long-running tasks
13
+ * into batches, improving responsiveness without requiring manual state management.
14
+ *
15
+ * @returns Promise that resolves after yielding (if necessary) to the main thread
16
+ */
17
+ export async function yieldIfNecessary() {
18
+ const result = checkShouldYield(timeOfLastYield);
19
+ if (result.shouldYield) {
20
+ timeOfLastYield = result.timeOfLastYield;
21
+ await yieldToMainThread();
22
+ }
23
+ }
24
+ /**
25
+ * Checks if the current execution should yield to the main thread based on elapsed time.
26
+ * Break up long-running tasks into timed batches to improve responsiveness.
27
+ * Borrowed from https://tinyurl.com/5b4fw7eb
28
+ *
29
+ * @param timeOfLastYield - Timestamp of the last yield (from performance.now())
30
+ * @returns Object containing whether to yield and the updated timestamp
31
+ */
32
+ function checkShouldYield(timeOfLastYield) {
33
+ // eslint-disable-next-line lwr/no-unguarded-apis
34
+ if (!globalThis.performance || !getSSREnabled()) {
35
+ return { shouldYield: false, timeOfLastYield };
36
+ }
37
+ const TASK_BATCH_DURATION = 50;
38
+ // eslint-disable-next-line lwr/no-unguarded-apis
39
+ const now = globalThis.performance.now();
40
+ if (now - timeOfLastYield > TASK_BATCH_DURATION) {
41
+ return { shouldYield: true, timeOfLastYield: now };
42
+ }
43
+ return { shouldYield: false, timeOfLastYield };
44
+ }
45
+ /**
46
+ * Yields control to the main thread during long-running tasks to improve responsiveness.
47
+ * Uses the scheduler.yield() API if available, otherwise falls back to setTimeout.
48
+ *
49
+ * @returns Promise that resolves after yielding to the main thread
50
+ */
51
+ async function yieldToMainThread() {
52
+ const scheduler = globalThis.scheduler;
53
+ // eslint-disable-next-line lwr/no-unguarded-apis
54
+ return scheduler?.yield ? scheduler.yield() : new Promise((resolve) => setTimeout(resolve, 0));
55
+ }
56
+ /**
57
+ * Gets the SSREnabled flag from the global LWR environment
58
+ *
59
+ * @returns Whether SSR is enabled
60
+ */
61
+ function getSSREnabled() {
62
+ const globalThisLWR = globalThis;
63
+ const { SSREnabled } = (globalThisLWR.LWR && globalThisLWR.LWR.env) || {};
64
+ return !!SSREnabled;
65
+ }
66
+ //# sourceMappingURL=scheduler.js.map
@@ -1,9 +1,8 @@
1
1
  // eslint-disable-next-line lwr/only-allowed-type-imports
2
2
 
3
- // eslint-disable-next-line lwr/only-allowed-type-imports
4
-
5
3
  import { BOOTSTRAP_END, INIT, INIT_MODULE } from 'lwr/metrics';
6
4
  import { logOperationStart, logOperationEnd } from 'lwr/profiler';
5
+ import { yieldIfNecessary } from 'lwr/scheduler';
7
6
 
8
7
  // TODO: This is a temporal workaround until https://github.com/salesforce/lwc/pull/2083 is sorted - tmp
9
8
  // eslint-disable-next-line lwr/only-allowed-imports
@@ -97,32 +96,6 @@ function createVisibilityObserver() {
97
96
  });
98
97
  return visibilityObserver;
99
98
  }
100
- const shouldYield = (() => {
101
- const globalThisLWR = globalThis;
102
- const {
103
- SSREnabled
104
- } = globalThisLWR.LWR && globalThisLWR.LWR.env || {};
105
-
106
- // eslint-disable-next-line lwr/no-unguarded-apis
107
- if (!globalThis.performance || !SSREnabled) {
108
- return () => false;
109
- }
110
-
111
- // Break up hydration tasks into timed batches.
112
- // Borrowed from https://tinyurl.com/5b4fw7eb
113
- const TASK_BATCH_DURATION = 50;
114
- // eslint-disable-next-line lwr/no-unguarded-apis
115
- let timeOfLastYield = globalThis.performance.now();
116
- return () => {
117
- // eslint-disable-next-line lwr/no-unguarded-apis
118
- const now = globalThis.performance.now();
119
- if (now - timeOfLastYield > TASK_BATCH_DURATION) {
120
- timeOfLastYield = now;
121
- return true;
122
- }
123
- return false;
124
- };
125
- })();
126
99
  function initializeWebComponent(elementName, Ctor) {
127
100
  return createElement(elementName, {
128
101
  is: Ctor
@@ -175,11 +148,9 @@ export function init(rootModules, serverData = {}) {
175
148
  // eslint-disable-next-line lwr/no-unguarded-apis
176
149
  const document = globalThis.document;
177
150
  for (const [specifier, ctor] of rootModules) {
178
- if (shouldYield()) {
179
- // Yield to the main thread during long hydration tasks
180
- // eslint-disable-next-line no-await-in-loop
181
- await yieldToMainThread();
182
- }
151
+ // Yield to the main thread during long hydration tasks
152
+ // eslint-disable-next-line no-await-in-loop
153
+ await yieldIfNecessary();
183
154
  const specifierIndex = ++index;
184
155
  const elementName = toKebabCase(specifier);
185
156
 
@@ -286,11 +257,4 @@ export function init(rootModules, serverData = {}) {
286
257
  logOperationStart({
287
258
  id: BOOTSTRAP_END
288
259
  });
289
- }
290
-
291
- // Allows the browser to yield to the main thread during long-running tasks, improving responsiveness.
292
- async function yieldToMainThread() {
293
- const scheduler = globalThis.scheduler;
294
- // eslint-disable-next-line lwr/no-unguarded-apis
295
- return scheduler?.yield ? scheduler.yield() : new Promise(resolve => setTimeout(resolve, 0));
296
260
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Result of checking whether to yield to the main thread
3
+ */
4
+
5
+ // Track the time of last yield for scheduler batching
6
+ let timeOfLastYield = 0;
7
+
8
+ /**
9
+ * Reset the internal yield tracking state. Used primarily for testing.
10
+ * @internal
11
+ */
12
+ export function resetYieldTracking() {
13
+ timeOfLastYield = 0;
14
+ }
15
+
16
+ /**
17
+ * Yields control to the main thread if enough time has elapsed since the last yield.
18
+ * This automatically tracks yield timing internally to break up long-running tasks
19
+ * into batches, improving responsiveness without requiring manual state management.
20
+ *
21
+ * @returns Promise that resolves after yielding (if necessary) to the main thread
22
+ */
23
+ export async function yieldIfNecessary() {
24
+ const result = checkShouldYield(timeOfLastYield);
25
+ if (result.shouldYield) {
26
+ timeOfLastYield = result.timeOfLastYield;
27
+ await yieldToMainThread();
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Checks if the current execution should yield to the main thread based on elapsed time.
33
+ * Break up long-running tasks into timed batches to improve responsiveness.
34
+ * Borrowed from https://tinyurl.com/5b4fw7eb
35
+ *
36
+ * @param timeOfLastYield - Timestamp of the last yield (from performance.now())
37
+ * @returns Object containing whether to yield and the updated timestamp
38
+ */
39
+ function checkShouldYield(timeOfLastYield) {
40
+ // eslint-disable-next-line lwr/no-unguarded-apis
41
+ if (!globalThis.performance || !getSSREnabled()) {
42
+ return {
43
+ shouldYield: false,
44
+ timeOfLastYield
45
+ };
46
+ }
47
+ const TASK_BATCH_DURATION = 50;
48
+ // eslint-disable-next-line lwr/no-unguarded-apis
49
+ const now = globalThis.performance.now();
50
+ if (now - timeOfLastYield > TASK_BATCH_DURATION) {
51
+ return {
52
+ shouldYield: true,
53
+ timeOfLastYield: now
54
+ };
55
+ }
56
+ return {
57
+ shouldYield: false,
58
+ timeOfLastYield
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Yields control to the main thread during long-running tasks to improve responsiveness.
64
+ * Uses the scheduler.yield() API if available, otherwise falls back to setTimeout.
65
+ *
66
+ * @returns Promise that resolves after yielding to the main thread
67
+ */
68
+ async function yieldToMainThread() {
69
+ const scheduler = globalThis.scheduler;
70
+ // eslint-disable-next-line lwr/no-unguarded-apis
71
+ return scheduler?.yield ? scheduler.yield() : new Promise(resolve => setTimeout(resolve, 0));
72
+ }
73
+
74
+ /**
75
+ * Gets the SSREnabled flag from the global LWR environment
76
+ *
77
+ * @returns Whether SSR is enabled
78
+ */
79
+ function getSSREnabled() {
80
+ const globalThisLWR = globalThis;
81
+ const {
82
+ SSREnabled
83
+ } = globalThisLWR.LWR && globalThisLWR.LWR.env || {};
84
+ return !!SSREnabled;
85
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.20.3",
7
+ "version": "0.20.5",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -34,10 +34,10 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@locker/sandbox": "0.25.3",
37
- "@lwrjs/shared-utils": "0.20.3"
37
+ "@lwrjs/shared-utils": "0.20.5"
38
38
  },
39
39
  "devDependencies": {
40
- "@lwrjs/types": "0.20.3",
40
+ "@lwrjs/types": "0.20.5",
41
41
  "@rollup/plugin-node-resolve": "^15.2.3",
42
42
  "@rollup/plugin-sucrase": "^5.0.2",
43
43
  "@rollup/plugin-terser": "^0.4.4",
@@ -61,7 +61,8 @@
61
61
  "lwr/lockerSandbox",
62
62
  "lwr/metrics",
63
63
  "lwr/profiler",
64
- "lwr/serverDataCallback"
64
+ "lwr/serverDataCallback",
65
+ "lwr/scheduler"
65
66
  ]
66
67
  },
67
68
  "engines": {
@@ -70,5 +71,5 @@
70
71
  "volta": {
71
72
  "extends": "../../../package.json"
72
73
  },
73
- "gitHead": "54759076bcb5d09e143a620e7653e2494658aefb"
74
+ "gitHead": "4ee0fa9b14629833090b379589202b9ac5a4a6c3"
74
75
  }