このブログははてなブログからの移行記事です。
やりたいこと
お仕事でページごとに必要なモジュールのみimport
したJSを実装し、それぞれコンパイルしたいという場面があった。
イメージ的にはsrc/(pc|sp)/**/*.js
をフォルダ構成やファイル名をそのままpublic/js
配下に吐きだすといった感じ。
Webpackは基本的に複数ファイルをよしなに1ファイルにバンドルするものなので結構情報が少なくて詰まったのでメモっておく。
実装方針
Webpackでは複数ファイルをコンパイル対象として、それぞれ特定フォルダに吐き出すといったことをサポートしている。
公式からコードを引用するとこんな感じ。
{ entry: { a: "./a", b: "./b", c: ["./c", "./d"] }, output: { path: path.join(__dirname, "dist"), filename: "[name].entry.js" } }
こんな感じで頑張ってentryに書いていってもいいんだがこれだと2つ問題がある。
- ファイルが増えれば増えるほど自分で書き足していかなきゃいけない
- entryのkey名でファイルが吐きだされるのですべてoutputで定義されたフォルダに吐き出される
2つ目の問題この記事がわかりやすく説明してくれてる。
この記事ではファイルがそこまで多くない想定なので手でentry
の項目を書いているが、私のケースだとファイルが大量にあったので以下の方針で設定を試みた。
- globを使ってコンパイル対象のファイルを全て取得する
- globで取った配列から
outputを基準として出力してほしいフォルダ + ファイル名
をkey,コンパイル対象のファイルパス
をvalueとした連想配列を作る - それをentryに渡す
コード
要するにこんな感じです。
この例はsrc/pc/*.js
とsrc/sp/*.js
をpublic/js/
配下にフォルダ構成そのままに出力する例です。
import webpack from 'webpack'; import path from 'path'; import glob from 'glob'; const jsBasePath = path.resolve(__dirname, 'src/'); const jsCompileFolders = ['pc', 'sp']; const targets = glob.sync(`${jsBasePath}/+(${jsCompileFolders.join('|')})/*.js`); const entries = {}; targets.forEach(value => { const re = new RegExp(`${jsBasePath}/`); const key = value.replace(re, ''); entries[key] = value; }); export default { entry: entries, output: { path: path.join(__dirname, 'public/js'), filename: '[name]', }, }
色々省略してますが、まずはコンパイル対象のフォルダを取る部分。
const targets = glob.sync(`${jsBasePath}/+(${jsCompileFolders.join('|')})/*.js`);
ここで同期処理でコンパイルしたいJSファイルの一覧を取ってきてます。
これを{[outputを基準として吐き出したいフォルダ+ファイル名]: [コンパイルするファイル]}
となるkey-valueをここで作ります。
const entries = {}; targets.forEach(value => { const re = new RegExp(`${jsBasePath}/`); const key = value.replace(re, ''); entries[key] = value; });
もっといい方法ありそうなんですが、愚直にkey-valueをオブジェクトに突っ込んでるだけです。 あとはこれをwebpackのconfigに渡して終わり。
サンプルコード
超必要最低限書いたサンプルコード置いておきます。
まとめ
webpack楽しいぞい