React & Webpack

このクイックスタートガイドでは、TypeScriptをReactWebpackで繋ぐ方法を説明します。 npmで既にNode.jsを使用していることを前提としています。

プロジェクトの構築

新しいディレクトリを作成するところから始めていきましょう。 ここではprojという名前にしましたが、好きな名前にしていただいて構いません。

mkdir proj
cd proj

始めるにあたり、ここでは次のようなプロジェクトの構成を想定しています。

proj/
├─ dist/
└─ src/
   └─ components/

TypeScriptファイルは、TypeScriptコンパイラとwebpackを通してsrcフォルダから実行され、 最終的にdist内のbundle.jsファイルになります。 私たちが書くコンポーネントは、全てsrc/componentsフォルダに入れます。

足場となるこの構成を作成しましょう。

mkdir src
cd src
mkdir components
cd ..

distディレクトリは、最終的にWebpackが作成してくれます。

プロジェクトの初期化

このフォルダをnpmパッケージ化します。

npm init

一連のプロンプトが表示され、 予め用意されているデフォルト以外の値でも好きなように設定することができます。 また、生成されたpackage.jsonファイルで、いつでも自由に変更したり元に戻すことが可能です。

依存関係のあるライブラリをインストール

まず、Webpackがグローバル上にインストールされている状態にします。

npm install -g webpack

Webpackは、あなたのコードと任意の全ての依存関係のライブラリを、ひとつの.jsファイルにまとめる事ができるツールです。

ReactとReact-DOMをそれらの宣言ファイルと一緒に、あなたのpackage.jsonへの依存関係があるものとして追加してみましょう。

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

@types/が接頭辞として付いているものは、ReactとReact-DOMの宣言ファイルも取得することを意味します。 通常、"react"のようなパスをインポートすると、reactパッケージ自身の内部が検索されますが、 パッケージ内部に宣言ファイルが含まれるとは限らないため、TypeScriptは@types/reactパッケージも同様に検索します。

次に開発時に必要となる依存性のあるツールawesome-typescript-loadersource-map-loaderを追加します。

npm install --save-dev typescript awesome-typescript-loader source-map-loader

これらはどちらも、TypeScriptとWebpackをうまく共存させてくれます。 awesome-typescript-loaderはtsconfig.jsonという名前のTypeScript標準の設定ファイルを使用して、 WebpackがTypeScriptのコードをコンパイルするのを手助けしてくれます。

source-map-loaderは独自のソースマップを生成する際に、TypeScriptからのソースマップの出力を使用してwebpackに通知します。 これにより、元のTypeScriptソースコードをデバッグしているかのようにして、最終的に出力されるファイルをデバッグできます。

awesome-typescript-loaderだけがTypeScript用のローダーでは無いことに注意してください。 代わりにts-loaderを使用することもできます。 これらの違いについては、こちらを参照にしてください。

開発時に依存があるものとしてTypeScriptをインストールしていることに注意してください。 TypeScriptをnpm link typescriptを使用してグローバルのコピーにリンクすることもできますが、あまり一般的ではありません。

TypeScriptの設定ファイルを追加

あなたが書くTypeScriptのコードと必須となる宣言ファイルの両方を一緒にする必要があります。

これを行うには、コンパイル設定と入力ファイルのリストを含むtsconfig.jsonを作成する必要があります。 プロジェクトのルートにtsconfig.jsonという名前の新しいファイルを作成し、次の内容を入力してください。

{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react"
    },
    "include": [
        "./src/**/*"
    ]
}

tsconfig.jsonの詳細については、こちらを参照してください。

コードを書く

Reactを使用した初めてのTypeScriptファイルを作成してみましょう。 まず、src/components内にHello.tsxという名前のファイルを作り、下記の内容を書いてください。

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

export const Hello = (props: HelloProps) => <h1>Hello from {props.compiler} and {props.framework}!</h1>;

この例では、全体的にStateless functionalコンポーネントを使用していることに注意してください。 また、この例をこのまま改良していくことも可能です。

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

// 'HelloProps'はpropsの形状(shape)を表すものです。
// Stateがセットされることは無いため、'undefined'型を使用します。
export class Hello extends React.Component<HelloProps, undefined> {
    render() {
        return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>;
    }
}

次は下記の内容で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")
);

index.tsxHelloコンポーネントをインポートしています。 "react""react-dom"とは異なり、Hello.tsxに相対パスを使用していることに注目してください。 これは重要なことです。 こうしなければ、TypeScriptはnode_modules内を検索してしまいます。

また、Helloコンポーネントを表示するページも必要です。 projのルートに、次の内容で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>

ここでnode_modulesからファイルを読み込んでいることに注目してください。 ReactとReact-DOMのnpmパッケージには、Webページに含めることができるスタンドアローンな.jsファイルが含まれていて、 てっとり早く動かすために直接参照しています。

これらのファイルを別のディレクトリにコピーするか、コンテンツ配信ネットワーク(CDN)でホストするようにしてください。 FacebookではReactのバージョンのCDNホストを利用可能にしており、 ここでをその詳細読むことができます。

webpackの設定ファイルを作成

プロジェクトディレクトリのルートにwebpack.config.jsファイルを作成しましょう。

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist"
    },

    // webpackの出力をデバッグするためのsourcemapsを有効化
    devtool: "source-map",

    resolve: {
        // 解決可能な拡張子に'.ts'と'.tsx'を追加
        extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
    },

    module: {
        loaders: [
            // '.ts'または'.tsx'の全てのファイルを、'awesome-typescript-loader'で扱う
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" }
        ],

        preLoaders: [
            // '.js'の全てのファイルに、'source-map-loader'によて予め処理されたsourcemapsを持たせる
            { test: /\.js$/, loader: "source-map-loader" }
        ]
    },

    // インポートしたモジュールのパスが下記のいずれかにマッチする場合、
    // それに相当するグローバル変数が存在するものとしてそれを使用します。
    // 依存性の全てを扱うことを避けることができるようになり、
    // ビルド間でそれらのライブラリがキャッシュ可能になるため重要です。
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    },
};

このexternalsについて疑問に思うかもしれませんが、 Reactの全てが同一ファイルにバンドルされることを避けたいと考えてのことです。 こうすることで、コンパイル時間を減らし、変更が無ければライブラリをキャッシュするブラウザの一般的な機能を利用します。

理想的には、Reactモジュールをブラウザからインポートするだけになることですが、 ほとんどのブラウザが、まだモジュール機能を完全にサポートしていません。

代わりにライブラリは、伝統的に自身をjQuery_のような1つのグローバル変数で扱えるようにしています。 これは"名前空間パターン"と呼ばれ、webpackではこのように書かれたライブラリを引き続き活用することができます。

"react": "React"のエントリーにより、 webpackはReact変数から"react"読み込みをインポートする魔法を働かせます。

webpackの設定についての詳細は、こちらを参照してください。

まとめ

そして、このコマンドを実行します。

webpack

お気に入りのブラウザでindex.htmlを開き、ここから全てが始まることを確認してください! ページ上に、"Hello from TypeScript and React!"と表示されていることが確認できるはずです。

 Back to top

© https://github.com/Microsoft/TypeScript-Handbook

このページは、ページトップのリンク先のTypeScript-Handbook内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • ドキュメントの情報が古い可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。