はじめに
作成中のRailsアプリのフロントエンドにReactを使いたかった。
Railsアプリ上でReactを利用する方法は複数あるらしい。
RailsでReact.jsを使ういくつかの方法
2016年時点で、RailsでReact.jsを使う方法はいくつかあって、どれを採用するかで悩みました。
- vendor/assets/javascripts にreact.jsを置いて利用する
- react-rails gem を利用する
- browserify-rails で npm管理して利用する
- railsプロジェクト内に、JavaScript開発用のディレクトリを用意して webpack + babel-loader で利用する
調査したところ、だいたいこんなパターンがあると思っていて、下に行くほどRailsよりもJavaScript開発の知識が必要になってくるイメージでした。
webpackを使った Rails上でのReact開発 - クックパッド開発者ブログ より
できるだけモダンな方法を採用したかったが、
- webpackをいきなり採用する自信がなかった
- 仕事先でWebpackerを使っているプロジェクトがあった
という理由で、Railsのgemとしてwebpackを扱えるWebpackerを採用することに。
せっかくなので個人的に勉強していたTypeScriptも合わせて導入してみる。
方法
READMEをちゃんと読んで進める。
rails/webpacker/README.md - Github
1.Webpackerのインストール
gem 'webpacker'
$bundle install
$bundle exec rails webpacker:install
自分がこれから設定していくWebpack環境のビルドは以下のように行う。
$bin/webpack-dev-server
webpackのビルド
$bin/webpack
2.Reactを使えるようにする
$bundle exec rails webpacker:install:react
3.TypeScriptを使えるようにする
$bundle exec rails webpacker:install:typescript
$yarn add @types/react @types/react-dom
4.jsxファイルをtsxに変更
$mv hello_react.jsx hello_react.tsx
5.tsxファイルの中身を編集
import React from "react";
import ReactDOM from "react-dom";
interface HelloProps {
name: string;
}
const Hello: React.SFC<HelloProps> = props => (
<div>Hello {props.name}!</div>
)
Hello.defaultProps = {
name: "David",
}
document.addEventListener("DOMContentLoaded", () => {
ReactDOM.render(
<Hello name="React" />,
document.body.appendChild(document.createElement("div")),
)
})
Webpacker で React + TypeScript - Qiita より
6.ビルドが成功したらhello_react.tsxファイルを挿入したい任意のRailsのviewsファイルに <%= javascript_pack_tag 'hello_react' %>
という形で挿入。
...
<section>
<%= javascript_pack_tag 'hello_react' %>
</section>
...
7.1~5で作成されたor編集したファイルなど
{
"name": "MyRailsApp",
"private": true,
"dependencies": {
"@babel/preset-react": "^7.0.0",
"@rails/webpacker": "^4.0.6",
"@types/react": "^16.8.23",
"@types/react-dom": "^16.8.4",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"ts-loader": "^6.0.4",
"tslint": "^5.18.0",
"tslint-config-airbnb": "^5.11.1",
"tslint-loader": "^3.5.4",
"typescript": "^3.5.2",
"webpack-dev-server": "^3.5.1"
}
}
{
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"module": "es6",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"*": ["node_modules/*", "app/javascript/*"]
},
"sourceMap": true,
"target": "es5",
"allowSyntheticDefaultImports": true, // 追加
"jsx": "react" // 追加
},
"exclude": [
"**/*.spec.ts",
"node_modules",
"vendor",
"public"
],
"compileOnSave": false
}
// 追加↓
{
"extends": ["tslint-config-airbnb", "tslint-react", "tslint-config-prettier"],
"rules": {
"variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case"]
}
}
...
extensions:
- .jsx // 追加
- .tsx
...
config/webpack/*.jsは特に修正しなかった気がする。
loaderの変更もややこそうだったのでなし。
const { environment } = require('@rails/webpacker')
const typescript = require('./loaders/typescript')
environment.loaders.prepend('typescript', typescript)
module.exports = environment
const PnpWebpackPlugin = require('pnp-webpack-plugin')
module.exports = {
test: /\.(ts|tsx)?(\.erb)?$/,
use: [
{
loader: 'ts-loader',
options: PnpWebpackPlugin.tsLoaderOptions()
}
]
}
感想
いろんなファイルが生成されたのでどこをいじればいいかわからず大変だった。
Linterのエラーが出まくったりビルドが通らなくていろいろ修正したりして沼になったりしたが、READMEとエラー文に忠実に進めていくのが大事。