Rails + Vue + Typescript な環境を構築してみる。Part1
Rails プロジェクトを新規作成して、Vue を導入する
Rails で Vue を使いたい場合、Rails プロジェクトを新規作成する時点でオプションを付けて rails new [プロジェクト名] --webpack=vue
を実行すれば OK です。
今回は、既存の Rails プロジェクトに後から Vue を導入するケースを想定して、rails new
後に bin/rails webpacker:install:vue
で Vue を導入します。
$ rails new vue-ts-rails-sample-app
$ bin/rails webpacker:install:vue
これで Webpacker の基本的な設定が済んだ状態で Vue がインストールされて、Rails で Vue が使えるようになる。
Typescript を導入する
続いて、TypeScript の導入を行っていきます。
$ bin/rails webpacker:install:typescript
Typescript with Vue Components を参考に、config/webpack/loaders/typescript.js
を修正し ts-loader
の対象に .vue
を追加します。
// config/webpack/loaders/typescript.js
const PnpWebpackPlugin = require('pnp-webpack-plugin')
module.exports = {
test: /\.(ts|tsx)?(\.erb)?$/,
use: [
{
loader: 'ts-loader',
options: PnpWebpackPlugin.tsLoaderOptions({
appendTsSuffixTo: [/\.vue$/]
})
}
]
}
.vue
をコンパイルする際に Vue の型定義ファイルが必要になるため、app/javascript
以下に型定義ファイルを追加します。今回は app/javascript/types/vue.d.ts
としました。
※ *.d.ts
の設置場所は tsconfig.json
の paths
に指定されているパス以下ならどこでもいい。
// app/javascript/types/vue.d.ts
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
.vue
内などで @/*
と書いた時に app/javascript/
以下が参照されるようにエイリアスを設定します。
// config/webpack/environment.js
const { resolve } = require('path')
// ...snip...
environment.config.merge({
resolve: {
alias: {
'@': resolve('app/javascript')
}
}
})
// ...snip...
// tsconfig.json
"paths": {
"*": ["node_modules/*", "app/javascript/*"],
+ "@/*": ["app/javascript/*"]
},
一先ずここまで行ったところで、Rails への Vue + Typescript の導入が正しくできているか確認してみます。
Vue、Typescript のインストール時に生成された hello_vue.js
と hello_typescript.ts
をリネーム(or 削除)して、v_page.ts
を作成します。(ここら辺は好きなようにしてどうぞ。)
// app/javascript/packs/v_page.ts
import Vue from 'vue'
import App from '@/app.vue'
document.addEventListener('DOMContentLoaded', () => {
const container = document.querySelector("#v-page")
if (container === null) return
const app = new Vue({
render: h => h(App)
}).$mount()
container.appendChild(app.$el)
})
/
で Vue を表示するために controller、routes、view を変更(もしくは新規作成)します。
# app/controllers/sample_controller.rb
class SampleController < ApplicationController
def index
end
end
# config/routes.rb
Rails.application.routes.draw do
root to: "sample#index"
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
<!-- app/views/sample/index.html.erb -->
<div id="v-page"></div>
<%= javascript_pack_tag 'v_page', 'data-turbolinks-track': 'reload' %>
app.vue
の script
を lang="ts"
に変更して、Typescript に対応した書き方に修正します。
今回はクラスベース API は使用せずに、Vue.extend()
を使った書き方にしました。
<!-- app/javascript/app.vue -->
<template>
<div id="app">
<p>{{ message }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
data () {
return {
message: "Hello Vue!"
}
}
})
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
ここまで終わったら、Rails サーバを起動して /
にブラウザからアクセスし、正常にコンパイルができていることと、想定通りの表示になっていることを確認できれば OK です。
おまけ
foreman を導入する
Gemfile に以下を追記後、bundle install
。
# Gemfile
# foreman
gem 'foreman'
$ bundle install
Procfile.dev を作成して、以下を追記。
# Procfile.dev
app: bin/rails s -b 0.0.0.0
frontend: bin/webpack-dev-server
bin/dev-server を作成して、以下を追記。パーミッションを 755
に。
# bin/dev-server
bundle exec foreman start -f Procfile.dev
$ chmod 755 bin/dev-server
これで bin/dev-server
を実行すると、foreman 経由で Rails サーバが立ち上がり、http://localhost:5000/ でアクセスできるようになる。
$ bin/dev-server
Pug を導入する
個人的には Vue の SCF の template
は Pug で記述したいので、Pug を導入します。
$ yarn add pug pug-plain-loader
// config/webpack/loaders/pug.js
module.exports = {
test: /\.pug$/,
use: [
{
loader: 'pug-plain-loader'
}
]
}
// config/webpack/environment.js
const pug = require('./loaders/pug')
environment.loaders.prepend('pug', pug)