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

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

ディレクトリ構造

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

├─ dist
├─ src
│ ├─ script
│ │ └─ main.js
│ └─ style
│   └─ style.scss
├─ .babelrc
├─ .browserslistrc
├─ .eslintrc.js
├─ package.json
└─ webpack.config.js

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

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

Webpack

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

npm install -D webpack webpack-cli

Babel

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

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

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を圧縮します。

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

ESLint

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

npm install -D eslint babel-eslint

その他

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

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

設定ファイル

webpack.config.js

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

{
  "presets": [
    [
      "@babel/env",
      {
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": ["@babel/plugin-proposal-optional-chaining"]
}

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

.browserslistrc

last 1 version
not dead

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

.eslintrc.js

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

npx eslint --init

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

module.exports = {
  parser: 'babel-eslint',
  extends: 'standard'
}

StandardJSスタイルにしました。

npm scripts

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

{
  "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は次のとおりになります。

{
  "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/"
  }
}