diff --git a/packages/@lwc/ssr-compiler/src/__tests__/compilation.spec.ts b/packages/@lwc/ssr-compiler/src/__tests__/compilation.spec.ts index c6832a1e4e..14e7715b63 100644 --- a/packages/@lwc/ssr-compiler/src/__tests__/compilation.spec.ts +++ b/packages/@lwc/ssr-compiler/src/__tests__/compilation.spec.ts @@ -31,7 +31,7 @@ describe('component compilation', () => { `; const filename = path.resolve('component.js'); const { code } = compileComponentForSSR(src, filename, {}); - expect(code).toContain('import tmpl from "./component.html"'); + expect(code).toContain('import __lwcTmpl from "./component.html"'); }); test('explicit templates imports do not use full file paths', () => { const src = ` @@ -59,7 +59,7 @@ describe('component compilation', () => { `; const filename = path.resolve('component.ts'); const { code } = compileComponentForSSR(src, filename, {}); - expect(code).toContain('import tmpl from "./component.html"'); + expect(code).toContain('import __lwcTmpl from "./component.html"'); }); describe('wire decorator', () => { diff --git a/packages/@lwc/ssr-compiler/src/__tests__/transmogrify.spec.ts b/packages/@lwc/ssr-compiler/src/__tests__/transmogrify.spec.ts index 3018ec9cd0..c055ef54ce 100644 --- a/packages/@lwc/ssr-compiler/src/__tests__/transmogrify.spec.ts +++ b/packages/@lwc/ssr-compiler/src/__tests__/transmogrify.spec.ts @@ -5,7 +5,7 @@ import { transmogrify } from '../transmogrify'; import type { Program as EsProgram } from 'estree'; const COMPILED_CMP = ` - async function* tmpl(props, attrs, slottedContent, Cmp, instance) { + async function* __lwcTmpl(props, attrs, slottedContent, Cmp, instance) { yield "Hello

"; @@ -27,7 +27,7 @@ const COMPILED_CMP = ` } } const __REFLECTED_PROPS__ = []; - async function* generateMarkup(tagName, props, attrs, slotted) { + async function* __lwcGenerateMarkup(tagName, props, attrs, slotted) { attrs = attrs ?? ({}); const instance = new Basic({ tagName: tagName.toUpperCase() @@ -65,10 +65,10 @@ describe('transmogrify', () => { }); describe('in sync mode', () => { - test('generateMarkup is transformed into sync mode', () => { - expect(COMPILED_CMP_SYNC).not.toContain('async function* generateMarkup'); - expect(COMPILED_CMP_SYNC).not.toContain('async function generateMarkup'); - expect(COMPILED_CMP_SYNC).toContain('function generateMarkup($$emit'); + test('__lwcGenerateMarkup is transformed into sync mode', () => { + expect(COMPILED_CMP_SYNC).not.toContain('async function* __lwcGenerateMarkup'); + expect(COMPILED_CMP_SYNC).not.toContain('async function __lwcGenerateMarkup'); + expect(COMPILED_CMP_SYNC).toContain('function __lwcGenerateMarkup($$emit'); expect(COMPILED_CMP_SYNC).not.toContain('yield* renderAttrs'); expect(COMPILED_CMP_SYNC).toContain('renderAttrs($$emit'); @@ -78,10 +78,10 @@ describe('transmogrify', () => { expect(COMPILED_CMP_SYNC).toContain('$$emit(">")'); }); - test('tmpl is transformed into sync mode', () => { - expect(COMPILED_CMP_SYNC).not.toContain('async function* tmpl'); - expect(COMPILED_CMP_SYNC).not.toContain('async function tmpl'); - expect(COMPILED_CMP_SYNC).toContain('function tmpl($$emit'); + test('__lwcTmpl is transformed into sync mode', () => { + expect(COMPILED_CMP_SYNC).not.toContain('async function* __lwcTmpl'); + expect(COMPILED_CMP_SYNC).not.toContain('async function __lwcTmpl'); + expect(COMPILED_CMP_SYNC).toContain('function __lwcTmpl($$emit'); expect(COMPILED_CMP_SYNC).not.toContain('yield " { }); describe('in async mode', () => { - test('generateMarkup is transformed into async mode', () => { - expect(COMPILED_CMP_ASYNC).not.toContain('async function* generateMarkup'); - expect(COMPILED_CMP_ASYNC).toContain('async function generateMarkup($$emit'); + test('__lwcGenerateMarkup is transformed into async mode', () => { + expect(COMPILED_CMP_ASYNC).not.toContain('async function* __lwcGenerateMarkup'); + expect(COMPILED_CMP_ASYNC).toContain('async function __lwcGenerateMarkup($$emit'); expect(COMPILED_CMP_ASYNC).not.toContain('yield* renderAttrs'); expect(COMPILED_CMP_ASYNC).toContain('renderAttrs($$emit'); @@ -114,9 +114,9 @@ describe('transmogrify', () => { expect(COMPILED_CMP_ASYNC).toContain('$$emit(">")'); }); - test('tmpl is transformed into async mode', () => { - expect(COMPILED_CMP_ASYNC).not.toContain('async function* tmpl'); - expect(COMPILED_CMP_ASYNC).toContain('async function tmpl($$emit'); + test('__lwcTmpl is transformed into async mode', () => { + expect(COMPILED_CMP_ASYNC).not.toContain('async function* __lwcTmpl'); + expect(COMPILED_CMP_ASYNC).toContain('async function __lwcTmpl($$emit'); expect(COMPILED_CMP_ASYNC).not.toContain('yield ". @@ -72,11 +72,11 @@ const bGenerateSlottedContent = esTemplateWithYield` ${/* scoped slot addLightContent statements */ is.expressionStatement} `; -// Note that this function name (`generateSlottedContent`) does not need to be scoped even though +// Note that this function name (`__lwcGenerateSlottedContent`) does not need to be scoped even though // it may be repeated multiple times in the same scope, because it's a function _expression_ rather // than a function _declaration_, so it isn't available to be referenced anywhere. const bAddSlottedContent = esTemplate` - addSlottedContent(${/* slot name */ is.expression} ?? "", async function* generateSlottedContent(contextfulParent, ${ + addSlottedContent(${/* slot name */ is.expression} ?? "", async function* __lwcGenerateSlottedContent(contextfulParent, ${ /* scoped slot data variable */ isNullableOf(is.identifier) }, slotAttributeValue) { // FIXME: make validation work again diff --git a/packages/@lwc/ssr-compiler/src/transmogrify.ts b/packages/@lwc/ssr-compiler/src/transmogrify.ts index 6a3a89a579..832212e1f7 100644 --- a/packages/@lwc/ssr-compiler/src/transmogrify.ts +++ b/packages/@lwc/ssr-compiler/src/transmogrify.ts @@ -19,12 +19,11 @@ interface TransmogrificationState { export type Visitors = Parameters>[1]; const EMIT_IDENT = b.identifier('$$emit'); +/** Function names that may be transmogrified. All should start with `__lwc`. */ // Rollup may rename variables to prevent shadowing. When it does, it uses the format `foo$0`, `foo$1`, etc. -const TMPL_FN_PATTERN = /tmpl($\d+)?/; -const GEN_MARKUP_OR_GEN_SLOTTED_CONTENT_PATTERN = - /(?:generateMarkup|generateSlottedContent)($\d+)?/; +const TRANSMOGRIFY_TARGET = /^__lwc(GenerateMarkup|GenerateSlottedContent|Tmpl)(?:\$\d+)?$/; -const isWithinFn = (pattern: RegExp, nodePath: NodePath): boolean => { +const isWithinFn = (nodePath: NodePath): boolean => { const { node } = nodePath; if (!node) { return false; @@ -32,12 +31,12 @@ const isWithinFn = (pattern: RegExp, nodePath: NodePath): boolean => { if ( (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') && node.id && - pattern.test(node.id.name) + TRANSMOGRIFY_TARGET.test(node.id.name) ) { return true; } if (nodePath.parentPath) { - return isWithinFn(pattern, nodePath.parentPath); + return isWithinFn(nodePath.parentPath); } return false; }; @@ -57,10 +56,7 @@ const visitors: Visitors = { // Component authors might conceivably use async generator functions in their own code. Therefore, // when traversing & transforming written+generated code, we need to disambiguate generated async // generator functions from those that were written by the component author. - if ( - !isWithinFn(GEN_MARKUP_OR_GEN_SLOTTED_CONTENT_PATTERN, path) && - !isWithinFn(TMPL_FN_PATTERN, path) - ) { + if (!isWithinFn(path)) { return; } node.generator = false; @@ -76,10 +72,7 @@ const visitors: Visitors = { // Component authors might conceivably use generator functions within their own code. Therefore, // when traversing & transforming written+generated code, we need to disambiguate generated yield // expressions from those that were written by the component author. - if ( - !isWithinFn(TMPL_FN_PATTERN, path) && - !isWithinFn(GEN_MARKUP_OR_GEN_SLOTTED_CONTENT_PATTERN, path) - ) { + if (!isWithinFn(path)) { return; } @@ -152,7 +145,7 @@ const visitors: Visitors = { * Is compiled into the following JavaScript, intended for execution during SSR & stripped down * for the purposes of this example: * - * async function* tmpl(props, attrs, slottedContent, Cmp, instance) { + * async function* __lwcTmpl(props, attrs, slottedContent, Cmp, instance) { * yield '
foobar
'; * const childProps = {}; * const childAttrs = {}; @@ -161,7 +154,7 @@ const visitors: Visitors = { * * When transmogrified in async-mode, the above generated template function becomes the following: * - * async function tmpl($$emit, props, attrs, slottedContent, Cmp, instance) { + * async function __lwcTmpl($$emit, props, attrs, slottedContent, Cmp, instance) { * $$emit('
foobar
'); * const childProps = {}; * const childAttrs = {}; @@ -170,7 +163,7 @@ const visitors: Visitors = { * * When transmogrified in sync-mode, the template function becomes the following: * - * function tmpl($$emit, props, attrs, slottedContent, Cmp, instance) { + * function __lwcTmpl($$emit, props, attrs, slottedContent, Cmp, instance) { * $$emit('
foobar
'); * const childProps = {}; * const childAttrs = {};