]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(compiler-vapor): support implicit prop in template
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Wed, 13 Nov 2024 02:12:12 +0000 (10:12 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Wed, 13 Nov 2024 02:12:12 +0000 (10:12 +0800)
13 files changed:
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/expression.spec.ts [new file with mode: 0644]
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/generators/expression.ts
packages/compiler-vapor/src/index.ts
packages/runtime-vapor/src/apiRender.ts

index 95bd002d2548c246819ee6c5997d5c274e329370..7d0eca13fa302289fbcc8f9e13018ff89505df49 100644 (file)
@@ -4,7 +4,7 @@ exports[`compile > bindings 1`] = `
 "import { renderEffect as _renderEffect, setText as _setText, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div></div>")
 
-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("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
 
-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("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
 const t1 = _template("<div></div>")
 
-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 (file)
index 0000000..410acfd
--- /dev/null
@@ -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
+}"
+`;
index 2cbc5a1c9aef4dbf99a77cf25c824144ee2d613b..63c6e2d287ae682d31091601955a5ec20f514f42 100644 (file)
@@ -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
 }"
index bb5fba17d759945a4734bfcbc11edfb41187f78f..c01b6431c92813746b4da8fc6d0cad32a52cbdb8 100644 (file)
@@ -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("<div></div>")
 
-export function render(_ctx) {
+export function render(_ctx, $props) {
   const n0 = t0()
   _renderEffect(() => _setHtml(n0, _ctx.code))
   return n0
index ee8fcf62d89dd0193b9c9685919f676ecedcb05e..5aec9a164986b38c87a07ac3a8bdbfd444d20364 100644 (file)
@@ -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("<input>")
 
-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()
index 18612957b5dd6eebc563ad9f4a86c89c429a4d00..be0649ee1b1369110dda8ea20d26dce91f9c659a 100644 (file)
@@ -65,7 +65,7 @@ const t2 = _template("<div></div>")
 const t3 = _template("<input>")
 _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("<div></div>")
 _delegateEvents("click")
 
-export function render(_ctx) {
+export function render(_ctx, $props) {
   const n0 = t0()
   _delegate(n0, "click", () => _ctx.handleClick)
   return n0
index 2a2f1692096b7698691cf87951b9463f086f6cd9..1c382d8be64e31fbe5502071e738b675b8d7104a 100644 (file)
@@ -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("<div><span></span></div>")
 
-export function render(_ctx) {
+export function render(_ctx, $props) {
   const n2 = t0()
   const n1 = n2.firstChild
   const n0 = _createTextNode([_ctx.msg, " "])
index 76819683240fc16c6dd09203969e9dafbcd7baa6..26a5d6bf52113723837a3b64681811858a560fb6 100644 (file)
@@ -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("<div></div>")
 
-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 (file)
index 0000000..c97decd
--- /dev/null
@@ -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']`)
+  })
+})
index cc8003fcbc76b0ad02eac168997374a9bc9137ab..db9f5bff64ad4bdc096ca7cbc54cc06257d7258e 100644 (file)
@@ -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)
index 7b298ef0fb74a5ac2d443b7c419713480e27b022..fee6cc18aaa5ef361b727b9d47403072cf05946a 100644 (file)
@@ -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]]
 
index de58de4548020626d6b09e2164cf12d5b73adb46..6eda10210603d6b21cdfdd8ca6a8e037eb2c0aa2 100644 (file)
@@ -9,7 +9,7 @@ export {
 } from './transform'
 export {
   generate,
-  type CodegenContext,
+  CodegenContext,
   type CodegenOptions,
   type VaporCodegenResult,
 } from './generate'
index d691a48dc0c5d8837a7660054d6ec326bb07801b..f045c552bc72c2a10be8171245b693896ffe63ba 100644 (file)
@@ -81,7 +81,10 @@ export function setupComponent(
         component.render,
         instance,
         VaporErrorCodes.RENDER_FUNCTION,
-        [instance.setupState],
+        [
+          instance.setupState, // _ctx
+          __DEV__ ? shallowReadonly(props) : props, // $props
+        ],
       )
       resetTracking()
     }