Rails + TypeScript + webpack環境構築

前置き

タケユー・ウェブ株式会社では、(案件にもよりますが)フロントエンドは基本TypeScript + webpackで書いています。

TypeScript + webpackとなるとwebpackerを使うのがRailsエンジニアには一般的かもしれませんが、webpackerは無駄な設定や依存ライブラリが多い上に、正しく扱うには、

と回り道をする必要があって非常に手間なので使っていません。

この記事では、どのように環境構築しているかを説明していきます。

また、コードは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

ディレクトリ構成

インストール

$ 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を作成します

https://github.com/itkrt2y/rails_typescript_webpack/blob/6d1974f2def6c048022911581489774c754c6d66/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タグ生成

https://github.com/itkrt2y/rails_typescript_webpack/blob/6d1974f2def6c048022911581489774c754c6d66/app/helpers/application_helper.rb

この関数を使って、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 --watchwebpack -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が動いて欲しくないので、.prettierignoretsconfig.jsonを書いておきます。

$ echo "tsconfig.json" > .prettierignore

まとめ

以上でRails + TypeScript + webpackの開発環境ができました。

細かい話をすると色々入ってないものもありますが、プロジェクトによっても対応方法が変わるので、今回は最低限で。

vscodeでの開発環境の話もしたいですが、それはまた機会があれば。

TakeyuWeb Engineer’s Blog

Ruby on Railsなどのプログラミング情報や技術的な試みからエンジニアとしての日常のことなどをお届けする、タケユー・ウェブのエンジニアによるブログです。

Tatsuya Itakura

Written by

Software Engineer

TakeyuWeb Engineer’s Blog

Ruby on Railsなどのプログラミング情報や技術的な試みからエンジニアとしての日常のことなどをお届けする、タケユー・ウェブのエンジニアによるブログです。