LoginSignup
1
0

More than 1 year has passed since last update.

webpack loaderの自作メモ

Last updated at Posted at 2022-01-04

はじめに

このメモでは、webpack loaderを自作するにあたって得た知見をまとめます。
webpack loaderのイメージが少しでも伝わればよいなーと思います。

webpackとかwebpack loaderってこんな感じ

image.png
上の図はwebpackとwebpack loaderのイメージです。様々なファイルを最終的に1つのjsファイルにまとめます。一番下の例はこちらloader/ShaderpackLoader.tsに書かれているloaderを使った際のファイルの変換のイメージで、glslファイルの文字列をjsのObject型に変換しています。

webpack

webpackは複数のjsファイルに書かれたモジュール(import, exportされるもの)を1つのjsファイルにまとめるツールです。webpackを使うメリットとしては、こちらこちらなどにもあるように以下のことなどが挙げられます。
1. jsを複数の小さなファイルに分けることで、全体が把握しやすくなり可読性が上がる
2. jsファイルの読み込み順を決めてくれる
3. 他人の作ったjsライブラリを簡単に取り込める

webpack loader

webpackの補助ツールのwebpack loaderは、webpackの実行直前にimport文などで取り込む任意の形式のファイルを一時的にjsのコードへと変換します。webpackとloaderを組み合わせることで、上の図のように任意のファイルを1つのjsファイルにまとめられます。webpack loaderの例としては、tsファイルをjsのコードに変換するts loaderなどがあり、他にも有名なものはここに載っています。

自作 webpack loader

loaderは自作することもできます。自作loaderを使うことで、以下のようなことができます。
1. 任意のファイルに書かれた文字列を解析して、都合の良い形式のjsコードに機械的に変換する
2. Node.js専用のライブラリで得た情報をフロントエンド用の静的なjsファイルに埋め込む

1の例としては以下に再掲するglslファイルのjsのオブジェクトへの変換です。glslファイルは、webの3DCGで使われるスクリプトファイルです。
image.png
jsのオブジェクトを直接作成せずファイルを解析するメリットとして、重複した情報をオブジェクトの別のプロパティに人為的なミスなく記入できることや、各ファイルのlinterを使えることなどが挙げられます。前者の例として、上の図の変換後のオブジェクトではshaderFunctionCodeの一部とshaderFunctionNameの値は意図的に重複させています。shaderFunctionNameの値をloaderで機械的に抜き出すことでtypoによるエラーを防いでいます。

webpack loaderを自作する

自作webpack loaderで必要となるのは以下の3つです。
1. webpack loaderのスクリプト(js)
2. webpackの設定ファイル
3. (必要であれば)loaderで変換するファイルの型定義ファイル

webpack loaderのスクリプト

任意の形式のファイルをどのようなjsのコードに変換するかを記述するもので、jsファイルで記述します。もちろん、tsファイルで作成してjsファイルにコンパイルして使うことも可能です。

以下がwebpack loaderのスクリプトの簡単な例です。

hogeLoader.js
module.exports = function (source) {
  const resultJson = {
    original: source,
    hoge: 'hogehoge', 
  };

  return `export default ${JSON.stringify(resultJson)}`;
};

webpack loaderのスクリプトの実態はjsの関数です。仮引数のsourceには、webpack loaderで変換するファイルに記述されている文字列が渡されます。

返り値は文字列で、その内容はmoduleをexportするjsのコードである必要があります。というのも、この返り値の文字列は、webpack loaderで変換するファイルを別のjsファイルからimportrequireで参照した際に渡されるコードとなるためです。

webpackの設定ファイル

webpackの設定ファイルでは、webpack loaderで変換する対象のファイルや、どのloaderを使用するかなどを指定できます。module.rulesに配列としてその情報を記述します。

注意点としては以下の2点です。
1. module.rulesに書かれたloaderは配列の最後の要素から順に実行されます
2. loaderはjsファイルである必要があるため、tsファイルでloaderを作成している場合はwebpack実行前にjsファイルに変換する必要があります

以下はwebpackの設定ファイルの例です。

webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.ts',

  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: [/node_modules/],
        loader: 'ts-loader',
      },
      {
        test: /\.hoge$/,
        include: /test.hoge/,
        loader: path.resolve(
          __dirname,
          './loader/dist/loader/hogeLoader.js'
        ),
      },
    ],
  },

webpackは、module.exports.entryでexportされているmoduleから参照できる全てのファイルを1つのjsにまとめようとします。まとめる前に、import, requireで参照されるファイルをmodule.rulesに従って変換します。

module.rulestestはloaderを実行する対象のファイルのパスの名前を正規表現で指定します。exclude, includeはそれぞれloaderを実行しないファイルのパス、実行するファイルのパスを指定します。loaderは、使用するwebpack loaderを指定します。npm packageとしてインストールしたloaderを使う場合はパッケージ名を指定します(上の例だとts-loader)。ライブラリ内にloaderがある場合はその絶対パスを指定します。上の例では、(webpack.config.jsがあるディレクトリ)/loader/dist/loaderディレクトリにhogeLoader.jsがある必要があります。

型定義ファイル

tsファイルから、webpack loaderで変換する適当な拡張子のファイルをimportしようとすると、以下のようなエラーが起きます。

image.png
解決方法としては、以下の2つです。
1. requireで参照する
2. 型定義ファイルを用意する

1の方法は簡単ではありますが、参照したObjectはany型になります。any型を使いたくない場合、2の方法を取る必要があります。

型定義ファイルの例は以下の通りです、

hoge.d.ts
declare module '*.hoge' {
  const original: string;
  const hoge: string;
}

型定義ファイルの説明については参考文献が多数あるので、そちらをご覧ください。型定義ファイル自体についてはこちら、置く場所についてはこちらなどが参考になるかと思います。

さいごに

webpack loaderを作って思ったことは、時間的に変化するデータに応じて、機械的にアップデートしたいファイル・データがあるときに便利だなーということです。「こんな機械的で単調なアップデート作業など、わざわざ人間様が毎度やることではない!」と思ったときなど、是非webpack loaderを作ってコマンド1つで機械様にお願いすることを考えてはいかがでしょう。

参考文献など

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0