From: 三咲智子 Kevin Deng Date: Wed, 13 Nov 2024 02:12:12 +0000 (+0800) Subject: feat(compiler-vapor): support implicit prop in template X-Git-Tag: v3.6.0-alpha.1~16^2~291 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=114d5015248f3bfcca9840408b248d33398cb4a5;p=thirdparty%2Fvuejs%2Fcore.git feat(compiler-vapor): support implicit prop in template --- diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index 95bd002d25..7d0eca13fa 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -4,7 +4,7 @@ exports[`compile > bindings 1`] = ` "import { renderEffect as _renderEffect, setText as _setText, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _renderEffect(() => _setText(n0, "count is ", _ctx.count, ".")) return n0 @@ -56,7 +56,7 @@ exports[`compile > directives > custom directive > basic 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample]]) return n0 @@ -67,7 +67,7 @@ exports[`compile > directives > custom directive > binding value 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg]]) return n0 @@ -78,7 +78,7 @@ exports[`compile > directives > custom directive > dynamic parameters 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, _ctx.foo]]) return n0 @@ -89,7 +89,7 @@ exports[`compile > directives > custom directive > modifiers 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, void 0, { bar: true }]]) return n0 @@ -100,7 +100,7 @@ exports[`compile > directives > custom directive > modifiers w/o binding 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, void 0, void 0, { "foo-bar": true }]]) return n0 @@ -111,7 +111,7 @@ exports[`compile > directives > custom directive > static parameters 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo"]]) return n0 @@ -122,7 +122,7 @@ exports[`compile > directives > custom directive > static parameters and modifie "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo", { bar: true }]]) return n0 @@ -143,7 +143,7 @@ exports[`compile > directives > v-pre > basic 1`] = ` "import { template as _template } from 'vue/vapor'; const t0 = _template("
{{ bar }}
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() return n0 }" @@ -154,7 +154,7 @@ exports[`compile > directives > v-pre > should not affect siblings after it 1`] const t0 = _template("
{{ bar }}
") const t1 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const _component_Comp = _resolveComponent("Comp") const n0 = t0() const n3 = t1() @@ -190,14 +190,14 @@ export function render(_ctx) { `; exports[`compile > expression parsing > interpolation 1`] = ` -"(() => { +"((_ctx) => { const n0 = _createTextNode(() => [a + b.value]) return n0 })()" `; exports[`compile > expression parsing > v-bind 1`] = ` -"(() => { +"((_ctx) => { const n0 = t0() _renderEffect(() => _setDynamicProps(n0, { [key.value+1]: _unref(foo)[key.value+1]() })) return n0 diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap new file mode 100644 index 0000000000..410acfd9bc --- /dev/null +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap @@ -0,0 +1,28 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`compiler: expression > basic 1`] = ` +"import { createTextNode as _createTextNode } from 'vue/vapor'; + +export function render(_ctx) { + const n0 = _createTextNode(() => [_ctx.a]) + return n0 +}" +`; + +exports[`compiler: expression > props 1`] = ` +"import { createTextNode as _createTextNode } from 'vue/vapor'; + +export function render(_ctx, $props) { + const n0 = _createTextNode(() => [$props.foo]) + return n0 +}" +`; + +exports[`compiler: expression > props aliased 1`] = ` +"import { createTextNode as _createTextNode } from 'vue/vapor'; + +export function render(_ctx, $props) { + const n0 = _createTextNode(() => [$props['bar']]) + return n0 +}" +`; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap index 2cbc5a1c9a..63c6e2d287 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap @@ -3,7 +3,7 @@ exports[`compiler: element transform > component > do not resolve component from non-script-setup bindings 1`] = ` "import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor'; -export function render(_ctx) { +export function render(_ctx, $props) { const _component_Example = _resolveComponent("Example") const n0 = _createComponent(_component_Example, null, null, true) return n0 @@ -14,7 +14,7 @@ exports[`compiler: element transform > component > generate multi root component "import { createComponent as _createComponent, template as _template } from 'vue/vapor'; const t0 = _template("123") -export function render(_ctx) { +export function render(_ctx, $props) { const n1 = t0() const n0 = _createComponent(_ctx.Comp) return [n0, n1] @@ -24,7 +24,7 @@ export function render(_ctx) { exports[`compiler: element transform > component > generate single root component 1`] = ` "import { createComponent as _createComponent } from 'vue/vapor'; -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = _createComponent(_ctx.Comp, null, null, true) return n0 }" @@ -41,14 +41,14 @@ export function render(_ctx) { `; exports[`compiler: element transform > component > resolve component from setup bindings (inline const) 1`] = ` -"(() => { +"((_ctx) => { const n0 = _createComponent(Example, null, null, true) return n0 })()" `; exports[`compiler: element transform > component > resolve component from setup bindings (inline) 1`] = ` -"(() => { +"((_ctx) => { const n0 = _createComponent(_unref(Example), null, null, true) return n0 })()" @@ -57,14 +57,14 @@ exports[`compiler: element transform > component > resolve component from setup exports[`compiler: element transform > component > resolve component from setup bindings 1`] = ` "import { createComponent as _createComponent } from 'vue/vapor'; -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = _createComponent(_ctx.Example, null, null, true) return n0 }" `; exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = ` -"(() => { +"((_ctx) => { const n0 = _createComponent(Foo.Example, null, null, true) return n0 })()" @@ -73,14 +73,14 @@ exports[`compiler: element transform > component > resolve namespaced component exports[`compiler: element transform > component > resolve namespaced component from props bindings (non-inline) 1`] = ` "import { createComponent as _createComponent } from 'vue/vapor'; -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = _createComponent(_ctx.Foo.Example, null, null, true) return n0 }" `; exports[`compiler: element transform > component > resolve namespaced component from setup bindings (inline const) 1`] = ` -"(() => { +"((_ctx) => { const n0 = _createComponent(Foo.Example, null, null, true) return n0 })()" @@ -89,7 +89,7 @@ exports[`compiler: element transform > component > resolve namespaced component exports[`compiler: element transform > component > resolve namespaced component from setup bindings 1`] = ` "import { createComponent as _createComponent } from 'vue/vapor'; -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = _createComponent(_ctx.Foo.Example, null, null, true) return n0 }" diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap index bb5fba17d7..c01b6431c9 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap @@ -4,7 +4,7 @@ exports[`v-html > should convert v-html to innerHTML 1`] = ` "import { renderEffect as _renderEffect, setHtml as _setHtml, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _renderEffect(() => _setHtml(n0, _ctx.code)) return n0 diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index ee8fcf62d8..5aec9a1649 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -177,7 +177,7 @@ exports[`compiler: vModel transform > should support member expression 1`] = ` "import { vModelText as _vModelText, withDirectives as _withDirectives, delegate as _delegate, template as _template } from 'vue/vapor'; const t0 = _template("") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _withDirectives(n0, [[_vModelText, () => _ctx.setupRef.child]]) const n1 = t0() @@ -192,7 +192,7 @@ export function render(_ctx) { `; exports[`compiler: vModel transform > should support member expression w/ inline 1`] = ` -"(() => { +"((_ctx) => { const n0 = t0() _withDirectives(n0, [[_vModelText, () => setupRef.value.child]]) const n1 = t0() diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap index 18612957b5..be0649ee1b 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap @@ -65,7 +65,7 @@ const t2 = _template("
") const t3 = _template("") _delegateEvents("click", "contextmenu", "mouseup", "keyup") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() const n1 = t1() const n2 = t0() @@ -448,7 +448,7 @@ export function render(_ctx) { `; exports[`v-on > should wrap in unref if identifier is setup-maybe-ref w/ inline: true 1`] = ` -"(() => { +"((_ctx) => { const n0 = t0() const n1 = t0() const n2 = t0() @@ -493,7 +493,7 @@ exports[`v-on > simple expression 1`] = ` const t0 = _template("
") _delegateEvents("click") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _delegate(n0, "click", () => _ctx.handleClick) return n0 diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index 2a2f169209..1c382d8be6 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -15,7 +15,7 @@ exports[`compiler: v-once > basic 1`] = ` "import { createTextNode as _createTextNode, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n2 = t0() const n1 = n2.firstChild const n0 = _createTextNode([_ctx.msg, " "]) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap index 7681968324..26a5d6bf52 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap @@ -4,7 +4,7 @@ exports[`v-text > should convert v-text to textContent 1`] = ` "import { renderEffect as _renderEffect, setText as _setText, template as _template } from 'vue/vapor'; const t0 = _template("
") -export function render(_ctx) { +export function render(_ctx, $props) { const n0 = t0() _renderEffect(() => _setText(n0, _ctx.str)) return n0 diff --git a/packages/compiler-vapor/__tests__/transforms/expression.spec.ts b/packages/compiler-vapor/__tests__/transforms/expression.spec.ts new file mode 100644 index 0000000000..c97decd9dd --- /dev/null +++ b/packages/compiler-vapor/__tests__/transforms/expression.spec.ts @@ -0,0 +1,34 @@ +import { BindingTypes } from '@vue/compiler-dom' +import { transformChildren, transformText } from '../../src' +import { makeCompile } from './_utils' + +const compileWithExpression = makeCompile({ + nodeTransforms: [transformChildren, transformText], +}) + +describe('compiler: expression', () => { + test('basic', () => { + const { code } = compileWithExpression(`{{ a }}`) + expect(code).toMatchSnapshot() + expect(code).contains(`ctx.a`) + }) + + test('props', () => { + const { code } = compileWithExpression(`{{ foo }}`, { + bindingMetadata: { foo: BindingTypes.PROPS }, + }) + expect(code).toMatchSnapshot() + expect(code).contains(`$props.foo`) + }) + + test('props aliased', () => { + const { code } = compileWithExpression(`{{ foo }}`, { + bindingMetadata: { + foo: BindingTypes.PROPS_ALIASED, + __propsAliases: { foo: 'bar' } as any, + }, + }) + expect(code).toMatchSnapshot() + expect(code).contains(`$props['bar']`) + }) +}) diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index cc8003fcbc..db9f5bff64 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -104,13 +104,22 @@ export function generate( const [frag, push] = buildCodeFragment() const context = new CodegenContext(ir, options) const { helpers, vaporHelpers } = context - const { inline } = options + const { inline, bindingMetadata } = options const functionName = 'render' + const args = ['_ctx'] + if (bindingMetadata && !inline) { + // binding optimization args + args.push('$props') + } + const signature = (options.isTS ? args.map(arg => `${arg}: any`) : args).join( + ', ', + ) + if (inline) { - push(`(() => {`) + push(`((${signature}) => {`) } else { - push(NEWLINE, `export function ${functionName}(_ctx) {`) + push(NEWLINE, `export function ${functionName}(${signature}) {`) } push(INDENT_START) diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index 7b298ef0fb..fee6cc18aa 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -132,8 +132,9 @@ function genIdentifier( prefix = `${raw}: ` } + const type = bindingMetadata[raw] if (inline) { - switch (bindingMetadata[raw]) { + switch (type) { case BindingTypes.SETUP_LET: name = raw = assignment ? `_isRef(${raw}) ? (${raw}.value = ${assignment}) : (${raw} = ${assignment})` @@ -167,7 +168,14 @@ function genIdentifier( raw = withAssignment(raw) } } else { - raw = withAssignment(canPrefix(raw) ? `_ctx.${raw}` : raw) + if (canPrefix(raw)) { + if (type === BindingTypes.PROPS_ALIASED) { + raw = `$props['${bindingMetadata.__propsAliases![raw]}']` + } else { + raw = `${type === BindingTypes.PROPS ? '$props' : '_ctx'}.${raw}` + } + } + raw = withAssignment(raw) } return [prefix, [raw, NewlineType.None, loc, name]] diff --git a/packages/compiler-vapor/src/index.ts b/packages/compiler-vapor/src/index.ts index de58de4548..6eda102106 100644 --- a/packages/compiler-vapor/src/index.ts +++ b/packages/compiler-vapor/src/index.ts @@ -9,7 +9,7 @@ export { } from './transform' export { generate, - type CodegenContext, + CodegenContext, type CodegenOptions, type VaporCodegenResult, } from './generate' diff --git a/packages/runtime-vapor/src/apiRender.ts b/packages/runtime-vapor/src/apiRender.ts index d691a48dc0..f045c552bc 100644 --- a/packages/runtime-vapor/src/apiRender.ts +++ b/packages/runtime-vapor/src/apiRender.ts @@ -81,7 +81,10 @@ export function setupComponent( component.render, instance, VaporErrorCodes.RENDER_FUNCTION, - [instance.setupState], + [ + instance.setupState, // _ctx + __DEV__ ? shallowReadonly(props) : props, // $props + ], ) resetTracking() }