執筆者: こつ子
最終更新: 2024/11/16
全国3000万人の「Webサイトは手打ちHTMLこそ至高」という職人の皆さん、こんにちは。
こつ子です。
私は今microCMSを用いてこの記事を書いているため、手打ちHTMLではありません。全国三千万の「Webサイトは手打ちHTMLこそ至高」という職人の皆さん、解散!
皆さんは動的型付け言語と静的型付け言語のどちらが好みですか?
私自身はJavaScriptでプログラミングの世界に入門したので動的型付け自体にはそこまで抵抗はないのですが、周りのプログラマたちはこぞって動的型付けを罵倒します。ひどい話。
今回はそんな動的型付け言語であるJavaScriptを静的型付けできるようにした言語TypeScriptと複数のJavaScript等のソースコードファイルを依存関係を解決しつつ一つのファイルにまとめてくれるwebpackのご紹介です。
かなりの長さの記事となってしまいましたが、お許しください。
あとできるだけ正確な情報をお届けしようとは努力しておりますが、当方も雰囲気でwebpackを使っている節があるため、もし間違いがあればご指摘いただけると幸いです。
そもそもTypeScriptとwebpackとは何でしょう?もともとはどちらもJavaScriptの欠点を克服するためのものでした。まずは二つの技術について軽くおさらいしてみましょう。「そういうのいいから」って言う人は容赦なく飛ばしちゃってください。
https://www.typescriptlang.org/
TypeScriptはMicrosoftが開発しているJavaScriptを拡張して作られたプログラミング言語です。静的型付けを行える点が最大の特徴で、事前にバグを防げるだけでなく、コードエディタ等のコード補完機能を充分に受けることができます。
なお、TypeScript自体をブラウザで実行することはできず、実行する前に一度JavaScriptにコンパイル(トランスパイル)する必要があります。基本的にはTypeScriptコンパイラでコンパイルするのですが、今回はそのコンパイル部分もwebpackにやらせようぜっていう話です。
webpackは複数のJavaScriptファイルを依存関係を解決しながら一つにまとめてくれるモジュールバンドラです。他の言語のようにモジュールごとにファイルを分けることが可能になり、名前空間の汚染を防いだり、より可読性の高いコードを書いたりすることができるようになります。その際に不要な改行を消したり変数名の省略などもしてサイズ圧縮も行ってくれます。
また、複数ファイルを一つにまとめることで、サイト上で読み込む際も必要なHTTPリクエストが一度で済むようになり、高速化につながります。
現代JavaScript(ECMAscript)では待望のimport export機能が実装されていますが、複数回HTTPリクエストを送ることになるため、webpackを使う意義は十分にあるといえるでしょう。
それだけではなく、各種プラグインを導入することでJavaScriptをまとめるだけでなく、画像やCSS、TypeScriptやScssまでもJavaScriptにしてひとまとめにしてくれます。すごい話。
今回はTypeScriptのローダーを導入して複数のTypeScriptファイルを一つのJavaScriptファイルに出力しようという話です。
ちなみに最近では同じようなモジュールバンドラとしてViteやTurbopackがあげられることがあります。ViteやTurbopackの方がビルドが速いし、設定も楽らしい。さてはこの記事もう要らねぇな。
しかしながら、オワコンといわれて随分経ったjQueryが求められることもありますし、この記事も何かの役に立つことでしょう。余力があったらViteやTurbopackも勉強してまとめます。
では、実際に環境構築していきましょう。
ここからCUIを用いて行う手順が多くあります。打ち間違い等に十分注意して行うようにしてください。何らかの結果でお使いのPCがダメージを受けても当方は責任を負いかねます。
まずはwebpackやTypeScriptコンパイラの実行環境であるNode.jsをインストールしましょう。
https://nodejs.org/en/download/package-manager
上の公式ページに沿ってnode.jsのバージョン管理ツールとnode.js本体をご自身の環境に合わせてインストールしてください。基本的にはバージョンはLTSの中で一番新しいものを用いるのが良いと思います。
ちなみにnode.js本体だけをインストールすることもできますが、どうせなら今後の色々を考えてバージョン管理ツールもインストールしておきましょう。
また、node.jsをインストールするとセットでnpmというパッケージマネージャーもインストールされます。今回はこれをメインで使うことになります。
次に任意の作業ディレクトリを作ってください。
今回私は「sample」というディレクトリを作りました。そしてコマンドプロンプト等を用いて、カレントディレクトリをその作業ディレクトリに移してください。
それでは初期化していきましょう。といってもやることは簡単です。以下のコマンドを打つだけ
npm init
多分色々英文が出た後に入力待ちの状態になったと思います。とりあえず尋ねられたことに対して答えていきましょうか。どこかに公開する予定がある場合はきっちり入力するべきですが、そうでない場合はエンター連打でも良いです。
一通り質問が終わると、「package.json」というフォルダがカレントディレクトリに生成されていると思います。
入力した内容が反映されてますね。この後色々とパッケージを入れていくわけですが、ここにはそれらの依存関係等も記録されていきます。
いよいよTypeScriptコンパイラをインストールしますよ!
以下のようなコマンドを打ってください。
npm install typescript
するとpackage.jsonに次のようなものが追加されたと思います。
"dependencies": {
"typescript": "^5.6.3"
}
これでTypeScriptが導入できました。また、その際にpackage.jsonとは別にpackage-lock.jsonというファイルも生成されたと思います。こちらは導入したパッケージの依存関係やバージョンをより詳しく記録したものです。
package.jsonやpackage-lock.jsonを用いることで同じ環境構築を簡単に行うことができるようになるのですが、後でまとめて話します。
今回は使いませんが、以下のようにするとTypeScriptのコンパイルを行うことができます。
npx tsc ファイル名.ts
npmではなくnpxである点に注意してください。npxはパッケージを実行するためのコマンドです。
思ったより簡単ですね。
次はwebpackとそのプラグインを導入します。
とはいっても、やることはさっきと同じです。
#webpack本体のインストール
npm install webpack
#webpackをcliで操作できるようにするパッケージ
npm install webpack-cli
ついでにwebpackでビルドしたものが確認できるように開発用サーバーを建てるパッケージも入れておきましょうか。VScodeをお使いの方は「Live Server」というVScodeの拡張機能で開発用サーバーを建てるのがおすすめですが、Vim派やサクラエディタ派にも配慮していきます。メモ帳派は見捨てます
npm install webpack-dev-server
次にプラグインを導入していきます。
今回必須となるプラグインは「ts-loader」です。
npm install ts-loader
他にもcssをjsファイルに組み込んでくれる「css-loader」やsassやscssをコンパイルしjsファイルに組み込んでくれる「sass-loader」、画像をBase64にして組み込んでくれる「url-loader」などがありますが、今回は割愛。
みなさん、「まだ環境構築続くんか!はよコンパイルさせろ」と思っているかと思いますが、もう少しだけこらえてください。
まずはwebpackの設定から。webpack.config.js
という名前のファイルを生成してください。その後、下記の雛形をコピペしてください
const path = require("path");
module.exports = {
//デフォルトの出力の形が変わる
//production development none のどれか
mode: 'production',
//どこを起点に処理を行うかを設定する
entry: './src/index.ts',
//どこにビルドしたJavaScriptファイルを出力するか
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js"
},
//どの実行環境に向けてビルドするか
target: 'web',
//モジュールについて
module: {
rules: [
//test 正規表現などを用いてファイル名を指定
//loader testの対象となるファイルをどのloaderで処理するかを決める
//exclude testによる検索の対象外となるフォルダ、ファイルを指定
{
test: /\.ts$/,
loader: "ts-loader",
exclude: "/node_modules/"
},
],
},
//開発用サーバを立てるときの設定
devServer: {
host: "127.0.0.1",
port: 5500,
//立てたあとにブラウザで開くか
open: true,
//ーバーが提供する静的ファイルのディレクトリ
static:{
directory: path.resolve(__dirname),
}
},
// パス解決のための設定
//import 文で ライブラリ読み込みに必要
resolve: {
//モジュールを検索するディレクトリを指定
modules: [
path.resolve(__dirname, 'src'),
"node_modules",
],
// 対象となる拡張子
extensions: [
'.ts',
'.js'
],
},
};
基本的にはコメントに書いてある通りです。entryやoutputなどは各自好みのものを設定してください。私は普段、ソースコードはsrcフォルダに、出力結果はdistフォルダに入れているのでそうしています。
幾つか補足説明を加えておきます。
const pass = require("path");
とpath.resolve(__dirname, "dist")
の部分前者はnode.jsの組み込みモジュールの「path」を呼び出している部分、後者はそのpathを用いて引数から絶対パスを生成している部分です。__dirname
はnode.jsにおいて現在のファイルのディレクトリを表す定数です。一つ目の引数である__dirnameで現在のwebpack.config.jsなどがあるディレクトリを入手し、二つ目の"dist"で取得したディレクトリ内のdistフォルダを指す絶対パスを生成している感じですね。
これはビルドした際の形式に影響を与える項目です。
productionは名前の通り製品版としてビルドする際に用います。不要な改行などは全て削除され、変数名なども可能な限り省略されたり短い別の文字に置き換えられたりします。
それに対してdevelopmentは開発用のモードで、どこの部分がどのファイル由来なのかなどが分かるようにコメントなどが添えられます。改行の省略なども控えめ。noneに関してはよくわかんねぇや
他にも様々な項目があるのですが、今回は割愛。
ではTypeScriptの方の設定に移ります。以下のコマンドを打ってください
npx tsc --init
あらためて言いますが、パッケージを実行するときはnpmではなくnpxですよ。
するとtsconfig.json
というファイルが生成されましたね。これはTypeScriptのコンパイルの設定を行うファイルです。
これも各項目についてはコメントを読んでいただくのが良いと思います。
しかしながら、デフォルトのままでは幾つか気になる点があるので修正しておきましょうか。
この項目はTypeScriptをJavaScriptに変換する際に、どのECMAScriptのバージョンにするかを決める項目です。デフォルトではes2016
に設定されていますが、これは正直古いですね。IEがご存命の頃は、IEのためにわざと古いバージョンに変換するということも多かったのですが、今日ではIEもついにMicroSoft社によって引導が渡されたのであまり考慮する必要はないと思います。ここは思い切ってES2023
にあげてしまいましょう!
この項目はTypeScriptの型定義ファイルの検索範囲を指定する項目ですね。TypeScriptではファイル名.d.ts
のように拡張子が.d.ts
のファイルは型定義ファイルとして扱われます。型定義ファイルは名前の通り、ソースコード内の変数等の型を定義するファイルです。同じファイル名のjsファイル、tsファイルの型を定義します。(hoge.d.ts
ならhoge.js
内の変数などの型を定義してくれる。)このファイルがあることで、JavaScriptで書かれたライブラリであっても、TypeScriptの静的型付けの恩恵を受けられるわけです。近年の多くのjsのライブラリはこの型定義ファイルが配布されていることが多いです。tsconfig.json
のtypeRootsの項目がデフォルトのままだと、node_modules/@types
内しか認識してくれないので、少し不便です。以下のように書き換えておきましょう。
"typeRoots": [
"node_modules/@types",
"types"
],
これにより、tsconfig.jsonと同じディレクトリにあるtypesフォルダの中も検索してくれます。node_modulesの中はあまり直接いじらないほうが良いので、npmによってパッケージをインストールされる際に一緒にインストールされる型定義ファイルとは別に自分で作った、ダウンロードした型定義ファイルを入れられるフォルダを用意しておくと良いでしょう。
さぁいよいよ長かった設定もラストです。package.json
を開いてください。その中のscriptsという項目を見てみましょう。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
上記のような内容が書かれていますね。この項目では、npm版シェルスクリプトのようなものです。
上の例の場合、npm run test
とコマンドプロンプトで打つと、echo \"Error: no test specified\" && exit 1
が実行されるという具合です。
よく使うコマンドをあらかじめここに設定しておくと開発効率が上がると思います。
私なら下記のような設定をします。
"scripts": {
"build": "webpack --mode production",
"dev": "webpack --mode development && webpack serve --open --config ./webpack.config.js",
"watch": "npx webpack --watch"
},
という具合です。他にもよく使うコマンドがあれば適宜追加していきましょう。
このタイミングでwebpack.config.js
tsconfig.json
package.json
package-lock.json
を何処かに保存しておきましょう。
npmの便利な機能としてnpm install
とモジュール名を指定せずにコマンドを打つと、自動的にpackage.json
とpackage-lock.json
に沿って必要なパッケージをダウンロードしてくれる機能があるのです。
つまり次回以降の環境構築は上記の4つを作業ディレクトリにコピペしてnpm install
を実行するだけでよくなります。楽ですね。
GitHubなどに上げる際も基本的にはnode_moduleフォルダの部分は不要でpackage.jsonとpackage-lock.jsonをプッシュしておけば良いというわけです。
お疲れ様でした。ひとまずは環境構築はこれで終わりです。いよいよ実際にビルドしてみましょう。どうせならmodule機能も試しますよ。
まずは次のようにディレクトリを作りましょう。今回私は作業ディレクトリの名前を「sample」にしたのでこんな感じになりました。
sample/
├── dist/
│ └── index.js
├── node_module
├── src/
│ ├── index.ts
│ └── module.ts
├── index.html
├── package-lock.json
├── package.json
├── tsconfig.json
└── webpack.config.js
JavaScriptの実行結果がわかるようにindex.html
に書き込みます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>テスト</h1>
<script src="dist/index.js"></script>
</body>
</html>
次にsrc/module.ts
を書いていきます。
//TypeScriptでは:の後ろに型注釈を書く。
//数字→number 文字列→string 返り値なし→void など
//intやfloatの区別はない点に注意
export function getHelloWorld():string{
const HELLO_WORLD:string = "HelloWorld!";
return HELLO_WORLD;
}
ここで定義した関数をsrc/index.ts
から呼び出します。
//moduleの拡張子はデフォルトの設定では省略可能
//むしろ省略しないとエラーが出る。なんで?
import { getHelloWorld } from "./module";
function main():void{
alert(getHelloWorld());
}
main();
これでOKです。
ではビルドしましょうか。早速npm run dev
を使います。
npm run dev
どうでしょうか?ポップアップで「HelloWorld!」が表示されましたか?
ここでdist/index.js
を開くと、色々とコメントが書かれたJavaScriptのファイルが出力されていることがわかると思います。では次はproductionモードでも出力してみましょうか。
npm run build
今度はdist/index.js
が1行にギチギチに詰められたコードに変わっていることが分かると思います。これならかなり読み込み速度も速そうですね。
いかがでしたか?
私も久々の環境構築でしたので、間違っている点や分かりにくい点もあると思いますが、ここまで長文記事を読んで頂きありがとうございます。
TypeScriptもwebpackも便利なものですので、ぜひ皆さんも有効活用してみましょう。