吉本式 Web制作のコーディングガイドライン

美しいコーディング・設計をするためのガイドラインコンテンツです。

webpackの設定について

webpackの設定ファイルであるwebpack.config.jsについて解説します。
前回の解説(Web制作の開発環境とファイル構成について)でサンプルデータとしてアップしたsample.zipにあるwebpack.config.jsを見ながら解説を読んでいただくとわかりやすいと思います。

webpack.config.jsの書き方は色々な方法があると思いますが、私の記述方法は、もしかすると一般的ではないかもしれません。
また、この設定ファイルのベースができ始めて1年以上経っているので、より最適な別の記述方法があると思いますので、(きっとある・・・)参考程度に理解していただければと思います。
webpack.config.jsでどういう設定をしているかをこれから解説していきますが、ひとつひとつのコードを具体的に解説するものではありません。
もし興味があれば、webpack.config.jsを調べていただければ、ある程度理解できるはずです。
まず全体的な設定として、pug(.pug)ファイル, scss(.scss)ファイル, ts(.ts)ファイルで設定の記述を分けています。

webpack.config.js
const scssConfig = {
// scssファイル設定
}
const tsConfig = {
// tsファイル設定
}
const pugConfig = {
// pugファイル設定
}
module.exports = [scssConfig, tsConfig, pugConfig];

案件によってはtsファイルを使用しない場合などあるかもしれません。
その場合は、
module.exports = [scssConfig, pugConfig];
というような感じで、tsConfigを削除します。
pug, scss, tsでそれぞれ設定を分けておけば、module.exports配列に必要に応じて削除したり追加したりするだけで対応ができるような仕組みにしています。

それではコードの頭から見ていきます。
まずは設定に必要なパッケージ・定数の解説です。

webpack.config.js
// パッケージの読み込み
const webpack = require('webpack');
const path = require('path');
const globule = require('globule');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

// 公開フォルダ・作業フォルダのディレクトリ指定
const dir = {
src: path.join(__dirname, 'src'),
public: path.join(__dirname, 'public')
};

// 対となる変換ファイルの拡張子指定
const convertExtensions = {
pug: 'html',
scss: 'css',
ts: 'js'
};

// development:開発, production:本番
const mode = 'production';

// エントリーポイントの格納先
const entry = {
pug: {},
scss: {},
ts: {}
};

・・・ 省略

必要なパッケージは、webpackpathglobuleextract-text-webpack-pluginとなります。
それぞれのパッケージの解説は割愛しますが、もし興味があれば、調べてみてください。
定数dirを定義し、公開フォルダ・作業フォルダをそれぞれ設定しておきます。

公開フォルダ → dir['public'] = '/作業ディレクトリ/public/';
作業フォルダ → dir['src'] = '/作業ディレクトリ/src/';

定数convertExtensionsは、エントリーポイントを追加する際に実行するコードで使用します。
pugファイルであればhtmlファイルに変換、scssファイルであればcssファイルに変換、tsファイルであればjsファイルに変換するという対になるファイルを指定する定数です。

定数modeは、各ファイル(pug, scss, ts)の設定で使用するmode設定の値です。
定数entryは、各ファイル(pug, scss, ts)ごとにエントリーポイントを分けてまとめる必要があるので、受け皿になる定数用意しておきます。
この定数も、エントリーポイントを追加する際に必要になります。

パッケージをインストールする必要があるので、package.jsonは次のようになります。
(package.jsonについては別の記事で解説します。)

package.json
{
"devDependencies": {
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"globule": "^1.2.1",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.5"
}
}

webpack.config.jsのrequireで読み込んでいるパッケージのみ抜粋しています。
続いて、変数entryにエントリーポイントを追加するコードを見ていきます。

webpack.config.js
・・・ 省略

Object.keys(convertExtensions).forEach(from => {
const to = convertExtensions[from];
globule.find([`**/*.${from}`, `!**/_*.${from}`], { cwd: dir['src'] }).forEach(filename => {
let _output = filename.replace(new RegExp(`.${from}$`, 'i'), `.${to}`);
let _source = path.join(dir['src'], filename);
if (_output.indexOf('pug/') !== -1) {
_output = _output.replace('pug/', '');
entry['pug'][_output] = _source;
}
if (_output.indexOf('scss/') !== -1) {
_output = _output.replace('scss/', 'css/');
entry['scss'][_output] = _source;
}
if (_output.indexOf('ts/') !== -1) {
_output = _output.replace('ts/', 'js/');
entry['ts'][_output] = _source;
}
});
});

・・・ 省略

上のコードの具体的な解説は割愛しますが、エントリーポイントを格納するために用意した定数entryにpug, scss, tsのそれぞれのファイルごとに出力するファイルを指定するようなコードになっています。

entry['pug']['page/index.html'] = '/作業ディレクトリ/src/pug/page/index.pug'
entry['scss']['css/home/style.css'] = '/作業ディレクトリ/src/scss/home/style.scss'

上のような格納になり、

/src/pug/page/index.pug → /public/page/index.html に出力される。
/src/scss/home/style.scss → /public/css/home/style.css に出力される。

というような設定になります。
これによって前回解説した「Web制作の開発環境とファイル構成について」で触れていた「作業フォルダと公開フォルダで中間言語(pug, scss, ts)と出力ファイル(html, css, js)が対になるようなファイル構成です。」が実現されるようになります。

また、includeされるファイルも存在します。
このincludeされるファイルは出力される必要のないファイルです。
たとえば、index.pugというファイルの中で、header.pugをincludeするのであれば、header.pugをheader.htmlに出力する必要はありません。
このincludeされるファイルには、頭文字に「_(アンダーバー)」を付与します。
header.pugがincludeされるファイルであれば、_header.pugになります。
これはpugファイルに限らず、scssファイルやtsファイルも同様です。
上記のコードで頭文字に「_(アンダーバー)」が設定されているファイルは出力ファイルの対象外としています。
ここは重要なポイントになりますので、頭に入れておいてください。

続いて、各言語(pug, scss, ts)の設定を解説します。

scssファイルの設定について

webpack.config.js(scssファイルで使用するloaderと設定コード部分を抜粋)
・・・ 省略

const scssLoader = {
use: [
{
loader: 'css-loader',
options: {
url: false
}
},
'csscomb-loader',
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
};
const scssConfig = {
mode: mode,
entry: entry['scss'],
output: {
filename: '[name]',
publicPath: '/',
path: dir['public']
},
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract(scssLoader)
}
]
},
plugins: [new ExtractTextPlugin('[name]')],
cache: true
};

scssファイルのloaderには、css-loadercsscomb-loaderpostcss-loadersass-loaderの4つを使用しています。
それぞれのloaderの解説は割愛しますが、もし興味があれば、調べてみてください。
csscomb-loaderには、設定ファイルとして.csscomb.jsonファイルがあります。
postcss-loaderには、設定ファイルとしてpostcss.config.jsファイルがあります。
postcss.config.jsファイルで私が使用しているプラグインはautoprefixerになります。
これらのloaderをpackage.jsonで指定します。
また、付随して必要なパッケージもインストールします。

package.json(scssファイルで使用するloaderと付随して必要なパッケージ)
{
"devDependencies": {
"autoprefixer": "^9.6.1",
"css-loader": "^3.0.0",
"csscomb-loader": "0.0.2",
"node-sass": "^4.12.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0"
}
}

scssファイルに関しては以上です。
続いて、tsファイルの設定についてです。

tsファイルの設定について

webpack.config.js
・・・ 省略

const tsLoader = ['ts-loader', 'tslint-loader'];

const tsConfig = {
mode: mode,
entry: entry['ts'],
output: {
filename: '[name]',
publicPath: '/',
path: dir['public']
},
resolve: {
extensions: ['.js', '.ts']
},
module: {
rules: [
{
test: /\.ts$/,
use: tsLoader
}
]
},
plugins: [new webpack.optimize.AggressiveMergingPlugin()],
cache: true
};

tsファイルのloaderには、ts-loadertslint-loaderの2つを使用しています。
それぞれのloaderの解説は割愛しますが、もし興味があれば、調べてみてください。
ts-loaderには、設定ファイルとしてtsconfig.jsonファイルがあります。
tslint-loaderには、設定ファイルとしてtslint.jsonファイルがあります。
これらのloaderをpackage.jsonで指定します。
また、付随して必要なパッケージもインストールします。

package.json
{
"devDependencies": {
"ts-loader": "^6.0.4",
"tslint": "^5.18.0",
"tslint-loader": "^3.5.4",
"typescript": "^3.5.3"
}
}

tsファイルに関しては以上です。
続いて、pugファイルの設定についてです。

pugファイルの設定について

webpack.config.js
・・・ 省略

const pagelist = require('./pug.config.js');

function getPageListData() {
let _data = {};
if (pagelist.data) {
for (let i = 0; i < pagelist.data.length; i++) {
_data[pagelist.data[i]['name']] = pagelist.data[i];
}
}
return _data;
}

const pugLoader = {
use: [
'html-loader',
{
loader: 'pug-html-loader',
options: {
pretty: true,
data: {
pagelist: getPageListData()
}
}
}
]
};

const pugConfig = {
mode: mode,
entry: entry['pug'],
output: {
filename: '[name]',
publicPath: '/',
path: dir['public']
},
module: {
rules: [
{
test: /\.pug$/,
use: ExtractTextPlugin.extract(pugLoader)
}
]
},
plugins: [new ExtractTextPlugin('[name]')],
cache: true
};

pugファイルのloaderには、html-loaderpug-html-loaderの2つを使用しています。
それぞれのloaderの解説は割愛しますが、もし興味があれば、調べてみてください。
これらのloaderをpackage.jsonで指定します。
また、付随して必要なパッケージもインストールします。

package.json
{
"devDependencies": {
"html-loader": "^0.5.5",
"pug-html-loader": "^1.1.5",
}
}

pugファイルをhtmlファイルに出力する際に、pug.config.jsというpugの設定ファイルが必要になります。
これは私が独自で用意したファイルになるため解説します。
pugファイルからhtmlファイルに出力する際の流れは、次のような流れになっています。

1. pug.config.jsを読み込む(このファイルには、各ページの情報が記載されてます)
2. pugファイルからhtmlファイルに出力する際、getPageListData関数を実行する
3. getPageListData関数によって、pugファイルに各ページの情報を取り込む
4. htmlファイルを出力する

という流れになります。
pug.config.jsに記載されている情報は、各ページのtitleやmeta情報、share情報などです。
これらの情報を、pugファイルに持たせるのではなく、外部ファイル(pug.config.js)で管理したほうが便利ではと思い、独自に設定したものです。
このpug.config.jsファイルについては、pugのファイル設計の解説の際、詳しく解説します。

以上が、webpackの設定についての解説です。
それでは続いてpackage.jsonの設定について解説していきます。