ts-loaderとbabel-loaderを組み合わせる
babel-loader
だけで、TypeScriptはトランスパイルが可能です。
具体的には
を使います。
もしBabelが必要な状況なのであれば、ts-loader
は必要ありません。
逆に、Babelが不要なのであればts-loader
が必要です。
しかし、
- レガシーブラウザ向けにBabelを通したもの
- モダンブラウザ向けにTSをトランスパイルしただけのもの
の両方が必要な場合は、自分はts-loader
とbabel-loader
を組み合わせるようにしています。
私の環境ではtsconfig.jsonはいずれの場合も次のようなイメージでした。
project
│ .babelrc
│ package-lock.json
│ package.json
│ tsconfig.json
│ webpack.config.js
│
├─dist(ここに吐き出す)
│
├─node_modules
│
└─src
│ hogehoge.ts (具体的な処理を書いていく)
│ polyfill.ts (polyfillのimportのみ。IE向けのバンドルで統合します。)
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"strict": true,
"newLine": "lf",
"outDir": "dist"
},
"exclude": [
"node_modules",
"**/*.test.ts"
]
}
IE11のためにTypeScriptをBabelを使ってトランスパイルする構成
{
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"@babel/preset-typescript": "^7.13.0",
"babel-loader": "^8.2.2",
"core-js": "^3.9.1",
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0"
}
}
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": 11
},
"corejs": 3,
"useBuiltIns": "usage"
}
],
[
"@babel/preset-typescript"
]
],
"plugins": [
]
}
const path = require('path');
module.exports = [
{
entry: 'hogehoge.ts', // ['polyfill.ts', 'hogehoge.ts'] などのようにしてもよさそう
output: {
filename: 'hogehoge.min.legacy.js',
path: path.join(__dirname, 'dist'),
},
resolve: {
extensions: [
'.ts',
'.js',
],
},
module: {
rules: {
test: /\.(ts|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
},
],
},
},
},
];
モダンブラウザだけを対象にTypeScriptをts-loaderを使ってトランスパイルする構成
{
"devDependencies": {
"core-js": "^3.9.1",
"ts-loader": "^8.0.18",
"tslint": "^6.1.3",
"tslint-loader": "^3.5.4",
"typescript": "^4.2.3",
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0"
}
}
const path = require('path');
module.exports = [
{
entry: 'hogehoge.ts'
output: {
filename: 'hogehoge.min.js',
path: path.join(__dirname, 'dist'),
},
resolve: {
extensions: [
'.ts',
'.js',
],
},
module: {
rules: {
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader',
},
// linterも通しておくと吉
// {
// loader: 'tslint-loader',
// options: {
// typeCheck: true,
// fix: false,
// emitErrors: true,
// },
// },
],
},
},
},
];
ts-loaderとbabel-loaderを組み合わせる
- レガシーブラウザ向けにBabelを通したもの
- モダンブラウザ向けにTSをトランスパイルしただけのもの
の2種類を出力したい時。
{
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"@babel/preset-typescript": "^7.13.0",
"babel-loader": "^8.2.2",
"core-js": "^3.9.1",
"ts-loader": "^8.0.18",
"tslint": "^6.1.3",
"tslint-loader": "^3.5.4",
"typescript": "^4.2.3",
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0"
}
}
const path = require('path');
module.exports = [
// べた書きだと長いのでそれぞれをモジュール化したり、
// 重複している部分を変数化したりしてまとめてもよさそう
{
// モダン向け
target: ['web', 'es5'],
output: {
entry: './src/hogehoge.ts',
path: path.join(__dirname, 'dist'),
},
filename: 'hogehoge.min.js',
resolve: {
extensions: [
'.ts',
'.js',
],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader',
},
{
loader: 'tslint-loader',
options: {
typeCheck: true,
fix: false,
emitErrors: true,
},
},
],
},
],
},
},
{
// IE向け
entry: [
'./src/_polyfill.ts',
'./src/hogehoge.ts',
],
target: ['web', 'es5'],
output: {
filename: 'hogehoge.min.legacy.js',
path: path.join(__dirname, 'dist'),
},
resolve: {
extensions: [
'.ts',
'.js',
],
},
module: {
rules: [
{
test: /\.(ts|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
},
],
},
],
},
},
];
IE向けとモダンブラウザ向けをそれぞれ読み込む。
<script src="./hogehoge.min.js" type="module"></script>
<script src="./hogehoge.min.legacy.js" nomodule></script>
Module not found: Error: Can't resolve
Babelを使っているときにこういうエラーがでることがあります。
これが出てしまったときは、
-
.babelrc
ファイル内でcore-jsを3
と明示しているか - babel-loaderの適応条件(
test
)が、ts
とjs
を対象としているか(/\.(ts|js)$/
) -
resolve.extensions
でts
とjs
を指定しているか
Module parse failed: Unexpected token
ts-loader側ではなくbabel-loader側でこれが出てきたら、pluginsの出番です1。
さまざまなプラグインが存在しているので、必要なものをnpm i -D
して.babelrc
に追記しましょう。
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": 11
},
"corejs": 3,
"useBuiltIns": "usage"
}
],
[
"@babel/preset-typescript"
]
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
IE11での「***は定義されていません。」「このオブジェクトではサポートされていない操作です。」など
IEでこれが出てくるときは、core-jsでは賄えないpolyfillの出番です。
この辺とかよく使います。
IE11用のバンドルでしか読み込まないpolyfill.tsでどんどんimportしちゃいましょう(IEで動くように書くよりpolyfill突っ込め派。)。
まとめ
webpackの仕様の深さ、loaderの概念、TypeScript、Babel、polyfill、などなど引っかかるポイントがめちゃめちゃ多くて大変なので、Babelがいらない平和な世界になってほしいと切に願います( ˘ω˘ )