Webpack4とBabel7とnode-sassによるWebページ作成環境を構築する

ちょっとしたWebサイトの開発にWebpack4とBabel7とnode-sassの 環境を整えたのでメモします。

ディレクトリ構造

ディレクトリ構造は次のとおりです。

1
2
3
4
5
6
7
8
9
10
11
├─ dist
├─ src
│ ├─ script
│ │ └─ main.js
│ └─ style
│ └─ style.scss
├─ .babelrc
├─ .browserslistrc
├─ .eslintrc.js
├─ package.json
└─ webpack.config.js

src以下が開発用ディレクトリでdistが出力用ディレクトリです。

パッケージのインストール

Webpack

JavaScriptのバンドル用にWebpackをインストールします。

1
npm install -D webpack webpack-cli

Babel

Babel本体と、WebpackでBabelを扱うためにbabel-loaderをインストールします。

@babel/preset-envの他にOptional Chainingも使いたいので入れます。

1
2
npm install -D @babel/core @babel/preset-env @babel/plugin-proposal-optional-chaining babel-loader
npm install @babel/polyfill

Sass

WebpackでSassをコンパイル及びバンドルすることもできますが、 jsファイル内にCSSのimportを書く必要があって気持ち悪いのでnode-sassおよび postcss-clinpm scripts内で直接使うことにします。 Webpackはjsのバンドル専用とします。

node-sassでScssのコンパイルを行います。 その後PostCSSのautoprefixerでprefixの付与をし、 postcss-cleanでcssを圧縮します。

1
npm install -D node-sass postcss-cli autoprefixer postcss-clean

ESLint

ESLintをインストールします。 BabelのパーサをESLintで利用するためにbabel-eslintをインストールします。

1
npm install -D eslint babel-eslint

その他

npm scriptsを便利にするためnpm-run-allを入れます。 その他、ファイルの変更の監視とオートリロードのためにwatchbrowser-syncを入れます。

1
npm install -D npm-run-all browser-sync watch

設定ファイル

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const path = require('path')

module.exports = {
entry: './src/script/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader'
}
}
]
}
}

modeはcliの引数で渡します。

.babelrc

1
2
3
4
5
6
7
8
9
10
11
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage"
}
]
],
"plugins": ["@babel/plugin-proposal-optional-chaining"]
}

useBuiltIns"usage"にすることで必要なものだけpolyfillを読み込んでくれるそうです。

.browserslistrc

1
2
last 1 version
not dead

Babelのpreset-envautoprefixerで使われます。 基本的に最新版と1つ前のバージョンまで対応します。 使用率が極端に低いものと公式サポートが切れているものは除いています。

.eslintrc.js

eslint --initでコンフィグファイルを作成します。 必要なパッケージのインストールも行ってくれる便利なやつです。

1
npx eslint --init

Babelのパーサを使うためにコンフィグファイルを修正します。

1
2
3
4
module.exports = {
parser: 'babel-eslint',
extends: 'standard'
}

StandardJSスタイルにしました。

npm scripts

npm scriptは次のとおりにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"scripts": {
"build:scss": "node-sass src/style/style.scss -o tmp/",
"build:postcss": "postcss tmp/*.css -u autoprefixer -d dist",
"build:style": "npm-run-all -s build:scss build:postcss",
"build:js": "webpack --mode=development",
"build": "npm-run-all -p build:js build:style",
"watch:style": "watch \"npm run build:style\" ./src/style/",
"watch:js": "watch \"npm run build:js\" ./src/script/",
"watch:server": "browser-sync start --server dist --files dist/*",
"watch": "npm-run-all -p watch:*",
"release:scss": "node-sass src/style/style.scss -o tmp/",
"release:postcss": "postcss tmp/*.css -u autoprefixer postcss-clean -d dist --no-map",
"release:style": "npm-run-all -s release:scss release:postcss",
"release:js": "webpack --mode=production",
"release": "npm-run-all -p release:js release:style"
}
}

開発時のbuildと本番用のreleaseがあります。 また、開発時用にwatchも用意してあります。

build:scssでスタイルは最初にtmp/へScssをコンパイルし出力します。 build:postcssでPostCSSのautoprefixerをかけています。 build:styleではこの2つをnpm-run-allでまとめています。

build:jswebpackdevelopmentModeで実行しています。

buildbuild:jsbuild:styleを並列に実行します。

watch:styleではscssファイルの変更をwatchで監視し、 変更があった際にはbuild:styleを実行しています。 watch:jsではjsファイルの変更をwatchで監視し、 変更があった際にはbuild:jsを実行しています。 watch:serverbrowser-syncを起動しています。 watchwatch:stylewatch:jswatch:serverを起動しています。

releaseではbuildとほとんど同じで、追加でCSSにpostcss-cleanをかけて WebpackをproductionModeで実行しています。

package.json全文

package.jsonは次のとおりになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
"name": "project",
"version": "1.0.0",
"dependencies": {
"@babel/polyfill": "^7.0.0",
"babel-loader": "^8.0.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"autoprefixer": "^9.1.3",
"babel-eslint": "^9.0.0",
"browser-sync": "^2.24.7",
"eslint": "^5.5.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^4.0.0",
"node-sass": "^4.9.3",
"npm-run-all": "^4.1.3",
"postcss-clean": "^1.1.0",
"postcss-cli": "^6.0.0",
"watch": "^1.0.2",
"webpack": "^4.17.1",
"webpack-cli": "^3.1.0"
},
"scripts": {
"build": "npm-run-all -p build:js build:style",
"build:js": "webpack --mode=development",
"build:postcss": "postcss tmp/*.css -u autoprefixer -d dist",
"build:scss": "node-sass src/style/style.scss -o tmp/",
"build:style": "npm-run-all -s build:scss build:postcss",
"release": "npm-run-all -p release:js release:style",
"release:js": "webpack --mode=production",
"release:postcss": "postcss tmp/*.css -u autoprefixer postcss-clean -d dist --no-map",
"release:scss": "node-sass src/style/style.scss -o tmp/",
"release:style": "npm-run-all -s release:scss release:postcss",
"watch": "npm-run-all -p watch:*",
"watch:js": "watch \"npm run build:js\" ./src/script/",
"watch:server": "browser-sync start --server dist --files dist/*",
"watch:style": "watch \"npm run build:style\" ./src/style/"
}
}