@lwrjs/client-modules 0.20.4 → 0.20.6

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,12 +1,9 @@
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
- import { createElement } from 'lwc';
6
- // <hydrateComponentProxy> - This code is removed in core
7
- // Note: a build step uses these comments to strip the code for core.
8
- // eslint-disable-next-line lwr/only-allowed-imports
9
- import { hydrateComponent } from 'lwc';
6
+ import { createElement, hydrateComponent } from 'lwc';
10
7
  // hydration directive + value constants
11
8
  // must align with the constants in @lwrjs/shared-utils/src/html-meta.ts
12
9
  export const HYDRATE_DIRECTIVE = 'lwr:hydrate';
@@ -14,7 +11,6 @@ export const HYDRATE_VISIBLE_VALUE = 'visible';
14
11
  function hydrateComponentProxy(customElement, Ctor, props) {
15
12
  hydrateComponent(customElement, Ctor, props);
16
13
  }
17
- // </hydrateComponentProxy>
18
14
  /**
19
15
  * Hydrate the custom element only when it is visible.
20
16
  * @param customElement - The custom element to hydrate
@@ -77,28 +73,6 @@ function createVisibilityObserver() {
77
73
  });
78
74
  return visibilityObserver;
79
75
  }
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
76
  function initializeWebComponent(elementName, Ctor) {
103
77
  return createElement(elementName, { is: Ctor });
104
78
  }
@@ -145,11 +119,9 @@ export function init(rootModules, serverData = {}) {
145
119
  // eslint-disable-next-line lwr/no-unguarded-apis
146
120
  const document = globalThis.document;
147
121
  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
- }
122
+ // Yield to the main thread during long hydration tasks
123
+ // eslint-disable-next-line no-await-in-loop
124
+ await yieldIfNecessary();
153
125
  const specifierIndex = ++index;
154
126
  const elementName = toKebabCase(specifier);
155
127
  // initialize and inject the root module into the LWR Root or DOM if it is missing
@@ -229,10 +201,4 @@ export function init(rootModules, serverData = {}) {
229
201
  logOperationEnd({ id: INIT });
230
202
  logOperationStart({ id: BOOTSTRAP_END });
231
203
  }
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
204
  //# 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,18 +1,12 @@
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
10
- import { createElement } from 'lwc';
11
-
12
- // <hydrateComponentProxy> - This code is removed in core
13
- // Note: a build step uses these comments to strip the code for core.
14
- // eslint-disable-next-line lwr/only-allowed-imports
15
- import { hydrateComponent } from 'lwc';
9
+ import { createElement, hydrateComponent } from 'lwc';
16
10
 
17
11
  // hydration directive + value constants
18
12
  // must align with the constants in @lwrjs/shared-utils/src/html-meta.ts
@@ -21,7 +15,6 @@ export const HYDRATE_VISIBLE_VALUE = 'visible';
21
15
  function hydrateComponentProxy(customElement, Ctor, props) {
22
16
  hydrateComponent(customElement, Ctor, props);
23
17
  }
24
- // </hydrateComponentProxy>
25
18
 
26
19
  /**
27
20
  * Hydrate the custom element only when it is visible.
@@ -97,32 +90,6 @@ function createVisibilityObserver() {
97
90
  });
98
91
  return visibilityObserver;
99
92
  }
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
93
  function initializeWebComponent(elementName, Ctor) {
127
94
  return createElement(elementName, {
128
95
  is: Ctor
@@ -175,11 +142,9 @@ export function init(rootModules, serverData = {}) {
175
142
  // eslint-disable-next-line lwr/no-unguarded-apis
176
143
  const document = globalThis.document;
177
144
  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
- }
145
+ // Yield to the main thread during long hydration tasks
146
+ // eslint-disable-next-line no-await-in-loop
147
+ await yieldIfNecessary();
183
148
  const specifierIndex = ++index;
184
149
  const elementName = toKebabCase(specifier);
185
150
 
@@ -286,11 +251,4 @@ export function init(rootModules, serverData = {}) {
286
251
  logOperationStart({
287
252
  id: BOOTSTRAP_END
288
253
  });
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
254
  }