webpackでTypeScriptチュートリアル環境を構築

TypeScriptをwebpackと組み合わせて動かしてみたいので、webpack + TypeScriptの環境を構築する。
流れとしては、最初は純粋にTypeScriptコンパイラを使ってtsファイルをコンパイルして動作させる環境を作り、その後でwebpackを使った環境を作る。

TypeScriptコンパイラを使った環境構築

Node.jsをインストール

公式サイト からインストーラを入手。 もしくは、nodenvを使ってインストール。

$ nodenv version
12.18.3

yarnをインストール

$ brew install yarn
$ yarn -v
1.17.3

TypeScriptをインストール

プロジェクトフォルダを作成して、TypeScriptをローカルインストール。

$ mkdir tutorial && cd tutorial
$ yarn init -y
$ yarn add typescript

以降はtutorialフォルダ下でコマンドを実行する。

TypeScript 動作確認

tsファイルを作成し、コンパイルして動かす。

$ vi index.ts

const message:string = 'Hello! TypeScript!';
console.log(message);

$ vi package.json

{
  "name": "tutorial",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "tsc"  // 追加
  },
  "dependencies": {
    "typescript": "^4.0.3"
  }
}
$ yarn dev index.ts  // コンパイル
$ node index.ts  // Hello! TypeScript!

webpackを使った環境構築

ビルドに必要なモジュールをインストール

$ yarn add -D webpack webpack-cli webpack-dev-server ts-loader --save-dev

TypeScriptコンパイラの設定ファイルを作成

設定ファイルを作成し、必要な設定を入れる。

$ ./node_modules/typescript/bin/tsc --init
$ vi tsconfig.js
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    /* コンパイルに使用する組み込みライブラリを指定する。このオプションが設定されない場合は、targetの値に応じたデフォルトライブラリが使われる。 https://www.typescriptlang.org/docs/handbook/compiler-options.html */
    // "lib": [],
    /* ビルドファイルにコメントを含めない */
    "removeComments": true,
    /* コンパイルエラーがあれば、ビルドファイルを出力しない */
    "noEmitOnError": true,
    /* すべての厳密なタイプチェックオプションを有効にする。*/
    "strict": true,
    /* 未使用のローカル変数が存在する場合にエラーを発生させる */
    "noUnusedLocals": true,
    /* 未使用のパラメータが存在する場合にエラーを発生させる */
    "noUnusedParameters": true,
    /* 関数内のすべてのコードパスが値を返さない場合にエラーを発生させる */
    "noImplicitReturns": true,
    /* switch文のフォールスルーケースが存在する場合にエラーを発生させる。(フォールスルーケース:switch文のcase内でbreakが無い場合に、その下のcaseの処理も実行されること) */
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "exclude": [
    // デフォルトで node_modules/ は除外されるため、この設定はしなくてよい。挙動の説明のために書いているだけ。
    "./node_modules"
  ],
  "include": [
    // ./src 配下のうち、excludeオプションに含まれるものを除いたtsファイルのみコンパイル
    "./src/**/*"
  ]
}

webpackでビルドするための設定

$ vi webpack.config.js

const path = require('path');

module.exports = {
    // モード値を production に設定すると最適化された状態で、
    // development に設定するとソースマップ有効でJSファイルが出力される
    mode: 'development', // "production" | "development" | "none"

    // メインとなるJavaScriptファイル(エントリーポイント)
    entry: './src/index.ts',

    output: {
        path: path.join(__dirname, "dist"),
        filename: "index.js",
        publicPath: "/dist"
    },

    module: {
        rules: [{
            // 拡張子 .ts の場合
            test: /\.ts$/,
            // TypeScript をコンパイルする
            use: 'ts-loader'
        }]
    },
    // import 文で .ts ファイルを解決するため
    resolve: {
        modules: [
            "node_modules", // node_modules 内も対象とする
        ],
        extensions: [
            '.ts',
            '.js' // node_modulesのライブラリ読み込みに必要
        ]
    },
    devServer: {
        contentBase: './',    // 公開するリソースのドキュメントルート
    }
};

$ vi package.json

  "scripts": {
    "dev": "webpack-dev-server --config webpack.config.js",  // 開発環境用ビルドコマンドを追加
    "build": "webpack --config webpack.config.js --mode production"  // 本番環境用ビルドコマンドを追加
  },

実行ファイルを作成

$ vi ./src/index.ts

const message:string = 'Hello! TypeScript!';
console.log(message);

$ vi inde.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
Hello! TypeScript!
<script src="./dist/index.js"></script>  // ビルドしたjsファイルを読み込み
</body>
</html>

ビルド・動作確認

開発環境用にビルド
$ yarn dev
webpack-dev-serverが動作しているアドレス http://localhost:8080/ にアクセス。すると、index.html の内容が表示されてコンソールにHello! TypeScript!が表示され、動作していることが確認できる。
また、webpack-dev-serverのホットリロードが有効になっているので、index.ts を編集するとブラウザが自動でリロードされる。

本番環境では、
$ yarn build
を実行し、ビルドファイル ./dist/index.js を作成することで、index.html絶対パスでブラウザアクセスすると、同じように動作することが確認できる。