コマンド3つで用意するシンプルなTypeScriptボイラープレート その2

   · ☕ 7 min read

前回の記事では@webpack-cli/init の使用によるボイラープレートの作成を記述しました。

とりあえずTypeScriptを動作させることを目的とした前回の記事でしたが、実際にこちらを使用して開発を進めたところ、(わかってはいたことですが)実際の開発に向けてもう少しconfigurationを弄っていきたくなりました。

今回はシンプルなSPA開発を想定して、最低限必要となるloaderの設定と型定義ファイルの設置について記します。

1. index.htmlの設定

1.1. HTMLテンプレートの用意, HtmlWebpackPluginの設定をWebpack.config.jsに追記

前回の記事で記述した通りに @webpack/cli-init を使用してボイラープレートを作成した場合は、作成時にHtmlWebpackPluinというnpmモジュールがwebpackと一緒にインストールされます。

これはバンドルファイルをサーブする際に使用するHTMLを簡易に作成してくれるプラグインです。便利です。

ただし初期設定の状態ではプレーンなhtmlファイルが自動で作成されるのみなので、プロダクトを作成する上でテンプレートとなるhtmlファイルを使用したい場合は、設定を変更する必要があります。

以下のように webpack.config.jsを修正する形となります。templateプロパティに指定したテンプレートをビルド時に吐いてくれます。公式を参照しています。

👇 変更前

1
2
new webpack.ProgressPlugin(),
		new HtmlWebpackPlugin(),

👇 変更後

1
2
3
4
5
6
new webpack.ProgressPlugin(),
		new HtmlWebpackPlugin(
			{
				template: './src/html/index.html',
			}
		),

テンプレートとなるhtmlファイルには、<script src='./bundle.js'></script>のようにバンドルファイルの参照を記入する必要はありません。追記されたJSファイルをプラグインが吐いてくれます。

1.2. 複数のエントリーポイントの設定

Entryを複数設定する方法についてです。

@webpack-cli/init で初期化を行った際は、作成されるエントリーポイントはHtmlWebpackPluginによって用意されるindex.html一つのみとなっています。仮にSPAを作成しようとした場合、ホーム画面以外にabout, contactといったページを作成することもあるでしょう。これはどのように用意するのでしょうか。

Webpack公式にありました。以下のような形でwebpack.config.jsを記述します。

1
2
3
4
5
6
7
8
module.exports = {
  //...
  entry: {
    home: './home.js',
    about: './about.js',
    contact: './contact.js'
  }
};

これは home.htmlではhome.jsを、about.htmlではabout.jsを読むことを示唆します。
(複数のエントリーポイントがある場合はMPA(Multiple Page Application)と呼ぶようです)

ただし、こちらのwebpack.config.jsのエントリーを弄っただけでは、すべてのtsファイルがすべてのエントリポイントで読み込まれてしまいます。上記の例でいうと、home.htmlにてhome.js以外のjsファイルも読み込まれてしまいます。あくまで上記はwebpack単体での使用を想定した公式による説明であったためであり、HtmlWebpackPluginを使用する上はプラグインがわの設定を行ってファイル読み込みを調整する必要があります。

よく分からなかったので関連issueを眺めていたら、HtmlWebpackPlugin公式にちゃんと書き方が記載されていることが判明しました。chunksプロパティを指定することで読み込むチャンクを限定できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
plugins: [
		new HtmlWebpackPlugin(
			{
				template: './src/html/index.html',
				chunks: ['index']// index.htmlではindex.tsだけ読み込む
			}
		),
		new HtmlWebpackPlugin(
			{
				filename: 'about.html',
				template: './src/html/index.html',
				chunks: ['about']//about.htmlではabout.tsだけ読み込む
			}
		),

あくまでHtmlWebpackPluginを使用した際の動きに限られますが、SPAを作成するのであれば同様の構成とする可能性は大きいでしょう。

ここまでの設定でSPAの実装に最低限必要な状態は整ったかと思います。

2. sassの設定

2.1. sass-loaderの設定をwebpack.config.jsに追記

方方で取り上げられているので割愛します。ics.mediaさんの記事が非常に丁寧に書かれています。

3. imageの設定

imageのバンドルにはfile-loaderを使用します。

file-loaderはfileのimportをresolveしてくれ、outputディレクトリに対してファイルを吐き出してくれます。その名の通り、image以外にもcss, mp3, mp4, なんでもいけます。

3.1. file-loaderの設定をwebpack.config.jsに追記

jpegであれば下記のような形になるかと思います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
				test: /\.jpg$/,
				include: [path.resolve(__dirname, 'src')],
				use: [
					{
						loader: 'file-loader',
						options: {
							name: '[name].[ext]'
						}
					}
				],
			},
3.2. 型定義ファイルを設置

ファイルを読み込んだだけではTypeScript側が型解決できません。そのためなんらかの方法でimageの型を定義しておく必要があります。

具体的な対策について公式を読んだのですが、今ひとつピンと来なかったので、色々とググってみました。

StackOveflowを見つつ、noteのコンピュさんの記事はとてもわかりやすいなあとパクらせて頂き、公式のtsconfig.jsonについての解説読んだが具体的な解決策は明示されておらず、Qiitaの@mtgtoさんの記事がファイル配置時におけるディレクトリ構成の一例を示してくれていた。コンピュさんの記事ではurl-loaderとfile-loaderの使い分けについても具体策を挙げていてくれており、非常に有難いです。

一例としてStackOverflowの回答を見ると、下記のような記述を行なったimport-jpg.d.tsファイルを用意して読み込め、とのことでした。

1
2
3
4
declare module "*.jpg" {
  const value: any;
  export default value;
}

TypeScript の型定義ファイルと仲良くなろう ⇦こちらのhatenaDevelopper’sBlogが非常に丁寧にまとめられています。

3.3. 型定義ファイルの場所をtscconfig.jsonに追記

上記の定義をTypeScriptコンパイラに教えてあげます。tsconfig.jsonに対してpathsプロパティを用いて定義ファイルの場所を指定します。また同時にtypeRootsプロパティを記述し、定義ファイル探索時のルートディレクトリを教えてあげます。

1
2
3
4
5
6
7
8
9
"paths": {
	"import-jpg": [
	"types/import-jpg"
	],
}
"typeRoots": [
	"types",
	"node_modules/@types"
]

上記の場合ですと、「型定義ファイルはtypesディレクトリに存在するので、その中のimport-jpgを読んでね」ということをコンパイラに伝えています。

4. audio/web-fontの設定

imageの設定と同様にこちらも行います。

5. 終わりに

以上で終わりです。

今回は、前回に引き続きwebpackのconfiguration周りについて記しました。これにより最低限SPAを開発する上では十分な環境が構築されるかと思います。

ただ、webpackを使用せずともデフォルトのtscコンパイラとnpm パッケージをいくつか組み合わせればTypeScriptの快適な開発環境は用意できることがわかってきました。特に、簡易なページを用意するにとどまる場合であれば、バンドルを行わないケースもあると思います。

この辺りについて良い方法を探りつつ引き続きノートしていきます。

Share on

whasse
WRITTEN BY
whasse
Web Developer