webpack + ts-loader で使う tsconfig.json を動的に切り替える

webpackby mizchi created at 2020/06/10/13:14

ToC

webpack を使っていると typescript の module 指定は、ESM を treeshake するために "module": "esnext" としたい。

しかし、ts-node を前提としたユーティリティスクリプトを作っていると、"module": "commonjs" としないと実行に失敗するようになってしまう。ts-jest も同様。

ts-node に関しては、引数で compilerOptions を書き換える方法があり、次のようになる。

yarn ts-node -O '{"module":"commonjs"}' script/x.ts

これだと常にこの引数を付けて実行する必要があり、不便。

ts-loader の configFile

TypeStrong/ts-loader: TypeScript loader for webpack をちゃんと読むと、configFile という引数がある。これで webpack でコンパイル時の tsconfig を切り替えられる。

(なお、本記事では開発中の ts-loader では型チェックは不要という立場から transpileOnly: true を付けているが、必要な場合は外すように)

デフォルトは ts-node 用に "module": "commonjs" としつつ、webpack に渡す設定だけ "module": "esnext" としたい。ただし、 tsconfig.json は webpack の補完で使われているので、残しておく必要がある。なので、tsconfig.json は起きつつ、それを extends する webpack.tsconfig.js を追加した。

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2019",
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react"
  }
}

webpack.tsconfig.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "esnext"
  }
}

webpack.config.js

const path = require("path");
const HTMLPlugin = require("html-webpack-plugin");
const WorkerPlugin = require("worker-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: {
          loader: "ts-loader",
          options: {
            transpileOnly: true,
            configFile: "webpack.tsconfig.json",
          },
        },
      },
    ],
  },
  resolve: {
    extensions: [".js", ".ts", ".tsx"],
  },
};

応用: プロダクションでターゲットを切り替える

動的に tsconfig.json を選択することで、 開発中は target: es2015 でデバッグしやすくし、production のみ target: es5 するという方法もある。

webpack.tsconfig.prod.json を追加

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "target": "es5",
    "module": "esnext"
  }
}
// webpack.config.js
const path = require("path");
const HTMLPlugin = require("html-webpack-plugin");
const WorkerPlugin = require("worker-plugin");

module.exports = (_, argv) => {
  return {
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          use: {
            loader: "ts-loader",
            options: {
              transpileOnly: true,
              configFile:
                argv.mode === "production"
                  ? "webpack.tsconfig.prod.json"
                  : "webpack.tsconfig.json",
            },
          },
        },
      ],
    },
    resolve: {
      extensions: [".js", ".ts", ".tsx"],
    },
  };
};

これでプロダクションビルド(webpack --mode production) で es5 向けにビルドされるようになった。

History
b4dacba - Add Wed Jun 10 13:42:45 2020 +0900