Skip to content

Commit 0cbf753

Browse files
fix: @W-17528759 - add flag to control locker integration (#5136)
* mob: repro of constructor hack * feat: added legacy locker flag * fix: added locker flag to tests --------- Co-authored-by: Nolan Lawson <nlawson@salesforce.com>
1 parent bcd6391 commit 0cbf753

File tree

7 files changed

+50
-5
lines changed

7 files changed

+50
-5
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import { addErrorComponentStack } from '../shared/error';
1111
import { evaluateTemplate, setVMBeingRendered, getVMBeingRendered } from './template';
1212
import { runWithBoundaryProtection } from './vm';
1313
import { logOperationStart, logOperationEnd, OperationId } from './profiler';
14+
import { LightningElement } from './base-lightning-element';
1415
import type { Template } from './template';
1516
import type { VM } from './vm';
16-
import type { LightningElement, LightningElementConstructor } from './base-lightning-element';
17+
import type { LightningElementConstructor } from './base-lightning-element';
1718
import type { VNodes } from './vnodes';
1819

1920
export let isInvokingRender: boolean = false;
@@ -57,7 +58,11 @@ export function invokeComponentConstructor(vm: VM, Ctor: LightningElementConstru
5758
// the "instanceof" operator would not work here since Locker Service provides its own
5859
// implementation of LightningElement, so we indirectly check if the base constructor is
5960
// invoked by accessing the component on the vm.
60-
if (vmBeingConstructed.component !== result) {
61+
const isInvalidConstructor = lwcRuntimeFlags.ENABLE_LEGACY_LOCKER_SUPPORT
62+
? vmBeingConstructed.component !== result
63+
: !(result instanceof LightningElement);
64+
65+
if (isInvalidConstructor) {
6166
throw new TypeError(
6267
'Invalid component constructor, the class should extend LightningElement.'
6368
);

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+
ENABLE_LEGACY_LOCKER_SUPPORT: null,
2324
};
2425

2526
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
@@ -75,6 +75,12 @@ export interface FeatureFlagMap {
7575
* native shadow mode.
7676
*/
7777
DISABLE_SYNTHETIC_SHADOW: FeatureFlagValue;
78+
79+
/**
80+
* If true, then lightning legacy locker is supported, otherwise lightning legacy locker will not function
81+
* properly.
82+
*/
83+
ENABLE_LEGACY_LOCKER_SUPPORT: FeatureFlagValue;
7884
}
7985

8086
export type FeatureFlagName = keyof FeatureFlagMap;

packages/@lwc/integration-karma/test/api/createElement/index.spec.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createElement, LightningElement } from 'lwc';
1+
import { createElement, LightningElement, setFeatureFlagForTest } from 'lwc';
22
import { isNativeShadowRootInstance, isSyntheticShadowRootInstance } from 'test-utils';
33

44
import Test from 'x/test';
@@ -97,6 +97,12 @@ describe.runIf(process.env.NATIVE_SHADOW)('native shadow', () => {
9797
});
9898

9999
describe('locker integration', () => {
100+
beforeEach(() => {
101+
setFeatureFlagForTest('ENABLE_LEGACY_LOCKER_SUPPORT', true);
102+
});
103+
afterEach(() => {
104+
setFeatureFlagForTest('ENABLE_LEGACY_LOCKER_SUPPORT', false);
105+
});
100106
it('should support component class that extend a mirror of the LightningElement', () => {
101107
function SecureBaseClass() {
102108
if (this instanceof SecureBaseClass) {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import NotReturningThis from 'x/notReturningThis';
55
import ParentThrowingBeforeSuper from 'x/parentThrowingBeforeSuper';
66
import DefinedComponent from 'x/definedComponent';
77
import UndefinedComponent from 'x/undefinedComponent';
8+
import ReturningBad from 'x/returningBad';
89

910
it('should throw when trying to invoke the constructor manually', () => {
1011
const func = () => {
@@ -79,3 +80,12 @@ it("[W-6981076] shouldn't throw when a component with an invalid child in unmoun
7980
);
8081
expect(() => document.body.removeChild(elm)).not.toThrow();
8182
});
83+
84+
it('should fail when the constructor returns something other than an instance of itself', () => {
85+
expect(() => {
86+
createElement('x-returning-bad', { is: ReturningBad });
87+
}).toThrowError(
88+
TypeError,
89+
'Invalid component constructor, the class should extend LightningElement.'
90+
);
91+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { LightningElement } from 'lwc';
2+
3+
export default class MyClass extends LightningElement {
4+
constructor() {
5+
super();
6+
7+
const bad = {};
8+
LightningElement.call(bad);
9+
10+
return bad;
11+
}
12+
}

packages/@lwc/integration-karma/test/integrations/locker/index.spec.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { createElement } from 'lwc';
1+
import { createElement, setFeatureFlagForTest } from 'lwc';
22

33
import LockerIntegration from 'x/lockerIntegration';
44
import LockerLiveComponent from 'x/lockerLiveComponent';
55
import LockerHooks, { hooks } from 'x/lockerHooks';
6-
6+
beforeEach(() => {
7+
setFeatureFlagForTest('ENABLE_LEGACY_LOCKER_SUPPORT', true);
8+
});
9+
afterEach(() => {
10+
setFeatureFlagForTest('ENABLE_LEGACY_LOCKER_SUPPORT', false);
11+
});
712
it('should support Locker integration which uses a wrapped LightningElement base class', () => {
813
const elm = createElement('x-secure-parent', { is: LockerIntegration });
914
document.body.appendChild(elm);

0 commit comments

Comments
 (0)