2022.09.18
webpackのEJS Loaderを作って自作のボイラーテンプレートに入れてみた

経緯
webpackとgulpとEJSを利用したボイラーテンプレートからgulpを取り除いてwebpackだけでビルド・ウォッチを実現させる為。
実装した時点でwebpackだけで利用できるLoaderが無くは無かったのですが、webpackのentryに追加することにより出力される .js
ファイルを無くすべく自作することにしました。
最終的に出来たものがこちらです。
この記事でのゴール
webpackでEJSのビルドとウォッチをできるようにする。
「ビルド中にエラーを吐かずに使えれば良い」くらいのノリで作ったものなので、公式リポジトリにコントリビュートするレベルの丁寧な作りではないです。
前提条件
以下をインストール済みであること
- Node.js(16系)
- npm または yarn
使うもの
- @babel/preset-env(7.7.7)
- babel-loader(8.2.3)
- ejs(3.1.8)
- glob(8.0.3)
- webpack(5.69.1)
- webpack-cli(4.10.0)
- webpack-dev-server(4.10.0)
- webpack-stream(7.0.0)
ファイル構成
├── babel.config.js
├── package.json
├── src
│ └── templates // ビルド対象のEJSを入れるディレクトリ
├── webpack-extensions
│ └── ejs-loader // Loaderのファイル
└── webpack.config.js
やること
- Loader用のファイルを用意
- webpack.config.js で1のファイルを利用する
1. Loader用のファイルを用意
このファイルでやること
- ローカルにある
.ejs
のファイルを読み取る - EJSファイルからhtmlファイルにビルドする
webpackのLoaderの作り方については公式を参照
ejs-loader.js
const path = require('path')
const ejs = require('ejs')
module.exports = function(source) {
const fileName = path.basename(this.resourcePath)
const file = this._module.rawRequest
let _source = source
const regExp = new RegExp(`./src/templates/pages/`)
const outputFilePath = file.replace(regExp, '')
const filePathLength = file.split('/').length
const outputFileName = file.split('/')[filePathLength-1]
const excludedExtensionFileName = outputFileName.split('.')[0]
const fileDirectory = outputFilePath.replace(outputFileName, '')
const sourceFileName = `${fileDirectory}/${fileName}`
const outputFile = `${fileDirectory}${excludedExtensionFileName}.html`
const assetInfo = { sourceFilename: sourceFileName }
ejs.renderFile(this.resourcePath, (err, str) => {
_source = str
})
this.emitFile(outputFile, _source, null, assetInfo)
return `export default ${JSON.stringify(_source)}`
}
webpack.config.js で1のファイルを利用する
webpack.config.js
const plugins = [
compiler => {
compiler.hooks.compilation.tap('Compile', compilation => {
compilation.hooks.processAssets.tap(
{
name: 'Compile',
stage: ''
},
(files) => {
// ここで出力されるjsファイルを強制的に取り除いている
Object.keys(files).forEach((fileName) => {
const isMatchRemoveFileName = !fileName.includes('assets') && fileName.includes('.js')
if (isMatchRemoveFileName) {
compilation.deleteAsset(fileName)
}
})
}
)
})
}
]
module.exports = {
// ~ 省略 ~
module: {
rules: [
// ~ 省略 ~
{
test: //
use: [
{
loader: path.resolve(__dirname, 'webpack-extensions/ejs-loader/index.js') // ここに作成したLoaderのパスを入れる
}
]
}
]
}
}