Laravel 5.4 で導入された Laravel Mix で Vue 2 + JSX を利用できるようにすることは難しくありません。
ただ、ちょっと作業がいるだけで。
もくじ
とりあえず先にコードを
とりあえず試しに、初期状態で JSX を使うコードを書いてみましょう。
Laravel-Mix は .js
でも .jsx
でもほぼ同様に解釈するようになっているのでJSXを書くファイルの拡張子をjs
にするか jsx
にするか気にする必要はないはずです。エディタ等との相性を考えると jsx
のほうがいい気がします。
とりあえず適当なコンポーネントを作り、登録します。
コンポーネントの作り方はrenderがJSXになるくらいで単一ファイルコンポーネントと対して変わりませんね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
export default { render (h) { return <div class={{foo: true}} onClick={this.clickHandler} style={{backgroundColor: '#abe'}}> <span>クリックしてみ?</span> {(() => { return this.items.length ? <ul> {this.items.map((item) => <li>{item}</li>)} </ul> : null })() } </div> }, methods: { clickHandler(e) { this.items.push((new Date).toLocaleString()); }, }, data() { return { items: [], }; } } |
なお、上記コードの場合 export default
してるので 直接 require
すると死にます。
import
を使う or require('hoge').default
する or そもそもmodules
でエクスポートする で対処。
1 2 3 |
import jsxExample from './components/Example' Vue.component('jsx-example', jsxExample); |
で、適当なViewでこのコンポーネントを参照しておきましょう。
1 |
<jsx-example /> |
そして、npm run dev
でビルドします。
………はい。案の定エラーです。JSX をパースする設定をしていないので当然ですね。
JSX を展開する
Vue.js で JSX を使う場合、 babel-plugin-transform-vue-jsx を利用します。
Laravel-Mix はデフォルトで React の JSX に対応してますが、React の JSX と Vue の JSX は微妙に展開結果が違います。
1. インストール
必要なモジュールをnpmでインストールします。
npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props --save-dev
2. .babelrc
を作成する
Laravel-Mixはデフォルトでは以下のようなbabelのオプションを内部で生成して利用していますが、プロジェクトのルートディレクトリに .babelrc
が存在している場合コチラが優先して使用されます。(下記追記注意)
1 2 3 4 5 6 |
{ 'cacheDirectory': true, 'presets': [ ['es2015', { 'modules': false }] ] } |
一般的にはこれに transform-vue-jsx
を追加しておけばいいでしょう。もし既に .babelrc
がプロジェクトに存在している場合はそれに追加、なければ新規に作成します。(追加するのはpluginなので注意)
1 2 3 4 5 6 7 8 |
{ "presets": [ ["es2015",{"modules": false}] ], "plugins": [ "transform-vue-jsx" ] } |
あ、ちなみに {modules: false}
はWebpack2 に import/export を任せるためのオプションです。静的解析が捗るやつ1。
☆追記 Laravel Mix 0.9.0 よりbabelプリセットが変更になっています
Laravel Mix 0.9.0 より、babel-preset-es2015
に代わって babel-preset-env
が使われるようになっています。
このため、これ以降でデフォルトの.babelrcはこのようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 |
{ cacheDirectory: true, presets: [ ['env', { 'modules': false, 'targets': { 'browsers': ['> 2%'], uglify: true } }] ] } |
また、上記の代わりに、以下のように .babelrc
を用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "presets": [ ["env",{ "modules": false, "targets": { "browsers": ["> 2%"], "uglify": true } }] ], "plugins": [ "transform-vue-jsx" ] } |
追記ここまで。
再挑戦
再度ビルドしてみます。ビルドが通ったでしょうか。私は通りました。
Let’s JSX
JSX は template を使った従来の Vue コンポーネントより時に柔軟に記述することができる一方、時に render
の無限ループ内で負荷のかかるコードを書いてしまう危険性があります。(もちろんrender
内で更新系のアクションを行おうものなら [vue warn] で怒られます。)
善悪を捉えながら JSX を有効活用していきましょう。
One more step!
上では jsx ファイルを単体で読み込みましたが、JSXは .vue
でももちろん使用可能です。
(上記インストールを済ませておけば)
<template>
をコンポーネントファイル内に書かず、render
メソッド内でJSXを書くだけ。更にこっちなら vue-loader を経由するため HMR や scoped css も使えるというおまけ付き。また上記の import/export による問題も発生しません。圧倒的にこっちのほうが実用的ですね。
ただし、エディターによってはこの組み合わせに対応しておらずにうまく扱えない場合があるかもしれません。
ちなみにIntelliJ IDEA系の場合、JSのバージョンを React JSX (JSX in ECMAScript 6) としておけば問題ありません。
Laravel + Vue2 + JSX で使用する際の参考になればと思います。