BETA

TypeScript + React + Webpackのテンプレ作成の道のり

投稿日:2020-05-24
最終更新:2020-05-24

概要

本記事ではTypeScript + React + Webpackのビルド環境を作ります。
特に、みんな(?)苦手なWebpackの設定方法(=webpack.config.js)に重点を置いていきます。

この記事は以下のステップを踏んでます。

  • とりあえずTypeScriptをコンパイル & 実行可能にする
  • WebpackでTypeScriptをバンドルできるようにする
  • TypeScript + React + Webpackの設定をする

Webpackに関する基本情報はこの辺りを参考にすると良さそうです。

一応GitHubに完成品おいてあります。
koralle/react-ts-webpack-template

環境

  • macOS 10.15.4 Catalina
  • npm 6.14.5
  • node 12.16.1
  • webpack 4.43.0
  • TypeScript 3.9.3

最初の準備 - とりあえずTypeScriptをコンパイル & 実行可能にする -

プロジェクトルートになるディレクトリを作成します。
今回はreact-ts-webpack-templateとします。

$ mkdir react-ts-webpack-template && cd $_  
$ npm init -y  

次に、TypeScriptを実行可能にしましょう。

$ npm install -D typescript  
$ npx tsc -v  
Version 3.9.3  

次に、tsconfig.jsonにTypeScriptをコンパイル & 実行するための設定を記述します。
以下のコマンドでtsconfig.jsonをルートディレクトリ直下に作成します。

$ npx tsc --init  

この結果、私の環境ではtsconfig.jsonの内容を覗くと以下の設定が有効になっていました。

{  
  "compilerOptions": {  
    /* Visit https://aka.ms/tsconfig.json to read more about this file */  

    /* Basic Options */  
    "target": "es5",  
    "module": "commonjs",  

    /* Strict Type-Checking Options */  
    "strict": true,                             

    "esModuleInterop": true,                    

    /* Advanced Options */  
    "skipLibCheck": true,                       
    "forceConsistentCasingInFileNames": true,  
  }  
}  

これを今回は以下のように書き換えます。

{  
  "compilerOptions": {  
    /* Visit https://aka.ms/tsconfig.json to read more about this file */  

    /* Basic Options */  
    "target": "es5", // バージョンES5でJSファイルを出力する  
    "module": "es6", // 出力するモジュールの仕組みとしてES6を指定  

    "outDir": "./",  // コンパイルしたTSファイルと同じ階層にJSファイルを出力する  

    /* Strict Type-Checking Options */  
    "strict": true,  
    "noImplicitAny": true,  

    "esModuleInterop": true,                    

    /* Advanced Options */  
    "skipLibCheck": true,                       
    "forceConsistentCasingInFileNames": true,  
  }  
}  

ちなみにtsconfig.jsonについては以下を参照にすると良さそうです。

これでTypeScriptをコンパイルする準備ができたので、
react-ts-webpack-template/sample.tsを作成して、以下のコードを書いてみます。

class Person {  
  constructor(public name:string, public age: number) {  
    // nameとageがPersonクラスのプロパティに設定される  
  }  

  sayHello = () => console.log(`${this.name} is ${this.age} years old.`);  
}  

const koralle: Person = new Person("koralle", 20);  
koralle.sayHello();  

コンパイルします。

$ npx tsc sample.ts  

`sample.js'が生成されるので実行します。

$ node sample.js  
koralle is 20 years old.  

これでTypeScriptが実行されることが確認できました。

WebpackでTypeScriptをバンドルできるようにする

ここが本題です。
この節での目標は、Person.tsindex.tsをWebpackで./dist/index.jsという
一つのJSファイルにまとめ、その結果を確認することです。

$ tree  
.  
├── Person.ts  
├── index.ts  

ちなみに、Person.tsindex.tsは以下のようになっています。

// Person.ts  
class Person {  
  constructor(public name:string, public age: number) {  
    // nameとageがPersonクラスのプロパティに設定される  
  }  

  sayHello = () => console.log(`${this.name} is ${this.age} years old.`);  
}  

export default Person;  
// index.ts  
import Person from "./Person";  

const koralle: Person = new Person("koralle", 20);  
koralle.sayHello();  

まずはWebpackをインストールします。
ついでにwebpack.config.jsを作成しちゃいましょう。

$ npm install -D webpack webpack-cli && touch webpack.config.js  

package.jsonのdevDependenciesに以下の2つがあれば導入成功です。

"webpack": "^4.43.0",  
"webpack-cli": "^3.3.11",  

次に、Webpackで出力したJSファイルを出力する先となるディレクトリを作ります。
今回はdistにします。

$ mkdir dist && touch ./dist/index.html  

次に、webpack.donfig.jsの設定をします。

以下の項目の設定をします。

  • Entry
  • Output
  • Loaders
  • Plugin

まずはテンプレだと思って以下の記述を追加します。

const path = require('path');  

module.exports = {  

}  

Entry

webpackのビルド時に最初に参照するTSファイルを記述します。
これをEntryといいます。

Entryの詳細はこのリンクから確認できます。

const path = require('path');  

module.exports = {  
    entry: './index.ts',  
}  

Output

出力先のディレクトリを指定します。
これをOutputといいます。

Outputの詳細はこのリンクから確認できます。

const path = require('path');  

module.exports = {  
  entry: './index.ts',  
  output: {  
    path: path.resolve(__dirname, './dist'),  
    filename: 'bundle.js'  
  }  
}  

Loaders

Webpackが扱えるのは.jsファイルと.jsonファイルのみを処理することができます。
.cssファイルや画像ファイル(.jpg, .png, .gif)など、そして今回取り扱う.tsファイルなどはLoaderという拡張機能利用する必要があります。

.tsファイルをWebpackで取り扱うために、今回はts-loaderを使用します。

$ npm install -D ts-loader  

Loaderに関する設定を記述する際には、以下の2つの項目に関する設定が必須です。

  • test
  • use

testは、どのフォーマットのファイルを変換すべきか指定します。
useは、testで指定したフォーマットのファイルを処理するために必要なLoaderを指定します。

今回は.tsファイルをts-loaderを使ってWebpackが処理できるように変換する必要があるので、
webpack.config.jsには以下のように記述します。

const path = require('path');  

module.exports = {  
  entry: './index.ts',  
  output: {  
    path: path.resolve(__dirname, './dist'),  
    filename: 'bundle.js'  
  },  
  module: {  
    rules: [{  
      test: /\.ts$/,  
      use: 'ts-loader'  
    }]  
  },  
}  

Plugin

webpackでビルドするときに最適化、アセット管理、環境変数の注入といった処理を追加する場合には、Pluginを使うことがあります。

この記事では使いません(記事編集時に何か導入して追記する可能性は高いです)。

Mode

Modeについてはこちらに記載がありますが、
今回はdevelopmentだけ設定します。

const path = require('path');  

module.exports = {  
    mode: 'development'  
  entry: './index.ts',  
  output: {  
    path: path.resolve(__dirname, './dist'),  
    filename: 'bundle.js'  
  },  
  module: {  
    rules: [{  
      test: /\.ts$/,  
      use: 'ts-loader'  
    }]  
  },  
}  

その他

resolve.extensionsに関する設定を追加することで、
例えば今回のようにindex.tsからPerson.ts内のPersonクラスをインポートしたい場合、 本来は

import Person from "./Person.ts";  

と記述する必要がありますが、これを

import Person from "./Person";  

と記述することができます。一応設定しておきましょう。

const path = require('path');  

module.exports = {  
    mode: 'development'  
  entry: './index.ts',  
  output: {  
    path: path.resolve(__dirname, './dist'),  
    filename: 'bundle.js'  
  },  
  module: {  
    rules: [{  
      test: /\.ts$/,  
      use: 'ts-loader'  
    }]  
  },  
  resolve: {  
    extensions: ['.ts', '.js', '.json']  
  }  
}  

更に、tsconfig.jsonに以下の記述を追加します。

"outDir": "./dist/",    

つまり、tsconfig.jsonは以下のようになります。

{  
  "compilerOptions": {  
    /* Visit https://aka.ms/tsconfig.json to read more about this file */  

    /* Basic Options */  
    "target": "es5", // バージョンES5でJSファイルを出力する  
    "module": "es6", // 出力するモジュールの仕組みとしてES6を指定  

    "outDir": "./dist/",  // ./dist/にJSファイルを出力する  

    /* Strict Type-Checking Options */  
    "strict": true,  
    "noImplicitAny": true,  

    "esModuleInterop": true,                    

    /* Advanced Options */  
    "skipLibCheck": true,                       
    "forceConsistentCasingInFileNames": true,  
  }  
}  

これで最低限の設定は完了です。
Webpackでビルドしてみます、

$ npx webpack --mode development  

ビルドが正常に完了すれば、node ./dist/bundle.jsとコマンドを入力すると
以下のように出力されるはずです。

$ node ./dist/bundle.js   
koralle is 20 years old.  

TypeScript + React + Webpackの設定をする

ここからはTypeScriptでReactアプリを作成する方法を考えていきます。

最終的にこういう構成にします。

├── dist  
│   ├── index.html  
│   ├── bundle.js  
│   └── bundle.js.map  
├── package-lock.json  
├── package.json  
├── src  
│   ├── App.tsx  
│   └── index.tsx  
├── tsconfig.json  
└── webpack.config.js  

まずはreactreact-domはdependenciesにインストールします。

& npm intall react react-dom  

ReactアプリをTypeScriptで開発するには、devDependenciesに@types/react@types/react-domをインストールします。

npm install -D @types/react @types/react-dom  

ちなみにこれらのパッケージについては公式Docに説明があります。

That @types/ prefix means that we also want to get the declaration files for React and React-DOM. Usually when you import a path like "react", it will look inside of the react package itself; however, not all packages include declaration files, so TypeScript also looks in the @types/react package as well. You’ll see that we won’t even have to think about this later on.
この@types/という接頭辞は、ReactとReact-DOMの宣言ファイルも取得したいということを意味します。通常、"react "のようなパスをインポートすると、reactパッケージの中を探しますが、すべてのパッケージが宣言ファイルを含むわけではないので、TypeScriptは@types/reactパッケージも探します。後になって、このことを考える必要がないことがわかるでしょう。

TypeScriptでReactを書くために必要な宣言ファイルがreactreact-domモジュールだけでは足りなくて、それを@types/react@types/react-domで補ってる、ということでしょうか...(不安)

次にwebpack.config.jsの設定をしますが、まずはSource Mapの設定をしておきましょう。
source-map-loaderをdevDependenciesにインストールします。
このパッケージによって、wepbackでSource Mapを吐き出すことができます。

$ npm install source-map-loader  

webpack.config.jsに設定を追加します。
追加・編集したのは以下の3点ですね。

  • devtool
  • resolve.extensions
  • module.rules
const path = require('path');  
const webpack = require('webpack');  

module.exports = {  
  mode: "development",  

  entry: './index.ts',  

  devtool: 'source-map',  

  output: {  
    path: path.resolve(__dirname, './dist'),  
    filename: 'bundle.js'  
  },  

  module: {  
    rules: [  
      {  
        test: /\.(ts|tsx)$/,  
        use: 'ts-loader',  
      },  
      {  
        enforce: "pre",  
        test: /\.js$/,  
        loader: 'source-map-loader',  
      },  
    ]  
  },  

  resolve: {  
    extensions: ['tsx', '.ts', '.js', '.json']  
  },  

}  

次に、tsconfig.jsonを修正します。
具体的には、compilerOptions.jsxcompilerOptions.sourceMapの項目の設定を追加します。

{  
  "compilerOptions": {  
    /* Visit https://aka.ms/tsconfig.json to read more about this file */  

    /* Basic Options */  
    "target": "es5",      // バージョンES5でJSファイルを出力する  
    "module": "es6",      // 出力するモジュールの仕組みとしてES6を指定  

    "jsx": "react",       // .tsxファイルのコンパイルをReact形式に合わせる  
    "sourceMap": true,    // Source Mapを生成する  

    "outDir": "./dist/",  // ./dist/にJSファイルを出力する  


    /* Strict Type-Checking Options */  
    "strict": true,  
    "noImplicitAny": true,  

    "esModuleInterop": true,                    

    /* Advanced Options */  
    "skipLibCheck": true,                       
    "forceConsistentCasingInFileNames": true,  
  }  
}  

これで最低限の設定はできたので、TypeScriptでReactコンポーネントを作成します。

index,tsxを作ります。。

import * as React from "react";  
import * as ReactDOM from "react-dom";  
import App from "./App";  

ReactDOM.render(  
  <App name="Hello, world!" />,  
  document.getElementById("root"),  
);  

App.tsxを作ります。

import * as React from "react";  

type Props = {  
  name: string;  
}  

const App: React.FC<Props> = (props)=> <h1>{props.name}</h1> ;  

export default App;  

./dist/index.htmlも忘れずに作っておきますl

<!DOCTYPE html>  
<html lang="en">  
<head>  
  <meta charset="UTF-8">  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  <title>koralle's React Template</title>  
</head>  
<body>  
  <div id="root"></div>  
  <script src="bundle.js"></script>  
</body>  
</html>  

準備ができたのでビルドします。

$ npx webpack --mode development  

ブラウザで確認します。

$ npx webpack-dev-server  

終わりに

お疲れさまでした。

(追加予定)

  • CSS、SassのLoaderの設定
  • 画像ファイル用のLoaderの設定
  • 開発用/本番用のwebpack.config.jsの切り替え
  • その他汎用的かつ便利なwebpack.config.jsの設定
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

しばらくはReact (+ TypeScript)、C++、Pythonの学習記録をメインにしていこうと思います。 GitHub→https://github.com/koralle

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう