TypeScriptの公式チュートリアル React & Webpack · TypeScriptをベースに、TypeScriptで記述したReactJSアプリをWebpackでビルドする開発環境の構築手順についてまとめています。
nodeのバージョン
この記事では、以下のバージョンのnode.jsを利用しました。
$ node -v
v8.5.0
$ npm -v
5.3.0
プロジェクトのディレクトリ構成を準備
プロジェクトの構成は、以下のようにsrc
ディレクトリにReactJSのコンポーネントを置き、dist
ディレクトリをWebpackのビルドターゲットとします。
以下コマンドで、プロジェクトのディレクトリ構成を作成します
$ mkdir reactjs-ts-webpack
$ cd reactjs-ts-webpack/
$ mkdir dist
$ mkdir -p src/components
$ tree
.
├── dist
└── src
└── components
3 directories, 0 files
npmプロジェクトの初期化とパッケージのインストール
npm init
コマンドで、package.json
を生成します。
$ npm init -y
まずは、Webpackをインストールします。
ここではローカルにインストールしてみます。
$ npm install --save-dev webpack
Webpack公式ドキュメント: Local Installation
ReactJS関連のパッケージ react
とreact-dom
、また、それらをTypeScriptで利用するための型定義ファイル(declaration files)を含むパッケージをインストールします
$ npm install --save react react-dom @types/react @types/react-dom
開発用のパッケージとして、typescript
と、Webpackでtypescriptをビルそするためのawesome-typescript-loader
、ソースマップを生成するsource-map-loader
をインストールします
$ npm install --save-dev typescript awesome-typescript-loader source-map-loader
package.jsonは以下のようになりました。
// package.json
{{
"name": "reactjs-ts-webpack",
"version": "1.0.0",
"description": "",
"main": "index.tsx",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"awesome-typescript-loader": "^3.2.3",
"source-map-loader": "^0.2.1",
"typescript": "^2.5.2",
"webpack": "^3.5.6"
},
"dependencies": {
"@types/react": "^16.0.5",
"@types/react-dom": "^15.5.4",
"react": "^15.6.1",
"react-dom": "^15.6.1"
}
}
TypeScriptの設定
TSをJSにコンパイルするawesome-typescript-loader
は、TypeScriptの設定ファイルtsconfig.json
を参照します
tsconfig.json
は、以下のように記述します
// tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": [
"./src/**/*"
]
}
tsconfig.json
の詳細はこちら
(日本語訳: tsconfig.json | TypeScript 日本語ハンドブック | js STUDIO )
上記に設定されているもののみ説明します。
compilerOptions
compilerOptions
は、TypeScriptのコンパイラtsc
の実行に指定するオプションです。
各オプションについては、Compiler Options · TypeScriptで参照できます。
参照: TypeScript1.6系のコンパイラのオプション一覧 – Qiita
オプション | 説明 |
---|---|
outDir | コンパイルして生成されたjsファイルの出力先ディレクトリ。後に説明するwebpack.config.js のoutput.path でも指定しているのでここでは省略しても良い。 |
sourceMap | ソースマップを作成するかどうか。ソースマップはoutDirに指定したディレクトリに出力されます。こちらもwebpack.config.js のdevtool にてソースマップの出力が設定されているので省略可。 |
noImplicitAny | true に設定すると暗黙のAny型の宣言がエラーになります ※1 |
module | モジュール管理方法を指定します。commonjs , es6 , amd などを指定できます ※2 |
target | 出力されるjsのECMAScript バージョン |
jsx | TypeScriptのコンパイルプロセスで、JSXもコンパイルする場合はreact を指定します。その他のオプションなど詳細は、JSX · TypeScriptを参照ください。 |
※1 暗黙のAny型について
例えば、以下のコードをコンパイルすると、エラーになります。
// greeting.js
function greeter(person) {
return "Hello, " + person;
}
コンパイルの実行結果
$ tsc greeting.ts --noImplicitAny true
greeting.ts(1,18): error TS7006: Parameter 'person' implicitly has an 'any' type.
※2 モジュールについて参考情報
- Module API – Methods
- JavaScriptのモジュール管理(CommonJSとかAMDとかBrowserifyとかwebpack)
- JavaScript Module Systems Showdown: CommonJS vs AMD vs ES2015
includes
対象ファイルをglobe風のファイルパターンで指定します。
サンプルコード
Reactコンポーネント
TypeScriptで、Reactコンポーネントを記述します。
JSXを含むファイルの拡張子はtsx
を使用します。拡張子tsx
のファイルが、jsx
オプションにreact
を指定した場合にJSXのコンパイル対象となるようです。
// src/components/Hello.tsx
import * as React from "react";
// propsの型定義を指定します
export interface HelloProps { compiler: string; framework: string; }
export const Hello = (props: HelloProps) => <h1>Hello from {props.compiler} and {props.framework}!</h1>;
propsの型定義は、ES6でprop-typesを使うより簡潔に記述できる気がします
components/Hello.tsx
をimportして表示するエントリーファイル
// src/index.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Hello } from "./components/Hello";
ReactDOM.render(
<Hello compiler="TypeScript" framework="React" />,
document.getElementById("example")
);
HTML
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
</head>
<body>
<div id="example"></div>
<!-- Dependencies -->
<script src="./node_modules/react/dist/react.js"></script>
<script src="./node_modules/react-dom/dist/react-dom.js"></script>
<!-- Main -->
<script src="./dist/bundle.js"></script>
</body>
</html>
react.js
とreact-dom.js
はバンドルに含めずに、node_modules
から直接読み込んでいます。
これは、次に説明するwebpack.config.js
のexternals
で設定していますが、実際にはCDNからソースを読み込む場合などに利用します。
Webpackの設定
// webpack.config.js
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
};
entry
Webpackが、バンドルするモジュールの解決を開始するファイル(またはファイルのリスト)を指定します。
Core Concept: Entry
設定リファレンス: entry
output
Webpackが、バンドルした結果を出力するファイルを指定します。
Core Concept: Output
設定リファレンス: Output
modules
ローダーは、test
にマッチするソースファイルを、Webpackが依存性を解決可能なモジュールに変換する処理を実行するものです。
ここではTypeScriptをJSにコンパイルするローダーawesome-typescript-loader
を指定しています。
Core Concept: Loaders
resolve
resolve
は、モジュールの依存性を解決方法に関するオプションを指定します。
ここではextensions
を設定していますが、
extentions
に指定された拡張子のファイルは、モジュールの読み込みに拡張子を省略することができるようになります。
例えば、src/index.tsx
では、./components/Hello.tsx
のimport
で拡張子を省略しています。
// src/index.tsx
import { Hello } from "./components/Hello";
devtool
devtool
は、開発用にソースマップを生成するかどうかを指定します。
ここでは、source-map
を指定しているので、元のTypeScriptをデバッグで参照できるようになります。
webpackでsource-mapを表示できるようにする – Qiita
externals
externals
は、依存性の解決から除外するモジュールを指定します。
ここでは、react.js
とreact-dom.js
を指定しているため、src/index.html
では、2つのファイルを直接script
タグで読み込んでいます。
ビルドの実行
$ ./node_modules/.bin/webpack
[at-loader] Using typescript@2.4.2 from typescript and "tsconfig.json" from /Users/hrendoh/workspace/reactjs-ts-webpack/tsconfig.json.
[at-loader] Checking started in a separate process...
[at-loader] Ok, 0.227 sec.
Hash: 9ecf7f5e1ec6d5984958
Version: webpack 2.2.1
Time: 1373ms
Asset Size Chunks Chunk Names
bundle.js 3.57 kB 0 [emitted] main
bundle.js.map 3.95 kB 0 [emitted] main
[3] ./src/index.tsx 332 bytes {0} [built]
+ 3 hidden modules
ソース変更の度にビルドするようにウォッチするには--watch
オプションを付けて実行します
$ ./node_modules/.bin/webpack --watch
ローカルインストールしていると特にwebpackのコマンドは長くなるので、以下のようにpackage.json
にスクリプトを定義しておくと楽です
// package.json
{
// ...
"scripts": {
"watch": "./node_modules/.bin/webpack --watch"
},
// ...
}
以下のコマンドでウォッチできるようになります
$ npm run watch
参考: NPM Scripts
実行確認
$ open index.html
以下のように表示されました
参考
TypeScriptの型定義ファイルについて