]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(custom-element): correctly handle number type props in prod (#8989)
author白雾三语 <32354856+baiwusanyu-c@users.noreply.github.com>
Wed, 6 Dec 2023 07:16:16 +0000 (15:16 +0800)
committerGitHub <noreply@github.com>
Wed, 6 Dec 2023 07:16:16 +0000 (08:16 +0100)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineProps.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript/defineProps.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/compiler-sfc/src/script/context.ts
packages/compiler-sfc/src/script/defineProps.ts

index 38c4419b5d3f7e20b4468c92a95c69e8d21f86b3..3fbd3a9b7b5f76fcf5e85cd5285236afaa36c509 100644 (file)
@@ -18,6 +18,66 @@ return { props, bar }
 }"
 `;
 
+exports[`defineProps > custom element retains the props type & default value & production mode 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Props { 
+          foo?: number;
+      }
+      
+export default /*#__PURE__*/_defineComponent({
+  __name: 'app.ce',
+  props: {
+    foo: { default: 5.5, type: Number }
+  },
+  setup(__props: any, { expose: __expose }) {
+  __expose();
+
+      const props = __props;
+      
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > custom element retains the props type & production mode 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+  __name: 'app.ce',
+  props: {
+    foo: {type: Number}
+  },
+  setup(__props: any, { expose: __expose }) {
+  __expose();
+
+      const props = __props
+      
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > custom element retains the props type w/ production mode 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+  __name: 'app.ce',
+  props: {
+    foo: {type: Number}
+  },
+  setup(__props: any, { expose: __expose }) {
+  __expose();
+
+      const props = __props
+      
+return { props }
+}
+
+})"
+`;
+
 exports[`defineProps > defineProps w/ runtime options 1`] = `
 "import { defineComponent as _defineComponent } from 'vue'
 
index 23d6a806f0d574b8c913b2e6735b8739c137c81a..7d46c4d2187de8870e9a4041919d670c721fa37e 100644 (file)
@@ -710,4 +710,35 @@ const props = defineProps({ foo: String })
       'da-sh': BindingTypes.PROPS
     })
   })
+
+  // #8989
+  test('custom element retains the props type & production mode', () => {
+    const { content } = compile(
+      `<script setup lang="ts">
+      const props = defineProps<{ foo: number}>()
+      </script>`,
+      { isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
+      { filename: 'app.ce.vue' }
+    )
+
+    expect(content).toMatch(`foo: {type: Number}`)
+    assertCode(content)
+  })
+
+  test('custom element retains the props type & default value & production mode', () => {
+    const { content } = compile(
+      `<script setup lang="ts">
+      interface Props { 
+          foo?: number;
+      }
+      const props = withDefaults(defineProps<Props>(), {
+          foo: 5.5,
+      });
+      </script>`,
+      { isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
+      { filename: 'app.ce.vue' }
+    )
+    expect(content).toMatch(`foo: { default: 5.5, type: Number }`)
+    assertCode(content)
+  })
 })
index 9a05d3b327f80c33c5b87ee13d238c1d99d7e607..91f52707d6850ed1700edd3906db0a41b995ba70 100644 (file)
@@ -130,6 +130,10 @@ export interface SFCScriptCompileOptions {
    * using it, disable this and switch to the [Vue Macros implementation](https://vue-macros.sxzz.moe/features/reactivity-transform.html).
    */
   reactivityTransform?: boolean
+  /**
+   * Transform Vue SFCs into custom elements.
+   */
+  customElement?: boolean | ((filename: string) => boolean)
 }
 
 export interface ImportBinding {
index b05b8d910eefca18875d283feabd9770e48c0e9b..3dc5d3ff0cdc0b0b9f11ddd7978617301462beaa 100644 (file)
@@ -12,6 +12,7 @@ import { TypeScope } from './resolveType'
 export class ScriptCompileContext {
   isJS: boolean
   isTS: boolean
+  isCE = false
 
   scriptAst: Program | null
   scriptSetupAst: Program | null
@@ -95,6 +96,14 @@ export class ScriptCompileContext {
       scriptSetupLang === 'ts' ||
       scriptSetupLang === 'tsx'
 
+    const customElement = options.customElement
+    const filename = this.descriptor.filename
+    if (customElement) {
+      this.isCE =
+        typeof customElement === 'boolean'
+          ? customElement
+          : customElement(filename)
+    }
     // resolve parser plugins
     const plugins: ParserPlugin[] = resolveParserPlugins(
       (scriptLang || scriptSetupLang)!,
index 0d35cdd776cfe1fcfce563e9578e406708b6266b..431f8d949a68ff6b1538f286a458ff7b0010b1bb 100644 (file)
@@ -276,6 +276,17 @@ function genRuntimePropFromType(
       defaultString
     ])} }`
   } else {
+    // #8989 for custom element, should keep the type
+    if (ctx.isCE) {
+      if (defaultString) {
+        return `${finalKey}: ${`{ ${defaultString}, type: ${toRuntimeTypeString(
+          type
+        )} }`}`
+      } else {
+        return `${finalKey}: {type: ${toRuntimeTypeString(type)}}`
+      }
+    }
+
     // production: checks are useless
     return `${finalKey}: ${defaultString ? `{ ${defaultString} }` : `{}`}`
   }