使用 JSX 包从基本 CLI 安装获取 Vue.js 以使用 TypeScript 呈现 JSX

Getting Vue.js to render JSX with TypeScript from base CLI install with JSX package

设置

我已经 created a basic project with the vue-cli,在此期间我使用“手动 select 功能”进行安装,我选择了以下内容(除了 linter):

然后,我还安装了 jsx support(我确认安装的 Babel 版本是 7,因为那个 jsx 支持 repo 需要它)。

在我的bable.config.js文件中我添加了(没有替换vue-cli生成的)预设jsx repo 请求:

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    '@vue/babel-preset-jsx', //<-- Added this
  ],
};

我已经确认 auto-generated tsconfig.json 具有所需的配置(至少据我所知):

"compilerOptions": {
    ...
    "jsx": "preserve",
    ...
}

我已经确认 自动生成的 shims-tsx.d.ts 文件具有所需的配置(至少我明白了):

import Vue, { VNode } from 'vue';

declare global {
  namespace JSX {
    // tslint:disable no-empty-interface
    interface Element extends VNode {}
    // tslint:disable no-empty-interface
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
      [elem: string]: any
    }
  }
}

在生成的自动生成main.ts文件中,JSX似乎被成功使用(即使它是不是 .tsx 扩展,因为我相信 webpack 在幕后正在改变一切:

new Vue({
  store,
  render: (h) => h(App),
}).$mount('#app');

所以自动生成的 App.vue 文件有这个(我忽略了 <style> 信息), 渲染很好npm run serve:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
  </div>
</template>

<script lang="ts">
import Vue, {VNode} from 'vue';
import HelloWorld from './components/HelloWorld.vue';

export default Vue.extend({
  name: 'App',
  components: {
    HelloWorld,
  },
});
</script>

问题

据我了解,对 App.vue 的以下修改应该可以工作(渲染函数正是 jsx 存储库中第一个“语法”示例所具有的功能):

// template removed

<script lang="ts">
import Vue, {VNode} from 'vue';
import HelloWorld from './components/HelloWorld.vue';

export default Vue.extend({
  name: 'App',
  functional: true,
  render() {
    return <p>hello</p>
  }
});
</script>

但是,我在终端中得到了这组错误 window:

ERROR in /home/scott/convrrt-component/view-play/src/App.vue(19,3):
19:3 No overload matches this call.
  The last overload gave the following error.
    Type '() => boolean' is not assignable to type '(createElement: CreateElement, hack: RenderContext<Record<string, any>>) => VNode'.
      Type 'boolean' is not assignable to type 'VNode'.
    17 |     HelloWorld,
    18 |   },*/
  > 19 |   render() {
       |   ^
    20 |     return <p>hello</p>
    21 |   }
    22 | });
ERROR in /home/scott/convrrt-component/view-play/src/App.vue(20,13):
20:13 Cannot find name 'p'.
    18 |   },*/
    19 |   render() {
  > 20 |     return <p>hello</p>
       |             ^
    21 |   }
    22 | });
    23 | </script>
ERROR in /home/scott/convrrt-component/view-play/src/App.vue(20,15):
20:15 Cannot find name 'hello'.
    18 |   },*/
    19 |   render() {
  > 20 |     return <p>hello</p>
       |               ^
    21 |   }
    22 | });
    23 | </script>
Version: typescript 4.1.6

我想也许我需要明确地使用 h() 函数,所以我为 render 函数尝试了这个(有点匹配 main.ts 正在做的事情):

  render(h, ctx) {
    return h(<p>hello</p>)
  }

那个不行。最后两个错误和上面一样,但是第一个错误变成这样:

ERROR in /home/scott/convrrt-component/view-play/src/App.vue(20,14):
20:14 No overload matches this call.
  Overload 1 of 2, '(tag?: string | VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<...>> | AsyncComponentPromise<...> | AsyncComponentFactory<...> | (() => Component<...>) | undefined, children?: VNodeChildren): VNode', gave the following error.
    Argument of type 'boolean' is not assignable to parameter of type 'string | VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<...>> | AsyncComponentPromise<...> | AsyncComponentFactory<...> | (() => Component<...>) | undefined'.
  Overload 2 of 2, '(tag?: string | VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<...>> | AsyncComponentPromise<...> | AsyncComponentFactory<...> | (() => Component<...>) | undefined, data?: VNodeData | undefined, children?: VNodeChildren): VNode', gave the following error.
    Argument of type 'boolean' is not assignable to parameter of type 'string | VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<...>> | AsyncComponentPromise<...> | AsyncComponentFactory<...> | (() => Component<...>) | undefined'.
    18 |   },*/
    19 |   render(h, ctx) {
  > 20 |     return h(<p>hello</p>)
       |              ^
    21 |   }
    22 | });
    23 | </script>

我尝试了一些我现在不太记得的其他事情(我认为 render 上的显式输入是函数本身和 return 值上的一个) .

问题:我还缺少什么 setup/configuration 或者我有什么语法问题导致它仍然无法将 return 呈现为 JSX 并通过 TypeScript护手?

默认启用 JSX

您无需在 Vue CLI 脚手架项目中安装任何 JSX 支持。 @vue/cli-plugin-babel/preset includes @vue/babel-preset-app, which already includes @vue/babel-preset-jsx.

'@vue/babel-preset-jsx' 附加到 Babel 预设会引入错误(可能是由于默认情况下已经存在的预设设置重复)。你应该删除它:

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    // '@vue/babel-preset-jsx', // XXX: Remove this
  ],
};

VS 代码扩展注意事项

如果在 VS Code 中使用 Vetur or VueDX,您会注意到 JSX 行上报告的 TypeScript 错误。使用 <script lang="tsx"> 避免这些错误:

<script lang="tsx">
import Vue from 'vue'

export default Vue.extend({
  render() {
    return <b>hello</b>
  }
})
</script>