From 750f5573ec5d8f183cc72ada5ff7a28df85ab2e2 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Thu, 25 Jul 2024 13:04:21 -0700 Subject: [PATCH] perf: optimize scoped ID for light/native (#4399) --- .github/workflows/karma.yml | 1 + packages/@lwc/compiler/README.md | 2 +- packages/@lwc/compiler/src/options.ts | 2 +- .../compiler/src/transformers/template.ts | 2 + .../@lwc/engine-core/src/framework/api.ts | 14 - .../Element-properties/Element.id.spec.js | 24 +- .../synthetic-shadow/scoped-id/aria.spec.js | 24 +- .../synthetic-shadow/scoped-id/href.spec.js | 30 + .../hrefDynamicEmptyString.html | 13 + .../hrefDynamicEmptyString.js | 7 + .../x/hrefDynamicNull/hrefDynamicNull.html | 13 + .../x/hrefDynamicNull/hrefDynamicNull.js | 7 + .../hrefDynamicUndefined.html | 13 + .../hrefDynamicUndefined.js | 7 + packages/@lwc/template-compiler/README.md | 1 + .../src/__tests__/config.spec.ts | 1 + .../static-optimized/light/actual.html | 15 + .../static-optimized/light/ast.json | 641 ++++++++++++++++++ .../static-optimized/light/config.json | 3 + .../static-optimized/light/expected.js | 77 +++ .../static-optimized/light/metadata.json | 3 + .../native-shadow/actual.html | 15 + .../static-optimized/native-shadow/ast.json | 624 +++++++++++++++++ .../native-shadow/config.json | 4 + .../native-shadow/expected.js | 76 +++ .../native-shadow/metadata.json | 3 + .../synthetic-shadow/actual.html | 15 + .../synthetic-shadow/ast.json | 624 +++++++++++++++++ .../synthetic-shadow/config.json | 4 + .../synthetic-shadow/expected.js | 121 ++++ .../synthetic-shadow/metadata.json | 3 + .../static-unoptimized/light/actual.html | 15 + .../static-unoptimized/light/ast.json | 641 ++++++++++++++++++ .../static-unoptimized/light/config.json | 3 + .../static-unoptimized/light/expected.js | 87 +++ .../static-unoptimized/light/metadata.json | 3 + .../native-shadow/actual.html | 15 + .../static-unoptimized/native-shadow/ast.json | 624 +++++++++++++++++ .../native-shadow/config.json | 4 + .../native-shadow/expected.js | 86 +++ .../native-shadow/metadata.json | 3 + .../synthetic-shadow/actual.html | 15 + .../synthetic-shadow/ast.json | 624 +++++++++++++++++ .../synthetic-shadow/config.json | 4 + .../synthetic-shadow/expected.js | 99 +++ .../synthetic-shadow/metadata.json | 3 + .../template-compiler/src/codegen/codegen.ts | 36 +- .../src/codegen/static-element-serializer.ts | 39 +- packages/@lwc/template-compiler/src/config.ts | 5 + 49 files changed, 4605 insertions(+), 90 deletions(-) create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.html create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.js create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.html create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.js create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.html create mode 100644 packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/metadata.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/metadata.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/metadata.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/metadata.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/metadata.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/actual.html create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/ast.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/config.json create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/expected.js create mode 100644 packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/metadata.json diff --git a/.github/workflows/karma.yml b/.github/workflows/karma.yml index ed8f477c42..1ec2b4be11 100644 --- a/.github/workflows/karma.yml +++ b/.github/workflows/karma.yml @@ -135,6 +135,7 @@ jobs: - run: API_VERSION=61 yarn sauce:ci - run: API_VERSION=61 DISABLE_SYNTHETIC=1 yarn sauce:ci - run: DISABLE_SYNTHETIC_SHADOW_SUPPORT_IN_COMPILER=1 DISABLE_SYNTHETIC=1 yarn sauce:ci + - run: DISABLE_SYNTHETIC_SHADOW_SUPPORT_IN_COMPILER=1 DISABLE_SYNTHETIC=1 DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn sauce:ci - run: ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL=1 yarn sauce:ci - run: ENABLE_ARIA_REFLECTION_GLOBAL_POLYFILL=1 DISABLE_SYNTHETIC=1 yarn sauce:ci - run: DISABLE_STATIC_CONTENT_OPTIMIZATION=1 yarn sauce:ci diff --git a/packages/@lwc/compiler/README.md b/packages/@lwc/compiler/README.md index 51299e50cd..5bc815b4e2 100644 --- a/packages/@lwc/compiler/README.md +++ b/packages/@lwc/compiler/README.md @@ -56,7 +56,7 @@ const { code } = transformSync(source, filename, options); - `customRendererConfig` (type: `object`, optional) - custom renderer config to pass to `@lwc/template-compiler`. See that package's README for details. - `enableLightningWebSecurityTransforms` (type: `boolean`, default: `false`) - The configuration to enable Lighting Web Security specific transformations. - `enableLwcSpread` (boolean, optional, `true` by default) - Deprecated. Ignored by compiler. `lwc:spread` is always enabled. - - `disableSyntheticShadowSupport` (type: `boolean`, default: `false`) - Set to true if synthetic shadow DOM support is not needed, which can result in smaller output. + - `disableSyntheticShadowSupport` (type: `boolean`, default: `false`) - Set to true if synthetic shadow DOM support is not needed, which can result in smaller/faster output. - `instrumentation` (type: `InstrumentationObject`, optional) - instrumentation object to gather metrics and non-error logs for internal use. See the `@lwc/errors` package for details on the interface. - `apiVersion` (type: `number`, optional) - API version to associate with the compiled module. diff --git a/packages/@lwc/compiler/src/options.ts b/packages/@lwc/compiler/src/options.ts index 9592f1cd71..fe9213fb06 100755 --- a/packages/@lwc/compiler/src/options.ts +++ b/packages/@lwc/compiler/src/options.ts @@ -115,7 +115,7 @@ export interface TransformOptions { customRendererConfig?: CustomRendererConfig; /** @deprecated Ignored by compiler. `lwc:spread` is always enabled. */ enableLwcSpread?: boolean; - /** Set to true if synthetic shadow DOM support is not needed, which can result in smaller output. */ + /** Set to true if synthetic shadow DOM support is not needed, which can result in smaller/faster output. */ disableSyntheticShadowSupport?: boolean; /** * Enable transformations specific to {@link https://developer.salesforce.com/docs/platform/lwc/guide/security-lwsec-intro.html Lighting Web Security}. diff --git a/packages/@lwc/compiler/src/transformers/template.ts b/packages/@lwc/compiler/src/transformers/template.ts index c0a8f7a04a..daf3dcbe25 100755 --- a/packages/@lwc/compiler/src/transformers/template.ts +++ b/packages/@lwc/compiler/src/transformers/template.ts @@ -44,6 +44,7 @@ export default function templateTransform( namespace, name, apiVersion, + disableSyntheticShadowSupport, } = options; const experimentalDynamicDirective = deprecatedDynamicDirective ?? Boolean(experimentalDynamicComponent); @@ -62,6 +63,7 @@ export default function templateTransform( enableDynamicComponents, instrumentation, apiVersion, + disableSyntheticShadowSupport, }); } catch (e) { throw normalizeToCompilerError(TransformerErrors.HTML_TRANSFORMER_ERROR, e, { filename }); diff --git a/packages/@lwc/engine-core/src/framework/api.ts b/packages/@lwc/engine-core/src/framework/api.ts index c8ce18f96f..498e844ec1 100644 --- a/packages/@lwc/engine-core/src/framework/api.ts +++ b/packages/@lwc/engine-core/src/framework/api.ts @@ -564,12 +564,6 @@ function k(compilerKey: number, obj: any): string | void { function gid(id: string | undefined | null): string | null | undefined { const vmBeingRendered = getVMBeingRendered()!; if (isUndefined(id) || id === '') { - if (process.env.NODE_ENV !== 'production') { - logError( - `Invalid id value "${id}". The id attribute must contain a non-empty string.`, - vmBeingRendered - ); - } return id; } // We remove attributes when they are assigned a value of null @@ -587,14 +581,6 @@ function gid(id: string | undefined | null): string | null | undefined { function fid(url: string | undefined | null): string | null | undefined { const vmBeingRendered = getVMBeingRendered()!; if (isUndefined(url) || url === '') { - if (process.env.NODE_ENV !== 'production') { - if (isUndefined(url)) { - logError( - `Undefined url value for "href" or "xlink:href" attribute. Expected a non-empty string.`, - vmBeingRendered - ); - } - } return url; } // We remove attributes when they are assigned a value of null diff --git a/packages/@lwc/integration-karma/test/shadow-dom/Element-properties/Element.id.spec.js b/packages/@lwc/integration-karma/test/shadow-dom/Element-properties/Element.id.spec.js index 01eb994e1c..e3efccef71 100644 --- a/packages/@lwc/integration-karma/test/shadow-dom/Element-properties/Element.id.spec.js +++ b/packages/@lwc/integration-karma/test/shadow-dom/Element-properties/Element.id.spec.js @@ -19,11 +19,7 @@ describe('scoped-ids', () => { describe('custom elements', () => { it('should render expected id attribute value when its value is set to `undefined`', () => { const elm = createElement('x-foo', { is: CustomElementIdValueUndefined }); - expect(() => { - document.body.appendChild(elm); - }).toLogErrorDev( - /\[LWC error\]: Invalid id value "undefined". The id attribute must contain a non-empty string./ - ); + document.body.appendChild(elm); const child = elm.shadowRoot.querySelector('x-child'); // #1769: The difference in behavior of id attribute is tracked with this issue expect(child.getAttribute('id')).toBe('undefined'); @@ -31,11 +27,7 @@ describe('scoped-ids', () => { it('should render the id attribute as a boolean attribute when its value is set to an empty string', () => { const elm = createElement('x-foo', { is: CustomElementIdValueEmpty }); - expect(() => { - document.body.appendChild(elm); - }).toLogErrorDev( - /\[LWC error\]: Invalid id value "". The id attribute must contain a non-empty string./ - ); + document.body.appendChild(elm); const child = elm.shadowRoot.querySelector('x-child'); expect(child.getAttribute('id')).toBe(''); }); @@ -44,22 +36,14 @@ describe('scoped-ids', () => { describe('native elements', () => { it('should not render id attribute when its value is set to null', () => { const elm = createElement('x-foo', { is: IdValueUndefined }); - expect(() => { - document.body.appendChild(elm); - }).toLogErrorDev( - /\[LWC error\]: Invalid id value "undefined". The id attribute must contain a non-empty string./ - ); + document.body.appendChild(elm); const div = elm.shadowRoot.querySelector('div'); expect(div.getAttribute('id')).toBeNull(); }); it('should render the id attribute as a boolean attribute when its value is set to an empty string', () => { const elm = createElement('x-foo', { is: IdValueEmpty }); - expect(() => { - document.body.appendChild(elm); - }).toLogErrorDev( - /\[LWC error\]: Invalid id value "". The id attribute must contain a non-empty string./ - ); + document.body.appendChild(elm); const div = elm.shadowRoot.querySelector('div'); expect(div.getAttribute('id')).toBe(''); }); diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/aria.spec.js b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/aria.spec.js index 9c9e130962..ca68b42aff 100644 --- a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/aria.spec.js +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/aria.spec.js @@ -1,5 +1,4 @@ import { createElement } from 'lwc'; -import { spyConsole } from 'test-utils'; import AriaStatic from 'x/ariaStatic'; import AriaDynamic from 'x/ariaDynamic'; @@ -26,27 +25,8 @@ function testAria(type, create) { beforeEach(async () => { elm = create(); - const consoleSpy = spyConsole(); - try { - document.body.appendChild(elm); - await Promise.resolve(); - - // empty string (`
`) is expected to log an error, but not boolean true (`
`) - // due to backwards compat - if (process.env.NODE_ENV !== 'production' && type === 'empty-string') { - expect(consoleSpy.calls.error.length).toEqual(10); - for (const call of consoleSpy.calls.error) { - expect(call[0].message).toMatch( - /The id attribute must contain a non-empty string/ - ); - } - } else { - expect(consoleSpy.calls.error.length).toEqual(0); - } - expect(consoleSpy.calls.warn.length).toEqual(0); - } finally { - consoleSpy.reset(); - } + document.body.appendChild(elm); + await Promise.resolve(); }); it('should transform the `for` attribute value', () => { diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/href.spec.js b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/href.spec.js index 83e070859c..88202b0f57 100644 --- a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/href.spec.js +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/href.spec.js @@ -5,6 +5,9 @@ import HrefDynamic from 'x/hrefDynamic'; import HrefDangling from 'x/hrefDangling'; import HrefBooleanTrue from 'x/hrefBooleanTrue'; import HrefBooleanTrueNoId from 'x/hrefBooleanTrueNoId'; +import HrefDynamicEmptyString from 'x/hrefDynamicEmptyString'; +import HrefDynamicUndefined from 'x/hrefDynamicUndefined'; +import HrefDynamicNull from 'x/hrefDynamicNull'; function testHref(type, create) { describe(`${type} href attribute values`, () => { @@ -96,3 +99,30 @@ describe('boolean true', () => { }); }); }); + +describe('dynamic empty value', () => { + const scenarios = [ + { + name: 'empty string', + Ctor: HrefDynamicEmptyString, + tagName: 'x-href-dynamic-empty-string', + }, + { name: 'undefined', Ctor: HrefDynamicUndefined, tagName: 'x-href-dynamic-undefined' }, + { name: 'null', Ctor: HrefDynamicNull, tagName: 'x-href-dynamic-null' }, + ]; + + scenarios.forEach(({ name, Ctor, tagName }) => { + describe(name, () => { + it('renders href as expected', () => { + const elm = createElement(tagName, { is: Ctor }); + document.body.appendChild(elm); + + const expected = name === 'empty string' ? '' : null; + + expect(elm.shadowRoot.querySelector('.sanjo').getAttribute('id')).toBe(expected); + expect(elm.shadowRoot.querySelector('a').getAttribute('href')).toBe(expected); + expect(elm.shadowRoot.querySelector('area').getAttribute('href')).toBe(expected); + }); + }); + }); +}); diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.html b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.html new file mode 100644 index 0000000000..d08ae6c6b6 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.html @@ -0,0 +1,13 @@ + diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.js b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.js new file mode 100644 index 0000000000..30a2b869c0 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicEmptyString/hrefDynamicEmptyString.js @@ -0,0 +1,7 @@ +import { LightningElement } from 'lwc'; + +export default class HrefDynamicEmptyString extends LightningElement { + get emptyString() { + return ''; + } +} diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.html b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.html new file mode 100644 index 0000000000..9f27076c78 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.html @@ -0,0 +1,13 @@ + diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.js b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.js new file mode 100644 index 0000000000..509b6a6903 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicNull/hrefDynamicNull.js @@ -0,0 +1,7 @@ +import { LightningElement } from 'lwc'; + +export default class HrefDynamicNull extends LightningElement { + get nullo() { + return null; + } +} diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.html b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.html new file mode 100644 index 0000000000..962aa658f3 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.html @@ -0,0 +1,13 @@ + diff --git a/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.js b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.js new file mode 100644 index 0000000000..756a3a7f75 --- /dev/null +++ b/packages/@lwc/integration-karma/test/synthetic-shadow/scoped-id/x/hrefDynamicUndefined/hrefDynamicUndefined.js @@ -0,0 +1,7 @@ +import { LightningElement } from 'lwc'; + +export default class HrefDynamicUndefined extends LightningElement { + get undef() { + return undefined; + } +} diff --git a/packages/@lwc/template-compiler/README.md b/packages/@lwc/template-compiler/README.md index 41ee96566c..8bc0c143c8 100644 --- a/packages/@lwc/template-compiler/README.md +++ b/packages/@lwc/template-compiler/README.md @@ -62,6 +62,7 @@ const { code, warnings } = compile(``, - `enableLwcSpread` (boolean, optional, `true` by default) - Deprecated. Ignored by template-compiler. `lwc:spread` is always enabled. - `customRendererConfig` (CustomRendererConfig, optional) - specifies a configuration to use to match elements. Matched elements will get a custom renderer hook in the generated template. - `instrumentation` (InstrumentationObject, optional) - instrumentation object to gather metrics and non-error logs for internal use. See the `@lwc/errors` package for details on the interface. +- `disableSyntheticShadowSupport` (type: `boolean`, default: `false`) - Set to true if synthetic shadow DOM support is not needed, which can result in smaller/faster output. - Example 1: Config to match `` elements under the `svg` namespace and have `href` attribute set. diff --git a/packages/@lwc/template-compiler/src/__tests__/config.spec.ts b/packages/@lwc/template-compiler/src/__tests__/config.spec.ts index 5666e4cd90..181f8a8ed5 100644 --- a/packages/@lwc/template-compiler/src/__tests__/config.spec.ts +++ b/packages/@lwc/template-compiler/src/__tests__/config.spec.ts @@ -47,6 +47,7 @@ describe('customRendererConfig normalization', () => { }, ], }, + "disableSyntheticShadowSupport": false, "enableDynamicComponents": false, "enableLwcSpread": true, "enableStaticContentOptimization": true, diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/actual.html new file mode 100644 index 0000000000..d4b7a2482e --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/ast.json new file mode 100644 index 0000000000..370b6b1c14 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/ast.json @@ -0,0 +1,641 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 423, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 35, + "start": 0, + "end": 34 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 412, + "end": 423 + } + }, + "directives": [ + { + "type": "Directive", + "name": "RenderMode", + "value": { + "type": "Literal", + "value": "light" + }, + "location": { + "startLine": 1, + "startColumn": 11, + "endLine": 1, + "endColumn": 34, + "start": 10, + "end": 33 + } + } + ], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 39, + "end": 61 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 66, + "end": 100, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 66, + "end": 83 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 92, + "end": 100 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 73, + "end": 82 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 83, + "end": 92 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 105, + "end": 137, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 105, + "end": 137 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 112, + "end": 127 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 128, + "end": 136 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 143, + "end": 177, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 143, + "end": 158 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 173, + "end": 177 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 146, + "end": 157 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 158, + "end": 173 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 182, + "end": 222, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 182, + "end": 200 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 212, + "end": 222 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 191, + "end": 199 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 200, + "end": 212 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 228, + "end": 251 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 256, + "end": 290, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 256, + "end": 273 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 282, + "end": 290 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 263, + "end": 272 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 263, + "end": 272 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 273, + "end": 282 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 295, + "end": 327, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 295, + "end": 327 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 302, + "end": 317 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 318, + "end": 326 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 318, + "end": 326 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 333, + "end": 366, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 333, + "end": 347 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 362, + "end": 366 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 336, + "end": 346 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 336, + "end": 346 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 347, + "end": 362 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 371, + "end": 411, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 371, + "end": 389 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 401, + "end": 411 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 380, + "end": 388 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 380, + "end": 388 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 389, + "end": 401 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/config.json new file mode 100644 index 0000000000..e6e73eecd0 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/config.json @@ -0,0 +1,3 @@ +{ + "enableStaticContentOptimization": true +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/expected.js new file mode 100644 index 0000000000..864f861c2c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/expected.js @@ -0,0 +1,77 @@ +import _implicitStylesheets from "./light.css"; +import _implicitScopedStylesheets from "./light.scoped.css?scoped=true"; +import { freezeTemplate, parseFragment, registerTemplate } from "lwc"; +const $fragment1 = parseFragment``; +const $fragment2 = parseFragment``; +const $fragment3 = parseFragment`Click to scroll`; +const $fragment4 = parseFragment`
Scroll to me
`; +const $fragment5 = parseFragment`Click me:`; +const $fragment6 = parseFragment``; +const $fragment7 = parseFragment`Click to scroll`; +const $fragment8 = parseFragment`Scroll to me`; +function tmpl($api, $cmp, $slotset, $ctx) { + const { st: api_static_fragment, sp: api_static_part } = $api; + return [ + api_static_fragment($fragment1, 1), + api_static_fragment($fragment2, 3), + api_static_fragment($fragment3, 5), + api_static_fragment($fragment4, 7), + api_static_fragment($fragment5, 9, [ + api_static_part( + 0, + { + attrs: { + for: $cmp.foo, + }, + }, + null + ), + ]), + api_static_fragment($fragment6, 11, [ + api_static_part( + 0, + { + attrs: { + id: $cmp.foo, + }, + }, + null + ), + ]), + api_static_fragment($fragment7, 13, [ + api_static_part( + 0, + { + attrs: { + href: $cmp.bar, + }, + }, + null + ), + ]), + api_static_fragment($fragment8, 15, [ + api_static_part( + 0, + { + attrs: { + id: $cmp.bar, + }, + }, + null + ), + ]), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.renderMode = "light"; +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-1kadf5igpar"; +tmpl.legacyStylesheetToken = "x-light_light"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/light/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/actual.html new file mode 100644 index 0000000000..33f76b4da8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/ast.json new file mode 100644 index 0000000000..81163d65b8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/ast.json @@ -0,0 +1,624 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 399, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 11, + "start": 0, + "end": 10 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 388, + "end": 399 + } + }, + "directives": [], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 15, + "end": 37 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 42, + "end": 76, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 42, + "end": 59 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 68, + "end": 76 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 49, + "end": 58 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 59, + "end": 68 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 88, + "end": 103 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 104, + "end": 112 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 119, + "end": 153, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 119, + "end": 134 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 149, + "end": 153 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 122, + "end": 133 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 134, + "end": 149 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 158, + "end": 198, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 158, + "end": 176 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 188, + "end": 198 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 167, + "end": 175 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 176, + "end": 188 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 204, + "end": 227 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 232, + "end": 266, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 232, + "end": 249 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 258, + "end": 266 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 249, + "end": 258 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 278, + "end": 293 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 309, + "end": 342, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 309, + "end": 323 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 338, + "end": 342 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 323, + "end": 338 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 347, + "end": 387, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 347, + "end": 365 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 377, + "end": 387 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 365, + "end": 377 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/config.json new file mode 100644 index 0000000000..b7e19f0f57 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/config.json @@ -0,0 +1,4 @@ +{ + "enableStaticContentOptimization": true, + "disableSyntheticShadowSupport": true +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/expected.js new file mode 100644 index 0000000000..054894217f --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/expected.js @@ -0,0 +1,76 @@ +import _implicitStylesheets from "./native-shadow.css"; +import _implicitScopedStylesheets from "./native-shadow.scoped.css?scoped=true"; +import { freezeTemplate, parseFragment, registerTemplate } from "lwc"; +const $fragment1 = parseFragment``; +const $fragment2 = parseFragment``; +const $fragment3 = parseFragment`Click to scroll`; +const $fragment4 = parseFragment`
Scroll to me
`; +const $fragment5 = parseFragment`Click me:`; +const $fragment6 = parseFragment``; +const $fragment7 = parseFragment`Click to scroll`; +const $fragment8 = parseFragment`Scroll to me`; +function tmpl($api, $cmp, $slotset, $ctx) { + const { st: api_static_fragment, sp: api_static_part } = $api; + return [ + api_static_fragment($fragment1, 1), + api_static_fragment($fragment2, 3), + api_static_fragment($fragment3, 5), + api_static_fragment($fragment4, 7), + api_static_fragment($fragment5, 9, [ + api_static_part( + 0, + { + attrs: { + for: $cmp.foo, + }, + }, + null + ), + ]), + api_static_fragment($fragment6, 11, [ + api_static_part( + 0, + { + attrs: { + id: $cmp.foo, + }, + }, + null + ), + ]), + api_static_fragment($fragment7, 13, [ + api_static_part( + 0, + { + attrs: { + href: $cmp.bar, + }, + }, + null + ), + ]), + api_static_fragment($fragment8, 15, [ + api_static_part( + 0, + { + attrs: { + id: $cmp.bar, + }, + }, + null + ), + ]), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-54b380gv09b"; +tmpl.legacyStylesheetToken = "x-native-shadow_native-shadow"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/native-shadow/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/actual.html new file mode 100644 index 0000000000..33f76b4da8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/ast.json new file mode 100644 index 0000000000..81163d65b8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/ast.json @@ -0,0 +1,624 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 399, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 11, + "start": 0, + "end": 10 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 388, + "end": 399 + } + }, + "directives": [], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 15, + "end": 37 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 42, + "end": 76, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 42, + "end": 59 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 68, + "end": 76 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 49, + "end": 58 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 59, + "end": 68 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 88, + "end": 103 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 104, + "end": 112 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 119, + "end": 153, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 119, + "end": 134 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 149, + "end": 153 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 122, + "end": 133 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 134, + "end": 149 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 158, + "end": 198, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 158, + "end": 176 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 188, + "end": 198 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 167, + "end": 175 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 176, + "end": 188 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 204, + "end": 227 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 232, + "end": 266, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 232, + "end": 249 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 258, + "end": 266 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 249, + "end": 258 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 278, + "end": 293 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 309, + "end": 342, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 309, + "end": 323 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 338, + "end": 342 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 323, + "end": 338 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 347, + "end": 387, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 347, + "end": 365 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 377, + "end": 387 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 365, + "end": 377 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/config.json new file mode 100644 index 0000000000..2d41150745 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/config.json @@ -0,0 +1,4 @@ +{ + "enableStaticContentOptimization": true, + "disableSyntheticShadowSupport": false +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/expected.js new file mode 100644 index 0000000000..5d8ad8e0b1 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/expected.js @@ -0,0 +1,121 @@ +import _implicitStylesheets from "./synthetic-shadow.css"; +import _implicitScopedStylesheets from "./synthetic-shadow.scoped.css?scoped=true"; +import { freezeTemplate, parseFragment, registerTemplate } from "lwc"; +const $fragment1 = parseFragment`Click me:`; +const $fragment2 = parseFragment``; +const $fragment3 = parseFragment`Click to scroll`; +const $fragment4 = parseFragment`Scroll to me`; +const $fragment5 = parseFragment`Click me:`; +const $fragment6 = parseFragment``; +const $fragment7 = parseFragment`Click to scroll`; +const $fragment8 = parseFragment`Scroll to me`; +function tmpl($api, $cmp, $slotset, $ctx) { + const { + gid: api_scoped_id, + sp: api_static_part, + st: api_static_fragment, + fid: api_scoped_frag_id, + } = $api; + return [ + api_static_fragment($fragment1, 1, [ + api_static_part( + 0, + { + attrs: { + for: api_scoped_id("foo"), + }, + }, + null + ), + ]), + api_static_fragment($fragment2, 3, [ + api_static_part( + 0, + { + attrs: { + id: api_scoped_id("foo"), + }, + }, + null + ), + ]), + api_static_fragment($fragment3, 5, [ + api_static_part( + 0, + { + attrs: { + href: api_scoped_frag_id("#bar"), + }, + }, + null + ), + ]), + api_static_fragment($fragment4, 7, [ + api_static_part( + 0, + { + attrs: { + id: api_scoped_id("bar"), + }, + }, + null + ), + ]), + api_static_fragment($fragment5, 9, [ + api_static_part( + 0, + { + attrs: { + for: api_scoped_id($cmp.foo), + }, + }, + null + ), + ]), + api_static_fragment($fragment6, 11, [ + api_static_part( + 0, + { + attrs: { + id: api_scoped_id($cmp.foo), + }, + }, + null + ), + ]), + api_static_fragment($fragment7, 13, [ + api_static_part( + 0, + { + attrs: { + href: api_scoped_frag_id($cmp.bar), + }, + }, + null + ), + ]), + api_static_fragment($fragment8, 15, [ + api_static_part( + 0, + { + attrs: { + id: api_scoped_id($cmp.bar), + }, + }, + null + ), + ]), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-520i124ag3i"; +tmpl.legacyStylesheetToken = "x-synthetic-shadow_synthetic-shadow"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-optimized/synthetic-shadow/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/actual.html new file mode 100644 index 0000000000..d4b7a2482e --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/ast.json new file mode 100644 index 0000000000..370b6b1c14 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/ast.json @@ -0,0 +1,641 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 423, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 35, + "start": 0, + "end": 34 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 412, + "end": 423 + } + }, + "directives": [ + { + "type": "Directive", + "name": "RenderMode", + "value": { + "type": "Literal", + "value": "light" + }, + "location": { + "startLine": 1, + "startColumn": 11, + "endLine": 1, + "endColumn": 34, + "start": 10, + "end": 33 + } + } + ], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 39, + "end": 61 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 66, + "end": 100, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 66, + "end": 83 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 92, + "end": 100 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 73, + "end": 82 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 83, + "end": 92 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 105, + "end": 137, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 105, + "end": 137 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 112, + "end": 127 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 128, + "end": 136 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 143, + "end": 177, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 143, + "end": 158 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 173, + "end": 177 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 146, + "end": 157 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 158, + "end": 173 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 182, + "end": 222, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 182, + "end": 200 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 212, + "end": 222 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 191, + "end": 199 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 200, + "end": 212 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 228, + "end": 251 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 256, + "end": 290, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 256, + "end": 273 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 282, + "end": 290 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 263, + "end": 272 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 263, + "end": 272 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 273, + "end": 282 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 295, + "end": 327, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 295, + "end": 327 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 302, + "end": 317 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 318, + "end": 326 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 318, + "end": 326 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 333, + "end": 366, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 333, + "end": 347 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 362, + "end": 366 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 336, + "end": 346 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 336, + "end": 346 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 347, + "end": 362 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 371, + "end": 411, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 371, + "end": 389 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 401, + "end": 411 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 380, + "end": 388 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 380, + "end": 388 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 389, + "end": 401 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/config.json new file mode 100644 index 0000000000..b5d7f0cbd0 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/config.json @@ -0,0 +1,3 @@ +{ + "enableStaticContentOptimization": false +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/expected.js new file mode 100644 index 0000000000..d1d3378867 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/expected.js @@ -0,0 +1,87 @@ +import _implicitStylesheets from "./light.css"; +import _implicitScopedStylesheets from "./light.scoped.css?scoped=true"; +import { freezeTemplate, registerTemplate } from "lwc"; +const stc0 = { + attrs: { + for: "foo", + }, + key: 0, +}; +const stc1 = { + attrs: { + type: "checkbox", + id: "foo", + }, + key: 1, +}; +const stc2 = { + attrs: { + href: "#bar", + }, + key: 2, +}; +const stc3 = { + attrs: { + id: "bar", + }, + key: 3, +}; +function tmpl($api, $cmp, $slotset, $ctx) { + const { t: api_text, h: api_element } = $api; + return [ + api_element("label", stc0, [api_text("Click me:")]), + api_element("input", stc1), + api_element("a", stc2, [api_text("Click to scroll")]), + api_element("section", stc3, [api_text("Scroll to me")]), + api_element( + "label", + { + attrs: { + for: $cmp.foo, + }, + key: 4, + }, + [api_text("Click me:")] + ), + api_element("input", { + attrs: { + type: "checkbox", + id: $cmp.foo, + }, + key: 5, + }), + api_element( + "a", + { + attrs: { + href: $cmp.bar, + }, + key: 6, + }, + [api_text("Click to scroll")] + ), + api_element( + "section", + { + attrs: { + id: $cmp.bar, + }, + key: 7, + }, + [api_text("Scroll to me")] + ), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.renderMode = "light"; +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-1kadf5igpar"; +tmpl.legacyStylesheetToken = "x-light_light"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/light/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/actual.html new file mode 100644 index 0000000000..33f76b4da8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/ast.json new file mode 100644 index 0000000000..81163d65b8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/ast.json @@ -0,0 +1,624 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 399, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 11, + "start": 0, + "end": 10 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 388, + "end": 399 + } + }, + "directives": [], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 15, + "end": 37 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 42, + "end": 76, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 42, + "end": 59 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 68, + "end": 76 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 49, + "end": 58 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 59, + "end": 68 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 88, + "end": 103 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 104, + "end": 112 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 119, + "end": 153, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 119, + "end": 134 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 149, + "end": 153 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 122, + "end": 133 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 134, + "end": 149 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 158, + "end": 198, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 158, + "end": 176 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 188, + "end": 198 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 167, + "end": 175 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 176, + "end": 188 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 204, + "end": 227 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 232, + "end": 266, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 232, + "end": 249 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 258, + "end": 266 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 249, + "end": 258 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 278, + "end": 293 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 309, + "end": 342, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 309, + "end": 323 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 338, + "end": 342 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 323, + "end": 338 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 347, + "end": 387, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 347, + "end": 365 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 377, + "end": 387 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 365, + "end": 377 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/config.json new file mode 100644 index 0000000000..22ac84ffda --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/config.json @@ -0,0 +1,4 @@ +{ + "enableStaticContentOptimization": false, + "disableSyntheticShadowSupport": true +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/expected.js new file mode 100644 index 0000000000..967c2619f9 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/expected.js @@ -0,0 +1,86 @@ +import _implicitStylesheets from "./native-shadow.css"; +import _implicitScopedStylesheets from "./native-shadow.scoped.css?scoped=true"; +import { freezeTemplate, registerTemplate } from "lwc"; +const stc0 = { + attrs: { + for: "foo", + }, + key: 0, +}; +const stc1 = { + attrs: { + type: "checkbox", + id: "foo", + }, + key: 1, +}; +const stc2 = { + attrs: { + href: "#bar", + }, + key: 2, +}; +const stc3 = { + attrs: { + id: "bar", + }, + key: 3, +}; +function tmpl($api, $cmp, $slotset, $ctx) { + const { t: api_text, h: api_element } = $api; + return [ + api_element("label", stc0, [api_text("Click me:")]), + api_element("input", stc1), + api_element("a", stc2, [api_text("Click to scroll")]), + api_element("section", stc3, [api_text("Scroll to me")]), + api_element( + "label", + { + attrs: { + for: $cmp.foo, + }, + key: 4, + }, + [api_text("Click me:")] + ), + api_element("input", { + attrs: { + type: "checkbox", + id: $cmp.foo, + }, + key: 5, + }), + api_element( + "a", + { + attrs: { + href: $cmp.bar, + }, + key: 6, + }, + [api_text("Click to scroll")] + ), + api_element( + "section", + { + attrs: { + id: $cmp.bar, + }, + key: 7, + }, + [api_text("Scroll to me")] + ), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-54b380gv09b"; +tmpl.legacyStylesheetToken = "x-native-shadow_native-shadow"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/native-shadow/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/actual.html new file mode 100644 index 0000000000..33f76b4da8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/actual.html @@ -0,0 +1,15 @@ + diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/ast.json new file mode 100644 index 0000000000..81163d65b8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/ast.json @@ -0,0 +1,624 @@ +{ + "root": { + "type": "Root", + "location": { + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 0, + "end": 399, + "startTag": { + "startLine": 1, + "startColumn": 1, + "endLine": 1, + "endColumn": 11, + "start": 0, + "end": 10 + }, + "endTag": { + "startLine": 15, + "startColumn": 1, + "endLine": 15, + "endColumn": 12, + "start": 388, + "end": 399 + } + }, + "directives": [], + "children": [ + { + "type": "Comment", + "raw": " static values ", + "value": " static values ", + "location": { + "startLine": 2, + "startColumn": 5, + "endLine": 2, + "endColumn": 27, + "start": 15, + "end": 37 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 39, + "start": 42, + "end": 76, + "startTag": { + "startLine": 3, + "startColumn": 5, + "endLine": 3, + "endColumn": 22, + "start": 42, + "end": 59 + }, + "endTag": { + "startLine": 3, + "startColumn": 31, + "endLine": 3, + "endColumn": 39, + "start": 68, + "end": 76 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 3, + "startColumn": 12, + "endLine": 3, + "endColumn": 21, + "start": 49, + "end": 58 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 3, + "startColumn": 22, + "endLine": 3, + "endColumn": 31, + "start": 59, + "end": 68 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113, + "startTag": { + "startLine": 4, + "startColumn": 5, + "endLine": 4, + "endColumn": 37, + "start": 81, + "end": 113 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 4, + "startColumn": 12, + "endLine": 4, + "endColumn": 27, + "start": 88, + "end": 103 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "foo" + }, + "location": { + "startLine": 4, + "startColumn": 28, + "endLine": 4, + "endColumn": 36, + "start": 104, + "end": 112 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 39, + "start": 119, + "end": 153, + "startTag": { + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 20, + "start": 119, + "end": 134 + }, + "endTag": { + "startLine": 6, + "startColumn": 35, + "endLine": 6, + "endColumn": 39, + "start": 149, + "end": 153 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Literal", + "value": "#bar" + }, + "location": { + "startLine": 6, + "startColumn": 8, + "endLine": 6, + "endColumn": 19, + "start": 122, + "end": 133 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 6, + "startColumn": 20, + "endLine": 6, + "endColumn": 35, + "start": 134, + "end": 149 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 45, + "start": 158, + "end": 198, + "startTag": { + "startLine": 7, + "startColumn": 5, + "endLine": 7, + "endColumn": 23, + "start": 158, + "end": 176 + }, + "endTag": { + "startLine": 7, + "startColumn": 35, + "endLine": 7, + "endColumn": 45, + "start": 188, + "end": 198 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Literal", + "value": "bar" + }, + "location": { + "startLine": 7, + "startColumn": 14, + "endLine": 7, + "endColumn": 22, + "start": 167, + "end": 175 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 7, + "startColumn": 23, + "endLine": 7, + "endColumn": 35, + "start": 176, + "end": 188 + } + } + ] + }, + { + "type": "Comment", + "raw": " dynamic values ", + "value": " dynamic values ", + "location": { + "startLine": 9, + "startColumn": 5, + "endLine": 9, + "endColumn": 28, + "start": 204, + "end": 227 + } + }, + { + "type": "Element", + "name": "label", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 39, + "start": 232, + "end": 266, + "startTag": { + "startLine": 10, + "startColumn": 5, + "endLine": 10, + "endColumn": 22, + "start": 232, + "end": 249 + }, + "endTag": { + "startLine": 10, + "startColumn": 31, + "endLine": 10, + "endColumn": 39, + "start": 258, + "end": 266 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "for", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + }, + "location": { + "startLine": 10, + "startColumn": 12, + "endLine": 10, + "endColumn": 21, + "start": 239, + "end": 248 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click me:", + "value": { + "type": "Literal", + "value": "Click me:" + }, + "location": { + "startLine": 10, + "startColumn": 22, + "endLine": 10, + "endColumn": 31, + "start": 249, + "end": 258 + } + } + ] + }, + { + "type": "Element", + "name": "input", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303, + "startTag": { + "startLine": 11, + "startColumn": 5, + "endLine": 11, + "endColumn": 37, + "start": 271, + "end": 303 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "type", + "value": { + "type": "Literal", + "value": "checkbox" + }, + "location": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 27, + "start": 278, + "end": 293 + } + }, + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "foo", + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + }, + "location": { + "startLine": 11, + "startColumn": 28, + "endLine": 11, + "endColumn": 36, + "start": 294, + "end": 302 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [] + }, + { + "type": "Element", + "name": "a", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 38, + "start": 309, + "end": 342, + "startTag": { + "startLine": 13, + "startColumn": 5, + "endLine": 13, + "endColumn": 19, + "start": 309, + "end": 323 + }, + "endTag": { + "startLine": 13, + "startColumn": 34, + "endLine": 13, + "endColumn": 38, + "start": 338, + "end": 342 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "href", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + }, + "location": { + "startLine": 13, + "startColumn": 8, + "endLine": 13, + "endColumn": 18, + "start": 312, + "end": 322 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Click to scroll", + "value": { + "type": "Literal", + "value": "Click to scroll" + }, + "location": { + "startLine": 13, + "startColumn": 19, + "endLine": 13, + "endColumn": 34, + "start": 323, + "end": 338 + } + } + ] + }, + { + "type": "Element", + "name": "section", + "namespace": "http://www.w3.org/1999/xhtml", + "location": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 45, + "start": 347, + "end": 387, + "startTag": { + "startLine": 14, + "startColumn": 5, + "endLine": 14, + "endColumn": 23, + "start": 347, + "end": 365 + }, + "endTag": { + "startLine": 14, + "startColumn": 35, + "endLine": 14, + "endColumn": 45, + "start": 377, + "end": 387 + } + }, + "attributes": [ + { + "type": "Attribute", + "name": "id", + "value": { + "type": "Identifier", + "start": 1, + "end": 4, + "name": "bar", + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + }, + "location": { + "startLine": 14, + "startColumn": 14, + "endLine": 14, + "endColumn": 22, + "start": 356, + "end": 364 + } + } + ], + "properties": [], + "directives": [], + "listeners": [], + "children": [ + { + "type": "Text", + "raw": "Scroll to me", + "value": { + "type": "Literal", + "value": "Scroll to me" + }, + "location": { + "startLine": 14, + "startColumn": 23, + "endLine": 14, + "endColumn": 35, + "start": 365, + "end": 377 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/config.json new file mode 100644 index 0000000000..3934e666c8 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/config.json @@ -0,0 +1,4 @@ +{ + "enableStaticContentOptimization": false, + "disableSyntheticShadowSupport": false +} diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/expected.js new file mode 100644 index 0000000000..7f4dddf3d0 --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/expected.js @@ -0,0 +1,99 @@ +import _implicitStylesheets from "./synthetic-shadow.css"; +import _implicitScopedStylesheets from "./synthetic-shadow.scoped.css?scoped=true"; +import { freezeTemplate, registerTemplate } from "lwc"; +function tmpl($api, $cmp, $slotset, $ctx) { + const { + gid: api_scoped_id, + t: api_text, + h: api_element, + fid: api_scoped_frag_id, + } = $api; + return [ + api_element( + "label", + { + attrs: { + for: api_scoped_id("foo"), + }, + key: 0, + }, + [api_text("Click me:")] + ), + api_element("input", { + attrs: { + type: "checkbox", + id: api_scoped_id("foo"), + }, + key: 1, + }), + api_element( + "a", + { + attrs: { + href: api_scoped_frag_id("#bar"), + }, + key: 2, + }, + [api_text("Click to scroll")] + ), + api_element( + "section", + { + attrs: { + id: api_scoped_id("bar"), + }, + key: 3, + }, + [api_text("Scroll to me")] + ), + api_element( + "label", + { + attrs: { + for: api_scoped_id($cmp.foo), + }, + key: 4, + }, + [api_text("Click me:")] + ), + api_element("input", { + attrs: { + type: "checkbox", + id: api_scoped_id($cmp.foo), + }, + key: 5, + }), + api_element( + "a", + { + attrs: { + href: api_scoped_frag_id($cmp.bar), + }, + key: 6, + }, + [api_text("Click to scroll")] + ), + api_element( + "section", + { + attrs: { + id: api_scoped_id($cmp.bar), + }, + key: 7, + }, + [api_text("Scroll to me")] + ), + ]; + /*LWC compiler vX.X.X*/ +} +export default registerTemplate(tmpl); +tmpl.stylesheets = []; +tmpl.stylesheetToken = "lwc-520i124ag3i"; +tmpl.legacyStylesheetToken = "x-synthetic-shadow_synthetic-shadow"; +if (_implicitStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets); +} +if (_implicitScopedStylesheets) { + tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets); +} +freezeTemplate(tmpl); diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/metadata.json new file mode 100644 index 0000000000..51ec5f799c --- /dev/null +++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/scoped-id-optimization/static-unoptimized/synthetic-shadow/metadata.json @@ -0,0 +1,3 @@ +{ + "warnings": [] +} \ No newline at end of file diff --git a/packages/@lwc/template-compiler/src/codegen/codegen.ts b/packages/@lwc/template-compiler/src/codegen/codegen.ts index 6807f9f10e..4288789eb0 100644 --- a/packages/@lwc/template-compiler/src/codegen/codegen.ts +++ b/packages/@lwc/template-compiler/src/codegen/codegen.ts @@ -170,6 +170,12 @@ export default class CodeGen { */ readonly state: State; + /** + * True if this is a synthetic shadow template - otherwise, we may apply certain optimizations + * that only exist for native shadow and light DOM. + */ + readonly isSyntheticShadow: boolean; + currentId = 0; currentKey = 0; innerHtmlInstances = 0; @@ -209,6 +215,10 @@ export default class CodeGen { this.scope = this.createScope(); this.state = state; this.apiVersion = getAPIVersionFromNumber(state.config.apiVersion); + + this.isSyntheticShadow = + this.renderMode !== LWCDirectiveRenderMode.light && + !this.state.config.disableSyntheticShadowSupport; } generateKey() { @@ -310,18 +320,16 @@ export default class CodeGen { return this._renderApiCall(RENDER_APIS.flatten, children); } - genScopedId(id: string | t.Expression): t.CallExpression { - if (typeof id === 'string') { - return this._renderApiCall(RENDER_APIS.scopedId, [t.literal(id)]); - } - return this._renderApiCall(RENDER_APIS.scopedId, [id]); + genScopedId(id: string | t.Expression): t.Expression | t.Literal { + const value = typeof id === 'string' ? t.literal(id) : id; + return this.isSyntheticShadow ? this._renderApiCall(RENDER_APIS.scopedId, [value]) : value; } - genScopedFragId(id: string | t.Expression): t.CallExpression { - if (typeof id === 'string') { - return this._renderApiCall(RENDER_APIS.scopedFragId, [t.literal(id)]); - } - return this._renderApiCall(RENDER_APIS.scopedFragId, [id]); + genScopedFragId(id: string | t.Expression): t.Expression | t.Literal { + const value = typeof id === 'string' ? t.literal(id) : id; + return this.isSyntheticShadow + ? this._renderApiCall(RENDER_APIS.scopedFragId, [value]) + : value; } genClassExpression(value: Expression) { @@ -725,7 +733,6 @@ export default class CodeGen { // IDs/IDRefs must be handled dynamically at runtime due to synthetic shadow scoping. // Note that for backwards compat we only consider non-booleans to be dynamic IDs/IDRefs - // TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior const isIdOrIdRef = (name === 'id' || isIdReferencingAttribute(name)) && !isBooleanLiteral(value); @@ -743,7 +750,12 @@ export default class CodeGen { isAllowedFragOnlyUrlsXHTML(currentNode.name, name, currentNode.namespace) && isFragmentOnlyUrl(value.value); - if (isExpression(value) || isIdOrIdRef || isSvgHref || isScopedFragmentRef) { + // If we're not running in synthetic shadow mode (light or shadow+disableSyntheticShadowSupport), + // then static IDs/IDrefs/fragment refs will be rendered directly into HTML strings. + const needsScoping = + this.isSyntheticShadow && (isIdOrIdRef || isScopedFragmentRef); + + if (isExpression(value) || isSvgHref || needsScoping) { let partToken = ''; if (name === 'style') { partToken = `${STATIC_PART_TOKEN_ID.STYLE}${partId}`; diff --git a/packages/@lwc/template-compiler/src/codegen/static-element-serializer.ts b/packages/@lwc/template-compiler/src/codegen/static-element-serializer.ts index 626eed9845..ef8350a69b 100644 --- a/packages/@lwc/template-compiler/src/codegen/static-element-serializer.ts +++ b/packages/@lwc/template-compiler/src/codegen/static-element-serializer.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: MIT * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ -import { htmlEscape, HTML_NAMESPACE, isVoidElement } from '@lwc/shared'; +import { HTML_NAMESPACE, htmlEscape, isVoidElement } from '@lwc/shared'; import { isAllowedFragOnlyUrlsXHTML, isFragmentOnlyUrl, @@ -13,14 +13,14 @@ import { } from '../parser/attribute'; import { Comment, Element, Literal, StaticChildNode, StaticElement, Text } from '../shared/types'; import { - isElement, + isBooleanLiteral, isComment, + isElement, isExpression, - isText, - isBooleanLiteral, isStringLiteral, + isText, } from '../shared/ast'; -import { transformStaticChildren, isContiguousText, hasDynamicText } from './static-element'; +import { hasDynamicText, isContiguousText, transformStaticChildren } from './static-element'; import type CodeGen from './codegen'; // Implementation based on the parse5 serializer: https://github.com/inikulin/parse5/blob/master/packages/parse5/lib/serializer/index.ts @@ -58,16 +58,14 @@ function serializeAttrs(element: Element, codeGen: CodeGen): string { name, value, hasExpression, - hasIdOrIdRef, hasSvgUseHref, - hasScopedFragmentRef, + needsScoping, }: { name: string; value: string | boolean; hasExpression?: boolean; - hasIdOrIdRef?: boolean; hasSvgUseHref?: boolean; - hasScopedFragmentRef?: boolean; + needsScoping?: boolean; }) => { let v = typeof value === 'string' ? templateStringEscape(value) : value; @@ -96,9 +94,7 @@ function serializeAttrs(element: Element, codeGen: CodeGen): string { // Skip serializing here and handle it as if it were a dynamic attribute instead. // Note that, to maintain backwards compatibility with the non-static output, we treat the valueless // "boolean" format (e.g. `
`) as the empty string, which is semantically equivalent. - // TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior - const needsPlaceholder = - hasExpression || hasIdOrIdRef || hasSvgUseHref || hasScopedFragmentRef; + const needsPlaceholder = hasExpression || hasSvgUseHref || needsScoping; // Inject a placeholder where the staticPartId will go when an expression occurs. // This is only needed for SSR to inject the expression value during serialization. @@ -114,16 +110,15 @@ function serializeAttrs(element: Element, codeGen: CodeGen): string { const hasExpression = isExpression(value); + // For boolean literals (e.g. ``), there is no reason to sanitize since it's empty + const hasSvgUseHref = + isSvgUseHref(element.name, name, element.namespace) && !isBooleanLiteral(value); + // IDs/IDRefs must be handled dynamically at runtime due to synthetic shadow scoping. // Note that for backwards compat we only consider non-booleans to be dynamic IDs/IDRefs - // TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior const hasIdOrIdRef = (name === 'id' || isIdReferencingAttribute(name)) && !isBooleanLiteral(value); - // For boolean literals (e.g. ``), there is no reason to sanitize since it's empty - const hasSvgUseHref = - isSvgUseHref(element.name, name, element.namespace) && !isBooleanLiteral(value); - // `` and `` must be dynamic due to synthetic shadow scoping // Note this only applies if there is an `id` attribute somewhere in the template const hasScopedFragmentRef = @@ -132,14 +127,18 @@ function serializeAttrs(element: Element, codeGen: CodeGen): string { isAllowedFragOnlyUrlsXHTML(element.name, name, element.namespace) && isFragmentOnlyUrl(value.value); + // If we're not running in synthetic shadow mode (light or shadow+disableSyntheticShadowSupport), + // then static IDs/IDrefs/fragment refs will be rendered directly into HTML strings. + const needsScoping = + codeGen.isSyntheticShadow && (hasIdOrIdRef || hasScopedFragmentRef); + return { hasExpression, - hasIdOrIdRef, hasSvgUseHref, - hasScopedFragmentRef, + needsScoping, name, value: - hasExpression || hasIdOrIdRef || hasSvgUseHref || hasScopedFragmentRef + hasExpression || hasSvgUseHref || needsScoping ? codeGen.getStaticExpressionToken(attr) : (value as Literal).value, }; diff --git a/packages/@lwc/template-compiler/src/config.ts b/packages/@lwc/template-compiler/src/config.ts index 422952331d..18aeed9920 100644 --- a/packages/@lwc/template-compiler/src/config.ts +++ b/packages/@lwc/template-compiler/src/config.ts @@ -90,6 +90,9 @@ export interface Config { * The API version to associate with the compiled template */ apiVersion?: number; + + /** Set to true if synthetic shadow DOM support is not needed, which can result in smaller/faster output. */ + disableSyntheticShadowSupport?: boolean; } type OptionalConfigNames = 'customRendererConfig' | 'instrumentation' | 'namespace' | 'name'; type RequiredConfigOptions = Required>; @@ -110,6 +113,7 @@ const AVAILABLE_OPTION_NAMES = new Set([ 'instrumentation', 'namespace', 'name', + 'disableSyntheticShadowSupport', ]); function normalizeCustomRendererConfig(config: CustomRendererConfig): CustomRendererConfig { @@ -176,6 +180,7 @@ export function normalizeConfig(config: Config): NormalizedConfig { enableDynamicComponents: false, enableStaticContentOptimization: true, enableLwcSpread: true, + disableSyntheticShadowSupport: false, ...config, apiVersion, // overrides the config apiVersion ...{ customRendererConfig },