Webpacker で React + TypeScript

この記事では、Webpacker で TypeScript を有効にして、Rails 上に React + TypeScript 開発環境を構築する方法をご紹介します。

## 環境
Rails5.1.4
Webpacker 3.0.2
TypeScript 2.6.1

## 手順

### Webpacker をインストール

```:Gemfile
gem 'webpacker', '~> 3.0'
```

```
$ bundle install 
$ bundle exec rails webpacker:install
$ bundle exec rails webpacker:install:react
```



### TypeScript 関連パッケージをインストール


```
$ yarn add ts-loader typescript @types/react @types/react-dom
```

- ts-loader => Webpacker でデフォルトで採用されている TypeScript 用の loader。(loaderの設定は、node_modules/@rails/webpacker/package/loaders/typescript.js に記述されている。)
- typescript => typescript 本体。
- @types/react, @types/react-dom => react, react-dom の型定義ファイル。


### tsconfig.jsonを作成
tsconfig.json で TypeScript のコンパイラオプションを定義します。
プロジェクトルートで下記コマンドを実行すると、tsconfig.json が作成されます。

```
$ node_modules/typescript/bin/tsc --init
```

最低限の設定として、以下のオプションを有効にします。


``` tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react",
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": true
  }
}
```

- tsconfig.json の詳細については[こちら](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)を参照してください。
- compilerOptionsの詳細については、[こちら](https://www.typescriptlang.org/docs/handbook/compiler-options.html)を参照してください。


### Webpacker で .tsx ファイルを処理できるようにする
拡張子 [.tsx] をconfig/webpacker.yml の extensions に追加します。

```config/webpacker.yml
  # 省略
  extensions:
    - .coffee
    - .erb
    - .js
    - .jsx
    - .ts
    - .tsx # 追加
```

(自分用メモ: webpack の [resolve.extensions](https://webpack.js.org/configuration/resolve/#resolve-extensions) オプションは、module import 時に指定した拡張子をwebpackが自動的に解決するための設定。Webpackerがこの設定をどう解釈しているかは、ソースを読んで確認する。)


以上で設定は完了です！

早速、webpacker:install:react タスクで自動生成された hello_react.js を、 TypeScript で書き換えてみます。

```app/javascript/packs/hello_react.tsx
import * as React from "react"
import * as 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")),
  )
})
```
View で `<%= javascript_pack_tag "hello_react" %>` 実行すると、結果を確認できます。

これだけだと TypeScript の強力さが伝わらないかもしれませんが・・、 それなりの規模のアプリケーションを開発していると、 props の型を定義できるだけでも、かなりの恩恵を受けられます:relaxed:




## TypeScript のloader を変えてみる
今回は TypeScript の loader として ts-loader を使いましたが、もちろん、TypeScript の loader は ts-loader だけではありません。
試しに、[awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader#differences-between-ts-loader)に切り替えてみます。
(at-loader と ts-loaderとの違いは、[こちら](https://github.com/s-panferov/awesome-typescript-loader#differences-between-ts-loader)を参照してください。)

設定はとても簡単で、下記のように、Webpackerの設定ファイルで、node_modules/@rails/webpacker/package/loaders/typescript.js の設定を上書きするだけです。


``` config/webpack/development.js
const environment = require('./environment')

// 追加
environment.loaders.set('typescript', {
  test: /\.tsx?$/,
  use: 'awesome-typescript-loader'
})
// 追加ここまで

module.exports = environment.toWebpackConfig()
```

## まとめ
Webpacker は本当に素晴らしいプロダクトで、細かい設定を気にせずに、簡単に TypeScript で React(もちろん他 Vue や Angularも) アプリケーションを書き始められます。

とにかく TypeScript さわってみたい！という方(もちろん、大規模なSPAを作りたい方も！)は、まずは Rails で小さくスタートしてみると良いのではないでしょうか:thumbsup:

## 参考
https://github.com/rails/webpacker/blob/master/docs/typescript.md