Skip to content

Commit aafc70f

Browse files
committed
feat: add enableSyntheticElementInternals flag
1 parent 1a8b40b commit aafc70f

File tree

11 files changed

+61
-9
lines changed

11 files changed

+61
-9
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { LightningElement as Component } from "lwc";
2+
3+
export default class Test extends Component {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"enableSyntheticElementInternals": true
3+
}

packages/@lwc/babel-plugin-component/src/__tests__/fixtures/component/enable-synthetic-element-internals/error.json

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import _tmpl from "./test.html";
2+
import { LightningElement as Component, registerComponent as _registerComponent } from "lwc";
3+
class Test extends Component {
4+
/*LWC compiler vX.X.X*/
5+
}
6+
const __lwc_component_class_internal = _registerComponent(Test, {
7+
tmpl: _tmpl,
8+
sel: "lwc-test",
9+
apiVersion: 9999999,
10+
enableSyntheticElementInternals: true
11+
});
12+
export default __lwc_component_class_internal;

packages/@lwc/babel-plugin-component/src/component.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
TEMPLATE_KEY,
1515
API_VERSION_KEY,
1616
COMPONENT_CLASS_ID,
17+
SYNTHETIC_ELEMENT_INTERNALS_KEY,
1718
} from './constants';
1819
import type { types, NodePath, Visitor } from '@babel/core';
1920
import type { BabelAPI, BabelTypes, LwcBabelPluginPass } from './types';
@@ -81,15 +82,28 @@ export default function ({ types: t }: BabelAPI): Visitor<LwcBabelPluginPass> {
8182
// sel: 'x-foo',
8283
// apiVersion: '58'
8384
// })
85+
const properties = [
86+
t.objectProperty(t.identifier(TEMPLATE_KEY), templateIdentifier),
87+
t.objectProperty(t.identifier(COMPONENT_NAME_KEY), componentRegisteredName),
88+
// It's important that, at this point, we have an APIVersion rather than just a number.
89+
// The client needs to trust the server that it's providing an actual known API version
90+
t.objectProperty(t.identifier(API_VERSION_KEY), t.numericLiteral(apiVersion)),
91+
];
92+
// Only include enableSyntheticElementInternals if explicitly defined
93+
if (typeof state.opts.enableSyntheticElementInternals === 'boolean') {
94+
const supportsSyntheticElementInternals = t.booleanLiteral(
95+
state.opts.enableSyntheticElementInternals || false
96+
);
97+
properties.push(
98+
t.objectProperty(
99+
t.identifier(SYNTHETIC_ELEMENT_INTERNALS_KEY),
100+
supportsSyntheticElementInternals
101+
)
102+
);
103+
}
84104
const registerComponentExpression = t.callExpression(registerComponentId, [
85105
node as types.Expression,
86-
t.objectExpression([
87-
t.objectProperty(t.identifier(TEMPLATE_KEY), templateIdentifier),
88-
t.objectProperty(t.identifier(COMPONENT_NAME_KEY), componentRegisteredName),
89-
// It's important that, at this point, we have an APIVersion rather than just a number.
90-
// The client needs to trust the server that it's providing an actual known API version
91-
t.objectProperty(t.identifier(API_VERSION_KEY), t.numericLiteral(apiVersion)),
92-
]),
106+
t.objectExpression(properties),
93107
]);
94108

95109
// Example:

packages/@lwc/babel-plugin-component/src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const TEMPLATE_KEY = 'tmpl';
3434
const COMPONENT_NAME_KEY = 'sel';
3535
const API_VERSION_KEY = 'apiVersion';
3636
const COMPONENT_CLASS_ID = '__lwc_component_class_internal';
37+
const SYNTHETIC_ELEMENT_INTERNALS_KEY = 'enableSyntheticElementInternals';
3738

3839
export {
3940
DECORATOR_TYPES,
@@ -46,4 +47,5 @@ export {
4647
COMPONENT_NAME_KEY,
4748
API_VERSION_KEY,
4849
COMPONENT_CLASS_ID,
50+
SYNTHETIC_ELEMENT_INTERNALS_KEY,
4951
};

packages/@lwc/babel-plugin-component/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface LwcBabelPluginOptions {
2121
name: string;
2222
instrumentation?: InstrumentationObject;
2323
apiVersion?: number;
24+
enableSyntheticElementInternals?: boolean;
2425
}
2526

2627
export interface LwcBabelPluginPass extends PluginPass {

packages/@lwc/compiler/src/options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ export interface TransformOptions {
108108
experimentalDynamicDirective?: boolean;
109109
/** Flag to enable usage of dynamic component(lwc:is) directive in HTML template */
110110
enableDynamicComponents?: boolean;
111+
/** Flag to enable usage of ElementInternals in synthetic shadow DOM */
112+
enableSyntheticElementInternals?: boolean;
111113
// TODO [#3370]: remove experimental template expression flag
112114
/** Flag to enable use of (a subset of) JavaScript expressions in place of template bindings. Passed to `@lwc/template-compiler`. */
113115
experimentalComplexExpressions?: boolean;
@@ -153,6 +155,7 @@ type OptionalTransformKeys =
153155
| 'enableLwcOn'
154156
| 'enableLightningWebSecurityTransforms'
155157
| 'enableDynamicComponents'
158+
| 'enableSyntheticElementInternals'
156159
| 'experimentalDynamicDirective'
157160
| 'experimentalDynamicComponent'
158161
| 'instrumentation';

packages/@lwc/engine-core/src/framework/base-lightning-element.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ import {
3838
} from '../libs/reflection';
3939

4040
import { HTMLElementOriginalDescriptors } from './html-properties';
41-
import { getComponentAPIVersion, getWrappedComponentsListener } from './component';
41+
import {
42+
getComponentAPIVersion,
43+
getWrappedComponentsListener,
44+
supportsSyntheticElementInternals,
45+
} from './component';
4246
import { isBeingConstructed, isInvokingRender, vmBeingConstructed } from './invoker';
4347
import { associateVM, getAssociatedVM, RenderMode, ShadowMode } from './vm';
4448
import { componentValueObserved } from './mutation-tracker';
@@ -493,6 +497,7 @@ function warnIfInvokedDuringConstruction(vm: VM, methodOrPropName: string) {
493497
attachInternals(): ElementInternals {
494498
const vm = getAssociatedVM(this);
495499
const {
500+
def: { ctor },
496501
elm,
497502
apiVersion,
498503
renderer: { attachInternals },
@@ -507,7 +512,7 @@ function warnIfInvokedDuringConstruction(vm: VM, methodOrPropName: string) {
507512
}
508513

509514
const internals = attachInternals(elm);
510-
if (vm.shadowMode === ShadowMode.Synthetic) {
515+
if (supportsSyntheticElementInternals(ctor) && vm.shadowMode === ShadowMode.Synthetic) {
511516
const handler: ProxyHandler<ElementInternals> = {
512517
get(target: ElementInternals, prop: keyof ElementInternals) {
513518
if (prop === 'shadowRoot') {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type ComponentConstructorMetadata = {
2424
tmpl: Template;
2525
sel: string;
2626
apiVersion: APIVersion;
27+
enableSyntheticElementInternals?: boolean | undefined;
2728
};
2829
const registeredComponentMap: Map<LightningElementConstructor, ComponentConstructorMetadata> =
2930
new Map();
@@ -76,6 +77,10 @@ export function getComponentAPIVersion(Ctor: LightningElementConstructor): APIVe
7677
return apiVersion;
7778
}
7879

80+
export function supportsSyntheticElementInternals(Ctor: LightningElementConstructor): boolean {
81+
return registeredComponentMap.get(Ctor)?.enableSyntheticElementInternals || false;
82+
}
83+
7984
export function getTemplateReactiveObserver(vm: VM): ReactiveObserver {
8085
const reactiveObserver = createReactiveObserver(() => {
8186
const { isDirty } = vm;

0 commit comments

Comments
 (0)