From e360cc5023092e765f01e482c9c9bf5c2fd9546e Mon Sep 17 00:00:00 2001 From: James Tu Date: Fri, 5 Sep 2025 20:00:12 -0700 Subject: [PATCH 1/6] fix: check for connectedness before scheduling rehydration --- packages/@lwc/engine-core/src/framework/vm.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/@lwc/engine-core/src/framework/vm.ts b/packages/@lwc/engine-core/src/framework/vm.ts index 54db244bc1..edeadbbd79 100644 --- a/packages/@lwc/engine-core/src/framework/vm.ts +++ b/packages/@lwc/engine-core/src/framework/vm.ts @@ -673,7 +673,14 @@ function flushRehydrationQueue() { for (let i = 0, len = vms.length; i < len; i += 1) { const vm = vms[i]; try { - rehydrate(vm); + // We want to prevent rehydration from occurring when nodes are detached from the DOM as this can trigger + // unintended side effects, like lifecycle methods being called multiple times. + // For backwards compatibility, we use a flag to control the check. + // 1. When flag is disabled always rehydrate (legacy behavior) + // 2. When flag is enabled only rehydrate when the VM state is connected (fixed behavior) + if (!lwcRuntimeFlags.DISABLE_DETACHED_REHYDRATION || vm.state === VMState.connected) { + rehydrate(vm); + } } catch (error) { if (i + 1 < len) { // pieces of the queue are still pending to be rehydrated, those should have priority From f42948b1cf9b938d5755a6074f11bbb1bf516bd5 Mon Sep 17 00:00:00 2001 From: James Tu Date: Fri, 5 Sep 2025 20:01:02 -0700 Subject: [PATCH 2/6] chore: add new feature flags for fix --- packages/@lwc/features/src/index.ts | 1 + packages/@lwc/features/src/types.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/packages/@lwc/features/src/index.ts b/packages/@lwc/features/src/index.ts index 2c4608d7b0..59dc9624f2 100644 --- a/packages/@lwc/features/src/index.ts +++ b/packages/@lwc/features/src/index.ts @@ -23,6 +23,7 @@ const features: FeatureFlagMap = { DISABLE_SCOPE_TOKEN_VALIDATION: null, LEGACY_LOCKER_ENABLED: null, DISABLE_LEGACY_VALIDATION: null, + DISABLE_DETACHED_REHYDRATION: null, }; if (!(globalThis as any).lwcRuntimeFlags) { diff --git a/packages/@lwc/features/src/types.ts b/packages/@lwc/features/src/types.ts index ab7984b7a8..f66032f010 100644 --- a/packages/@lwc/features/src/types.ts +++ b/packages/@lwc/features/src/types.ts @@ -93,6 +93,12 @@ export interface FeatureFlagMap { * If false or unset, then the value of the `LEGACY_LOCKER_ENABLED` flag is used. */ DISABLE_LEGACY_VALIDATION: FeatureFlagValue; + + /** + * If true, skips rehydration of DOM elements that are not connected. + * Applies to rehydration performed while flushing the rehydration queue. + */ + DISABLE_DETACHED_REHYDRATION: FeatureFlagValue; } export type FeatureFlagName = keyof FeatureFlagMap; From fc014b563a7b8b7fd018bd68d88ea7d122b3ff8d Mon Sep 17 00:00:00 2001 From: James Tu Date: Fri, 5 Sep 2025 20:02:10 -0700 Subject: [PATCH 3/6] test: add flags for tests --- packages/@lwc/integration-not-karma/configs/base.js | 6 +++++- packages/@lwc/integration-not-karma/helpers/options.js | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/@lwc/integration-not-karma/configs/base.js b/packages/@lwc/integration-not-karma/configs/base.js index 4b08ac144f..1a7340646f 100644 --- a/packages/@lwc/integration-not-karma/configs/base.js +++ b/packages/@lwc/integration-not-karma/configs/base.js @@ -18,6 +18,7 @@ const env = { 'ENGINE_SERVER', 'FORCE_NATIVE_SHADOW_MODE_FOR_TEST', 'NATIVE_SHADOW', + 'DISABLE_DETACHED_REHYDRATION', ]), LWC_VERSION, NODE_ENV: options.NODE_ENV_FOR_TEST, @@ -61,7 +62,10 @@ export default {