[webpack]ts-loaderでJavaScriptをトランスコンパイルする(babel-loader不要)
こちらにも同じ記事を書いています
ts-loaderはJavaScriptをトランスコンパイル出来るのか?
ts-loaderはTypeScriptをトランスコンパイルするというのが、固定観念になっていないだろうか?しかしTypeScriptのパッケージに付属するtscではJavaScriptをコンパイル出来る。ならばts-loaderでも同様のことが出来て当然なはずだ。特にTypeScript3.7系統になってからは、JavaScriptのトランスコンパイル関する制約がかなり緩和された。ならば試してみるのが早い。
環境構築
パッケージのインストール
適当なディレクトリを作り、以下のコマンドを使ってパッケージを放り込む
コンパイルはTypeScriptにやらせるので、babel類はもちろんインストールしない
yarn init -y
yarn add -D typescript ts-loader webpack webpack-cli
Webpackの設定
今回はJavaScriptのトランスコンパイルが前提なので、最小限のビルド設定のみを記述している
modeをdevelopmentにしているのは、吐き出したソースの状態を視覚的に確認するためである
const path = require("path");
module.exports = {
mode: "development",
// mode: 'production',
entry: [path.resolve(__dirname, "src/index.js")],
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist/js")
},
module: {
rules: [
{
test: /\.(js|ts)$/,
exclude: /node_modules/,
loader: "ts-loader"
}
]
},
resolve: {
extensions: [".ts", ".js"]
},
devtool: "source-map"
};
tsconfig.jsonの設定
ts-loaderを使う場合、JavaScriptのトランスコンパイルもtsconfig.jsonに記述することになる
重要項目はallowJsで、これをtrueに設定しておかなければJavaScriptはコンパイル出来ない
{
"compilerOptions": {
"target": "es5", /*ES5にトランスコンパイル*/
"module": "commonjs",
"lib": [
"es2018",
"dom"
],
"allowJs": true, /*JavaScriptのコンパイルには必須*/
"checkJs": true, /*JavaScriptで簡易的な型チェックを行う*/
"sourceMap": true,
"inlineSources": true,
"outDir": "../../dist",
"strict": true,
}
}
テスト用プログラムの作成
アロー関数とfor-ofはES5へのトランスコンパイルが行われる
bodyの取得にquerySelectorを使っているのは後でTypoの実験をするためなので気にしないで欲しい
addEventListener("DOMContentLoaded", () => {
const message = "動作テスト\nを行う\nサンプル";
const body = document.querySelector("body");
if (body) {
for (const msg of message.split("\n")) {
const node = document.createElement("div");
node.innerHTML = msg;
body.appendChild(node);
}
}
});
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<meta charset="utf-8">
<title>ts-loader sample</title>
<script type="text/javascript" src="js/bundle.js"></script>
</head>
<body>
</body>
</html>
ビルドとその結果
ビルド
yarn webpack
出力コード(コメント部分は除去)
見事にES5へのトランスコンパイルが行われている
ts-loaderでJavaScriptのトランスコンパイルに成功したのだ!
"use strict";
addEventListener("DOMContentLoaded", function () {
var message = "動作テスト\nを行う\nサンプル";
var body = document.querySelector("body");
if (body) {
for (var _i = 0, _a = message.split("\n"); _i < _a.length; _i++) {
var msg = _a[_i];
var node = document.createElement("div");
node.innerHTML = msg;
body.appendChild(node);
}
}
});
ts-loaderの利点
-
babel-loaderがいらない
ts-loaderだけでトランスコンパイル出来るので、babel-loaderは必要なくなる
polyfillのような機能は無いので、@babel/coreは必要に応じて追加すれば良い -
簡易的な型チェックが利用できる
たとえば
const body = document.querySelector("body");
を
const body = document.querySelect("body");
というTypoをしたとすると、トランスコンパイル時に以下のように出力される
TS2551: Property 'querySelect' does not exist on type 'Document'. Did you mean 'querySelector'?
JavaScriptを使っていながら、TypeScriptの恩恵にあずかれるのだ
-
TypeScriptとJavaScriptのやりとりにd.tsが不要となる
TypeScript3.7系統はJavaScriptのコンパイル時、d.tsを自動生成する能力を持っている。この機能が働くと、TypeScriptからJavaScriptのファイルをimportするときに、d.tsを手動で作らなくてもそのまま読み込むことが可能だ。 -
JavaScriptからTypeScriptへの移行が楽になる
JavaScriptをメインで使っている人も、ある日TypeScriptでコードが書きたくなったときに必要なのは拡張子をtsにしたファイルを作ることだけだ
jsとtsのプログラムを混在させる
export function Add(a: number, b: number) {
return a + b;
}
import { Add } from "./add";
addEventListener("DOMContentLoaded", () => {
const body = document.body;
if (body) body.innerHTML = `10+20=${Add(10, 20)}`;
});
結果
10+20=30
JavaScriptからTypeScriptを呼び出しているが、もちろん逆も可能だ。
まとめ
JavaScriptとは型指定を省略できるTypeScriptなのだ
という感覚でプログラムが書ける。
これからTypeScriptへ移行しようかと迷っている方々は、とりあえずローダーだけts-loaderに差し替えてみてはどうだろうか?