Rails + TypeScript + webpack環境構築
前置き
タケユー・ウェブ株式会社では、(案件にもよりますが)フロントエンドは基本TypeScript + webpackで書いています。
TypeScript + webpackとなるとwebpackerを使うのがRailsエンジニアには一般的かもしれませんが、webpackerは無駄な設定や依存ライブラリが多い上に、正しく扱うには、
- webpackを理解し
- webpackerでのwebpackの扱い方を理解し
- webpacker越しにwebpackの設定を変更する
と回り道をする必要があって非常に手間なので使っていません。
この記事では、どのように環境構築しているかを説明していきます。
また、コードはGitHubに置いてあります。
本記事執筆時点のバージョン
Rails 5.2.2
Node.js 10.12.0
npm 6.5.0
yarn 1.12.3
TypeScript 3.2.2
webpack 4.28.2
vscode 1.30.2
ディレクトリ構成
- TypeScriptのソースコード置き場は
app/frontend/
- ビルドファイル生成先は
public/javascripts/dist/
インストール
$ yarn add -D typescript webpack webpack-cli ts-loader source-map-loader webpack-manifest-plugin clean-webpack-plugin webpack-livereload-plugin
設定ファイル作成
tsconfig.json
tsc
コマンドを使ってtsconfig.json
ファイルを作成します。
$ npx tsc --init --target es5 --module esnext --moduleResolution node --sourcemap
各オプションの意味について詳しくはtsconfig.json
の中のコメントと公式ドキュメントを読んでください。
webpack.config.js
以下のwebpack.config.jsを作成します
webpack plugins
webpack-manifest-plugin
output: { filename: "[name].[contenthash].js" }
のように定義している場合、例えばfoo.ts
のビルド結果はfoo.10c48d231ae3e965fbfc.js
みたいなファイル名になります。
最終的にどんなファイル名になるかがわからないとscriptタグを書けないので、このプラグインによって以下のようなmanifestファイルを作成します。
{
"foo.js": "foo.10c48d231ae3e965fbfc.js"
}
このmanifestでのキー側のファイル名にはwebpack.config.jsのentry
のキーに使われたファイル名が使われていて、キーなしでentry: "index.ts"
のように書いた場合にはmain.js
という名前になります。
また、manifestファイルのデフォルト名のmanifest.jsonは一般的すぎる名前でちょっと嫌なので、今回は引数に { fileName: "webpack-manifest.json" }
と指定してファイル名を変えています。
clean-webpack-plugin(任意)
ビルド前に引数で指定したディレクトリを消してくれるようになります。
distには古いファイルが溜まりがちなので、このプラグインを入れておくと綺麗に保てて安心です。
webpack-livereload-plugin(任意)
ファイルを更新したら自動でビルドしなおしてブラウザをリロードして欲しい場合(Live Reload / Hot Module Replacement)、webpackを使っているならば通常はwebpack-dev-serverを使います。
ただ、本当にLive Reloadするだけでいいならば、webpack-livereload-pluginを使うと導入が楽です。
今回の例でも、上記webpack.config.jsの設定だけでwebpack --watch
でのLive Reloadが可能になります。
scriptタグ生成
この関数を使って、webpackで生成したファイルをsrc
としたscriptタグを作ります。
<%= javascript_bundle_tag("hello_world") %>
今回の例では開発環境でもビルドファイルにdigestをつける想定のためjavascript_bundle_tag
が呼び出されるたびにmanifestを読み込んでいますが、開発環境ではdigestをつけないのならばサーバー起動時に一回読み込むだけでいいので以下のようにしてもいいと思います。
# config/application.rb
module MyApp
class Application < Rails::Application
config.x.webpack_manifest = JSON.load(Rails.root.join("public", "javascripts", "dist", "webpack-manifest.json"))
end
end# app/helpers/application_helper.rb
module ApplicationHelper
def javascript_bundle_tag(filename)
javascript_include_tag(webpack_manifest[["#{filename}.js"], skip_pipeline: true, defer: true)
end private def webpack_manifest
@webpack_manifest ||= Rails.application.config.x.webpack_manifest
end
end
ちなみに、webpackerでは毎回読み込んでます。
package.json
にコマンド追加(任意)
{
"scripts": {
"start": "webpack --watch",
"build": "webpack -p"
}
}
.gitignore
ビルドファイル生成先を.gitignoreに追加
$ echo "public/javascripts/dist/" >> .gitignore
ビルド・scriptタグ作成
app/frontend/hello_world.ts
を作って、 webpack --watch
や webpack -p
でビルドします。(コード)
ビルドしたファイルは任意のviewファイルで <%= javascript_bundle_tag("hello_world") %>
と書いてscriptタグを作って読み込みます。(コード)
TSLint / Prettier設定
TypeScriptを使うならば、TSLintとPrettierも使うと便利です。
(ただし、2019年1月現在、TSLintはESLintに移行していく予定だそうです)
$ yarn add -D tslint prettier tslint-config-prettier
$ npx tslint --init # tslint.json作成
tslint.jsonのextendsを修正します。
また、TSLintとPrettierで設定がコンフリクトしないように、tslint-config-prettierを入れます。
{
"defaultSeverity": "error",
"extends": ["tslint:latest", "tslint-config-prettier"],
"jsRules": {},
"rules": {},
"rulesDirectory": []
}
あと、個人的にはtsconfig.json
ではprettierが動いて欲しくないので、.prettierignore
にtsconfig.json
を書いておきます。
$ echo "tsconfig.json" > .prettierignore
まとめ
以上でRails + TypeScript + webpackの開発環境ができました。
細かい話をすると色々入ってないものもありますが、プロジェクトによっても対応方法が変わるので、今回は最低限で。
vscodeでの開発環境の話もしたいですが、それはまた機会があれば。