Skip to content

Commit 17417e9

Browse files
committed
chore: add a flag for signals try/catch fix
1 parent 7f13509 commit 17417e9

File tree

4 files changed

+58
-8
lines changed

4 files changed

+58
-8
lines changed

packages/@lwc/engine-core/src/framework/mutation-tracker.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ export function componentValueObserved(vm: VM, key: PropertyKey, target: any = {
4242
lwcRuntimeFlags.ENABLE_EXPERIMENTAL_SIGNALS &&
4343
isObject(target) &&
4444
!isNull(target) &&
45-
safeHasProp(target, 'value') &&
46-
safeHasProp(target, 'subscribe') &&
47-
isFunction(target.subscribe) &&
45+
(lwcRuntimeFlags.USE_TRY_CATCH_FOR_SIGNALS_CHECK
46+
? safeHasProp(target, 'value')
47+
: 'value' in target) &&
48+
(lwcRuntimeFlags.USE_TRY_CATCH_FOR_SIGNALS_CHECK
49+
? safeHasProp(target, 'subscribe')
50+
: 'subscribe' in target) &&
51+
isFunction((target as any).subscribe) &&
4852
isTrustedSignal(target) &&
4953
// Only subscribe if a template is being rendered by the engine
5054
tro.isObserving()

packages/@lwc/features/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const features: FeatureFlagMap = {
2020
ENABLE_FORCE_SHADOW_MIGRATE_MODE: null,
2121
ENABLE_EXPERIMENTAL_SIGNALS: null,
2222
DISABLE_SYNTHETIC_SHADOW: null,
23+
USE_TRY_CATCH_FOR_SIGNALS_CHECK: null,
2324
};
2425

2526
if (!(globalThis as any).lwcRuntimeFlags) {

packages/@lwc/features/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ export interface FeatureFlagMap {
7575
* native shadow mode.
7676
*/
7777
DISABLE_SYNTHETIC_SHADOW: FeatureFlagValue;
78+
79+
/**
80+
* Use a try/catch when sniffing for whether an object is a signal or not
81+
*/
82+
USE_TRY_CATCH_FOR_SIGNALS_CHECK: FeatureFlagValue;
7883
}
7984

8085
export type FeatureFlagName = keyof FeatureFlagMap;

packages/@lwc/integration-karma/test/signal/protocol/index.spec.js

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createElement, setFeatureFlagForTest } from 'lwc';
2+
import { catchUnhandledRejectionsAndErrors } from 'test-utils';
23
import Reactive from 'x/reactive';
34
import NonReactive from 'x/nonReactive';
45
import Container from 'x/container';
@@ -214,13 +215,52 @@ describe('signal protocol', () => {
214215
expect(subscribe).not.toHaveBeenCalled();
215216
});
216217

217-
it('does not throw an error for objects that throw upon "in" checks', async () => {
218-
const elm = createElement('x-throws', { is: Throws });
219-
document.body.appendChild(elm);
218+
describe('try/catch for the signals check', () => {
219+
describe('flag on', () => {
220+
beforeAll(() => {
221+
setFeatureFlagForTest('USE_TRY_CATCH_FOR_SIGNALS_CHECK', true);
222+
});
220223

221-
await Promise.resolve();
224+
afterAll(() => {
225+
setFeatureFlagForTest('USE_TRY_CATCH_FOR_SIGNALS_CHECK', false);
226+
});
227+
228+
it('does not throw an error for objects that throw upon "in" checks', async () => {
229+
const elm = createElement('x-throws', { is: Throws });
230+
document.body.appendChild(elm);
231+
232+
await Promise.resolve();
233+
234+
expect(elm.shadowRoot.querySelector('h1').textContent).toBe('hello');
235+
});
236+
});
222237

223-
expect(elm.shadowRoot.querySelector('h1').textContent).toBe('hello');
238+
describe('flag off', () => {
239+
let caughtError;
240+
241+
catchUnhandledRejectionsAndErrors((error) => {
242+
caughtError = error;
243+
});
244+
245+
afterEach(() => {
246+
caughtError = undefined;
247+
});
248+
249+
it('does throw an error for objects that throw upon "in" checks', async () => {
250+
const elm = createElement('x-throws', { is: Throws });
251+
document.body.appendChild(elm);
252+
253+
// wait 2 ticks for all errors to be caught
254+
await new Promise(setTimeout);
255+
await new Promise(setTimeout);
256+
257+
// still renders
258+
expect(elm.shadowRoot.querySelector('h1').textContent).toBe('hello');
259+
260+
// throws error
261+
expect(caughtError).not.toBeUndefined();
262+
});
263+
});
224264
});
225265
});
226266

0 commit comments

Comments
 (0)