React+TypeScript+Webpackで環境構築

今回はReact+TypeScript+webpackの環境構築をしていきたいと思います。公式のドキュメントを参考になぞってみました。是非、一読してみてください。

前提としてnodenpmはインストール済みで進めていきます。

作業ディレクトリを作成してください。

以下のディレクトリ構成で進めていきます。

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

ここでは、まだdistフォルダを作成しなくても良いです。 後述しますが、webpackが自動で作ってくれます。

プロジェクトディレクトリ直下でnpm init -yと実行してください。 そうするとpackage.jsonが生成されます。

webpackのインストール

まずグローバルにwebpackがインストールされているか確認してください。 まだインストールがされていなければ

npm i -g webpackと実行してwebpackがインストールされていることを確認してください。

Reactのインストール

reactとreact-domをインストールしましょう。

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

ここで@typesという接頭辞が出てきて何ぞや?と思われた方もいると思います。この@typesというのはreactreact-dom型定義ファイルになります。

どんな型定義ファイルがあるかはこちらから確認ができます。

react単体で型定義をする場合は、PropTypesなどを作成すると思いますが、TypeScript 2から型定義ファイルの管理をnpmで行えるようになりました。

TypeScriptのインストール

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

この中のパッケージのawesome-typescript-loadersource-map-loaderはwebpackと一緒に使うときに必要になります。

awesome-typescript-loaderはwebpackがTypeScriptのスタンダードな設定ファイルであるtsconfig.jsonを使ってtypescriptのファイルをコンパイルしてくれます。

source-map-loaderはその名の通り、ソースマップを生成してくれます。

tsconfig.jsonの設定

tsconfig.jsonファイルをプロジェクトディレクトリ直下に作成し、以下のように設定してください。

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

  • sourceMap

    • ソースマップの有無。
  • noImplicitAny

    • 厳密に型を決めるときなど、暗黙のanyの型はエラーとすることができます。
  • module

    • moduleコードの生成方法
  • target

    • トランスパイルする先の、ECMAScript の ターゲット・バージョンになります.。

詳細を知りたい方はこちらで確認してください。

Let's Write Code

実際にReactを使ってTypeScriptを書いていきましょう。 まず、Hello.tsxというファイルをsrc/components直下に配置してください。

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>;

こちらはステートレスコンポーネントで記述しています。 文字通り、何か状態を保持ている状態ではなく、描画するためだけのコンポーネントになります。

クラス構文を使って記述すると以下のようになります。

import * as React from "react";

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

// 'HelloProps' describes the shape of props.
// State is never set so we use the '{}' type.
export class Hello extends React.Component<HelloProps, {}> {
    render() {
        return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>;
    }
}

コードの中にこのような記述があります。

React.Component<HelloProps, {}>

ComponentはReact.Component<P, S> を extends したクラスを作成します。 Pは props の型、 Sは state の型となります。

次にindex.tsxをsrc直下に追加します。

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.tsxをインポートしてReact.DOMのrederメソッドでレンダリングしています。

次にHello.tsxの内容を表示させるためにindex.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/umd/react.development.js"></script>
        <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>

        <!-- Main -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

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"
    },
};

上記externalsとあると思いますが、React.jsのプロジェクトでは、webpackによるビルド時のデフォルト挙動がReact.jsライブラリ自体もビルドするため、時間がかかります。

そこでexternals指定してReact.jsをビルドから除外する手順が有効となります。

webapackコマンドを実行してください。

f:id:top_men:20180307010932p:plain

このように表示されていればOKです!

今度はローカルサーバーを立てながら実際に簡単なTodoアプリを作成していきたいと思います。