使用 JSX 包从基本 CLI 安装中获取 Vue.js 使用 TypeScript 渲染 JSX

Sco*_*ttS 1 rendering jsx typescript vue.js vue-cli

设置

使用 vue-cli 创建了一个基本项目,在此期间我使用“手动选择功能”进行安装,其中我选择了以下内容(除了 linter 之外):

  • 选定的Babel、TypeScript、Vuex 和 Linter / Formatter
  • 选择2.x
  • 对类风格组件说不
  • 是要与 TypeScript 一起使用 Babel(现代模式、自动检测的 polyfill、转译 JSX 所需)?

然后,我还安装了jsx 支持(并且我验证了安装的 Babel 版本是 7,因为这是该 jsx 支持存储库所必需的)。

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

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    '@vue/babel-preset-jsx', //<-- Added this
  ],
};
Run Code Online (Sandbox Code Playgroud)

我已经确认自动生成的 tsconfig.json具有所需的配置(至少据我所知):

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

Run Code Online (Sandbox Code Playgroud)

我已经确认自动生成的 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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在生成的自动生成的 main.ts文件中,JSX 似乎已成功使用(即使它不是扩展.tsx,因为我相信 webpack 在幕后正在将事情转变为工作:

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

所以自动生成的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>
Run Code Online (Sandbox Code Playgroud)

问题

据我了解,对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>
Run Code Online (Sandbox Code Playgroud)

但相反,我在终端窗口中收到这组错误:

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
Run Code Online (Sandbox Code Playgroud)

我想也许我需要显式使用该h()函数,所以我尝试了该render函数(与正在执行的操作相匹配main.ts):

  render(h, ctx) {
    return h(<p>hello</p>)
  }
Run Code Online (Sandbox Code Playgroud)

那没有用。最后两个错误与上面相同,但第一个错误改为:

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>
Run Code Online (Sandbox Code Playgroud)

我尝试了一些我现在不太记得的其他事情(render我认为,在函数本身和返回值上显式键入 was 之一)。

问题:我仍然缺少哪些设置/配置,或者我有哪些语法问题导致它仍然无法渲染return为 JSX 并通过 TypeScript 挑战?

ton*_*y19 5

默认启用 JSX

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

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

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    // '@vue/babel-preset-jsx', // XXX: Remove this
  ],
};
Run Code Online (Sandbox Code Playgroud)

VS Code 扩展警告

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

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

export default Vue.extend({
  render() {
    return <b>hello</b>
  }
})
</script>
Run Code Online (Sandbox Code Playgroud)