Closed7

Vite で Vue 3 + TSX (JSX) の環境作成

Vue + JSX に興味が出たので試してみることにした。
今回は Vite を使って構築していく。

npm init @vitejs/app vue-tsx --template vue-ts

そのままだと JSX が書けないようなので、プラグインをインストールして設定に追加。

npm i -D @vitejs/plugin-vue-jsx
vite.config.ts
 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
+import vueJsx from '@vitejs/plugin-vue-jsx'

 // https://vitejs.dev/config/
 export default defineConfig({
-  plugins: [vue()]
+  plugins: [vue(), vueJsx()]
 })

.vue ファイルを使わず、.tsx ファイルだけを使う場合(後述)は、元からある vue のプラグインは削除してよい。

template 部分を削除。
script タグを lang="tsx" に変更。
components プロパティは不要。
setup のreturn を JSX を書き出す関数に変更。
画像ファイルは絶対パスに変更する必要があった。 import がよい(後述)

src/App.vue
-<template>
-  <img alt="Vue logo" src="./assets/logo.png" />
-  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
-</template>

-<script lang="ts">
+<script lang="tsx">
 import { defineComponent } from 'vue'
 import HelloWorld from './components/HelloWorld.vue'
 
 export default defineComponent({
   name: 'App',
-  components: {
-    HelloWorld
-  }
+  setup() {
+    return () => (
+      <>
+        <img alt="Vue logo" src="src/assets/logo.png" />
+        <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
+      </>
+    )
+  }
 })
 </script>

FYI: Options API で書く場合は、render メソッドとして定義

  render() {
    return (
      <>
        <img alt="Vue logo" src="src/assets/logo.png" />
        <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
      </>
    )
  }

追記: 画像は絶対パスではなく import して src に指定するのが正解っぽい

import logo from './assets/logo.png'
// 中略
        <img alt="Vue logo" src={logo} />

FYI: style タグが不要な場合は .tsx ファイルにしてもよい(script タグの中身だけ残す)

App.tsx
import { defineComponent } from "vue";
import HelloWorld from "./components/HelloWorld.vue";

export default defineComponent({
  name: "App",
  components: {
    HelloWorld
  },
  setup() {
    // 中略
  }
})

追記: .tsx ファイルは Vue Test Utils の対応が不完全らしい。

https://uit-inside.linecorp.com/episode/82
あとからスタイルを当てたくなったときにリネームしないといけなくなるので、.tsx は避けて全部 .vue ファイル(+ script タグ)にしておくのがよさそうか

@clickonClick にする
イベントハンドラは関数にする
ref の値には .value をつける

src/components/HelloWorld.vue
-<template>
-  <button @click="count++">count is: {{ count }}</button>
-</template>
   setup: () => {
     const count = ref(0)
-    return { count }
+    return () => (
+      <button onClick={() => count.value++}>count is: {count.value}</button>
+    )
   }

JSX だと HMR が効かず、手動でリロードしないと反映されないので地味にストレスがたまる...

調べたら過去に issue が立っていて修正されてるっぽいけど違うか?

https://github.com/vitejs/vite/issues/1486
今後のアップデートに期待。

v-model はそのまま使えた。
修飾子をつける場合はドットではなくアンダースコアをつけて v-model_lazy= のようにする

  setup() {
    const text = ref('')
    return () => (
      <>
        <p>text: {text.value}</p>
        <input v-model={text.value} />
      </>
    )
  }

Vite の JSX プラグインの依存元は @vue/babel-preset-jsx というパッケージで、README では vModel= となっているが、その書き方だと動作はするものの Vetur 上でエラー表示される。(ちなみに vOn:click はランタイムエラーになった)
https://github.com/vuejs/jsx

↑間違い
JSX プラグインの依存元は @vue/babel-plugin-jsx だった。

https://github.com/vuejs/jsx-next
修飾子は以下のように書くのが正解(上記のアンダースコアでも動作はしている)
<input v-model={val} />
<input v-model={[val, ["modifier"]]} />
<A v-model={[val, "argument", ["modifier"]]} />
このスクラップは2021/05/19にクローズされました
作成者以外のコメントは許可されていません