让 Vue.js 从带有 JSX 包的基本 CLI 安装使用 TypeScript 渲染 JSX

Posted

技术标签:

【中文标题】让 Vue.js 从带有 JSX 包的基本 CLI 安装使用 TypeScript 渲染 JSX【英文标题】:Getting Vue.js to render JSX with TypeScript from base CLI install with JSX package 【发布时间】:2021-09-24 21:46:08 【问题描述】:

设置

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

已选择 Babel、TypeScript、Vuex 和 Linter / Formatter 已选择 2.x 类样式组件 Yes 将 Babel 与 TypeScript 一起使用(现代模式需要, 自动检测到 polyfills,转译 JSX)?

然后,我还安装了jsx support(我验证安装的 Babel 版本是 7,因为该 jsx 支持 repo 需要它)。

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

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

我已经确认 自动生成的 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
    
  

在生成的 auto-generated ma​​in.ts 文件中,JSX 似乎已成功使用(尽管我相信它不是 .tsx 扩展名webpack 在幕后将事情转变为工作:

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

所以自动生成的 App.vue 文件有这个(我忽略了&lt;style&gt; 信息),在npm run serve渲染得很好

<template>
  <div id="app">
    <img  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>

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

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 呈现为 JSX 并通过 TypeScript 挑战? p>

【问题讨论】:

【参考方案1】:

JSX 默认启用

您无需在 Vue CLI 脚手架项目中安装任何 JSX 支持。 @vue/cli-plugin-babel/preset includes @vue/babel-preset-app,已经是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 或 VueDX,您会注意到 JSX 行上报告的 TypeScript 错误。使用&lt;script lang="tsx"&gt; 来避免这些错误:

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

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

【讨论】:

这解决了我的问题。谢谢!过分热衷于添加 JSX 支持,但没有意识到它是内置的。我很惊讶,因为我在构建中选择了“TypeScript”,它不会自动将 lang="tsx" 分配给 script 标签。我相信实际上是缺少(仅是ts)导致了错误。

以上是关于让 Vue.js 从带有 JSX 包的基本 CLI 安装使用 TypeScript 渲染 JSX的主要内容,如果未能解决你的问题,请参考以下文章

我在使用带有电子的 vue js 进行捆绑时遇到问题

在 Vue 中如何使用 JSX,就这么简单!建议收藏

在 Vue 中如何使用 JSX,就这么简单!建议收藏

手把手教你在 Vue 中使用 JSX,不怕学不会!建议收藏

手把手教你在 Vue 中使用 JSX,不怕学不会!建议收藏

Vue.js - vue-cli-service 服务 - img src 没有从对象正确加载