Skip to content

Commit 4697c8b

Browse files
chore: re-introduce new constructor validation with gate
1 parent c40065c commit 4697c8b

File tree

4 files changed

+29
-12
lines changed

4 files changed

+29
-12
lines changed

packages/@lwc/engine-core/src/framework/invoker.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,19 @@ export function invokeComponentConstructor(vm: VM, Ctor: LightningElementConstru
5454
// job
5555
const result = new Ctor();
5656

57-
// Check indirectly if the constructor result is an instance of LightningElement. Using
58-
// the "instanceof" operator would not work here since Locker Service provides its own
59-
// implementation of LightningElement, so we indirectly check if the base constructor is
60-
// invoked by accessing the component on the vm.
57+
// Check indirectly if the constructor result is an instance of LightningElement.
58+
// When Locker is enabled, the "instanceof" operator would not work since Locker Service
59+
// provides its own implementation of LightningElement, so we indirectly check
60+
// if the base constructor is invoked by accessing the component on the vm.
61+
// When the ENABLE_LIGHTNING_CONSTRUCTOR_CHECK gate is true and LEGACY_LOCKER_ENABLED is false,
62+
// then the instanceof LightningElement can be used.
63+
const useLegacyConstructorCheck =
64+
!lwcRuntimeFlags.ENABLE_LIGHTNING_CONSTRUCTOR_CHECK ||
65+
lwcRuntimeFlags.LEGACY_LOCKER_ENABLED;
6166

62-
// TODO [W-17769475]: Restore this fix when we can reliably detect Locker enabled
63-
// const isInvalidConstructor = lwcRuntimeFlags.LEGACY_LOCKER_ENABLED
64-
// ? vmBeingConstructed.component !== result
65-
// : !(result instanceof LightningElement);
66-
const isInvalidConstructor = vmBeingConstructed.component !== result;
67+
const isInvalidConstructor = useLegacyConstructorCheck
68+
? vmBeingConstructed.component !== result
69+
: !(result instanceof LightningElement);
6770

6871
if (isInvalidConstructor) {
6972
throw new TypeError(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const features: FeatureFlagMap = {
2222
DISABLE_SYNTHETIC_SHADOW: null,
2323
DISABLE_SCOPE_TOKEN_VALIDATION: null,
2424
LEGACY_LOCKER_ENABLED: null,
25+
ENABLE_LIGHTNING_CONSTRUCTOR_CHECK: null,
2526
};
2627

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

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ export interface FeatureFlagMap {
8686
* properly.
8787
*/
8888
LEGACY_LOCKER_ENABLED: FeatureFlagValue;
89+
90+
/**
91+
* If true, then the legacy constructor check is only used if
92+
* LEGACY_LOCKER_ENABLED is true.
93+
*/
94+
ENABLE_LIGHTNING_CONSTRUCTOR_CHECK: FeatureFlagValue;
8995
}
9096

9197
export type FeatureFlagName = keyof FeatureFlagMap;

packages/@lwc/integration-karma/test/component/LightningElement/index.spec.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LightningElement, createElement } from 'lwc';
1+
import { LightningElement, createElement, setFeatureFlagForTest } from 'lwc';
22

33
import NotInvokingSuper from 'x/notInvokingSuper';
44
import NotReturningThis from 'x/notReturningThis';
@@ -81,12 +81,19 @@ it("[W-6981076] shouldn't throw when a component with an invalid child in unmoun
8181
expect(() => document.body.removeChild(elm)).not.toThrow();
8282
});
8383

84-
// TODO [W-17769475]: Restore this test when we can reliably detect Locker enabled
85-
xit('should fail when the constructor returns something other than an instance of itself', () => {
84+
it('should fail when the constructor returns something other than LightningElement when ENABLE_LIGHTNING_CONSTRUCTOR_CHECK is true', () => {
85+
setFeatureFlagForTest('ENABLE_LIGHTNING_CONSTRUCTOR_CHECK', true);
8686
expect(() => {
8787
createElement('x-returning-bad', { is: ReturningBad });
8888
}).toThrowError(
8989
TypeError,
9090
'Invalid component constructor, the class should extend LightningElement.'
9191
);
92+
setFeatureFlagForTest('ENABLE_LIGHTNING_CONSTRUCTOR_CHECK', false);
93+
});
94+
95+
it('should succeed when the constructor returns something other than LightningElement when ENABLE_LIGHTNING_CONSTRUCTOR_CHECK is falsy', () => {
96+
expect(() => {
97+
createElement('x-returning-bad', { is: ReturningBad });
98+
}).not.toThrow();
9299
});

0 commit comments

Comments
 (0)