2019.2.18

【テンプレ有り】webpack4でSassとES6の開発環境を構築する

webpack(ウェブパック)とは、モジュールバンドラーと呼ばれる複数のファイルを1つにまとめることが出来るツールです。

webpackを使うことによって、サイト上でサーバーへのリクエストを減らして表示速度を向上出来たり、開発時に機能ごとに複数のファイルに分けて作業をすることが可能になります。

本記事では、サービスサイトなど通常のサイトを作ることを想定としており、Vue.jsなどを使いSPAを作るフロントエンドエンジニア向けでは無いので予めご了承下さい。

また、本記事で紹介しているwebpackの設定で出来ることは下記の通りになります。

  • Sass(Scss)をコンパイルしてcssに出力
  • cssにベンダープレフィックスを自動付与(Autoprefixer)
  • ES6をES5にコンパイル(これによりアロー関数やファイル分割が可能になる)
  • cssとjsでソースマップを使用可能&minify化
  • 開発用、本番用で実行したい処理を分ける

 

本記事で紹介するコードはこちらからダウンロード出来ます。

環境構築

必要なファイルをダウンロード

本記事では、私が用意したコードを元に解説を行っていきますので、ファイル一式をこちらからダウンロードして下さい。

ディレクトリ構成は下記のようになっているかと思います。

|--_src
| |--js
| | |--_index.js
| | |--hoge.js
| |--sass
| | |--index.sass
|--package.json
|--public
| |--application.js
| |--index.html
| |--style.css
|--webpack.common.js
|--webpack.dev.js
|--webpack.prod.js

まず、ディレクトリ構成とそれぞれのファイルを簡単に解説していきます。

_srcは、実際に作業するディレクトリになります。jsとsassのディレクトリにそれぞれファイルを追加して開発を行っていきます。

publicは、jsとsassがコンパイルされて書き出されるディレクトリになります。これを本番用のディレクトリにしても大丈夫です。

webpack.common.jswebpack.dev.jswebpack.prod.jsは、webpackの設定が記述されているファイルです。

package.jsonは、プラグインなどのバージョンを管理するファイルになります。これを利用することで、複数人でも同じ開発環境を簡単に作ることが出来ます。

node.jsをインストール

webpackを使うにはnode.jsが必須になります。

ターミナルでnode -vを実行してみて下さい。nodeのバージョンが返ってきたらインストールされているので、下記の作業は不要です。command not found: nodeのようにエラーが返ってきたらnodeがインストールされていないので、公式サイトからインストールする必要があります。

インストール手順

  1. 公式サイト(https://nodejs.org/ja/)にアクセス
  2. 任意のバージョンを選択してpkgファイルをダウンロードする(左側の推奨番をダウンロードが一番安心です)
  3. ダウンロードしたpkgファイルを実行してnode.jsをインストール
  4. ターミナルでnode -vを実行してバージョンが返ってきたら成功

webpackとプラグインをインストール

ターミナルでpackage.jsonがあるディレクトリに移動します。

その後、下記コマンドを実行して下さい。

npm i

iinstallの略です

 

環境構築はこれで終わりです。

 

ここから先は、さらに詳しく設定ファイルなどの解説をしていきますが、「解説は不要」「早く作業したい」という方のために、どのように開発時にSassやES6をコンパイルするかを先に次のセクションで紹介します。

使い方

開発時

Sassとjs(ES6)を編集して保存したら自動でコンパイルされるようにすることが出来ます。下記コマンドでディレクトリを監視モードにします。

npm run watch

このコマンドを実行したら_srcディレクトリが監視モードになります。試しにsassやjsを編集して保存をしてみて下さい。

publicディレクトリにコンパイルされるはずです。

この監視モードの状態でコンパイルされたファイルは開発用のファイルになり、ソースマップが使える状態です

ソースマップを使うことで、ブラウザのデベロッパーツールで「どのファイルの何行目で書いた処理」なのかが分かるようになります。

以下の画像では、pタグのスタイルがどのsassファイルで書かれたのかがひと目で分かるかと思います。このようにソースマップは開発時のデバッグなどで非常に便利な機能なのです。

本番用ファイルを作成

ソースマップは便利な機能ですが、本番環境には必要ありません。npm run watchでコンパイルしたファイルを本番で使っても問題はありませんが、せっかくwebpackを使うのでより最適なファイルを本番環境で使いましょう。

本番用のファイルを作成するには下記コマンドを実行します。

npm run build

少し時間がかかりますが、処理が終わるとpublicディレクトリのcssからはソースマップの記述が削除、jsはminify化されます。

これで本番環境に最適なファイルを作ることが出来ました。

使い方のまとめ

  • 開発時にはnpm run watch
  • 本番用ファイルを作成するにはnpm run build

サンプルファイルについて

初めに

webpackの設定はwebpack.common.jswebpack.dev.jswebpack.prod.jsの3ファイルに記述しています。

webpack.dev.jsには開発時の設定を記述しています。つまり、npm run watchを実行する際の設定を記述しています。

webpack.prod.jsには本番用の設定を記述しています。つまり、npm run buildを実行する際の設定を記述しています。

そしてwebpack.common.jsには、開発時と本番用どちらにも共通する設定を記述しています。

つまり、基本的な設定はwebpack.common.jsに記述して、開発用と本番用で処理を分けたいときはそれぞれwebpack.dev.jswebpack.prod.jsのファイルに設定を記述します。

また、設定ファイルのコードは下記に記載しています。

webpack.common.js

const path = require('path')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const autoprefixer = require('autoprefixer')

module.exports = {

  entry: {
    'public/application.js': './_src/js/_index.js',
    'public/style.css': './_src/sass/index.sass'
  },

  output: {
    path: __dirname,
    filename: '[name]'
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [{
          loader: 'babel-loader',
          options: {
            presets: 'env'
          }
        }],
        exclude: /node_modules/,
      },
      {
        test: /\.sass$/,
        use: [
          ExtractTextWebpackPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: true,
              minimize: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true,
              plugins: [
                autoprefixer({
                  browsers: 'last 2 versions',
                  grid: true
                })
              ]
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          },
        ]
      }
    ]
  },

  plugins: [
    new ExtractTextWebpackPlugin('[name]'),
  ]

}

webpack.dev.js

const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {

  mode: 'development',

  devtool: 'inline-source-map',

})

webpack.prod.js

const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {

  mode: 'production',

})

解説

まず、webpack.common.jsの中身を解説していきます。

定義

const path = require('path')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const autoprefixer = require('autoprefixer')

webpackのプラグインを使うには、このように最初に定義しなくてはいけません。

上記では、パスを操作するpath、sassなどをファイルとして出力するextract-text-webpack-plugin、ベンダープレフィックスを自動で付与するautoprefixerを記述しています。

module.exports

module.exports = {}
基本的にwebpackの設定はこの中に記述します。

entry

  entry: {
    'public/application.js': './_src/js/_index.js',
    'public/style.css': './_src/sass/index.sass'
  },
entryには、コンパイルさせたいファイルを設定します。これをコンパイル元のファイルをエントリーポイントと呼びます。
'任意の名前': 'コンパイルさせたいファイルのパス'
上記のようなjson形式で値を設定しますが、テンプレでは任意の名前の箇所にコンパイル先のパスを設定しているかと思います。しかし、任意の名前を設定することが出来るので、パスではなく単語などの名前を設定しても特に問題ありません。
テンプレでコンパイル先のパスを設定している理由は次のoutputの欄で説明します。

output

  output: {
    path: __dirname,
    filename: '[name]'
  },
outputには、sassやjsをどこにコンパイルさせるかの設定を記述します。
pathにはコンパイル先のパスを設定して、filenameにはコンパイルされるファイル名を設定します。
例えば、作業用のjsをapp.jsの名前でpublicディレクトリにコンパイルさせたいとしたら、下記のように記述します。
  output: {
    path: __dirname,
    filename: 'public/app.js'
  },
■ __dirnameについて
pathには「コンパイル先のパスを設定する」と先ほど記載しましたが、上記の例では__dirnameを設定しているかと思います。
この__dirnameは変数で、webpackの設定ファイルがある階層の絶対パスが格納されています。
なので、pathには__dirnameを設定して、filenameにはwebpackの設定ファイルを起点としたコンパイル先のパス(ファイル名を含む)を設定してあげればいいのです。
■ [name]について
この[name]は配列で、entryの'任意の名前': 'コンパイルさせたいファイルのパス'任意の名前が格納されています。entryが複数設定されていたら、[name]にも複数の値が格納されています。
outputにはコンパイル先をファイルごとに指定しなければいけません。エントリーポイントが複数ある場合は、その数だけ下記のように記述しなければいけません。
output: {
  path: __dirname,
  filename: {
    'public/style.css',
    'public/app.js'
  }
},
この書き方だとエントリーポイントが増えるたびにoutputも変更しなければいけません。
しかし、テンプレのように、
entry'任意の名前': 'コンパイルさせたいファイルのパス'任意の名前にコンパイル先のパス(ファイル名を含む)を記述して、
outputfilename[name]を与えることでエントリーポイントが増えてもoutputを変更しなくてすむようになります。

module

moduleの中のrulesには、コンパイル対象のファイル(今回はjsとsass)についての設定を記述します。

このrulesの中を編集することはあまりないので、今回は最低限の解説のみにします。

 

jsの設定は下記の通りです。

{
  test: /\.js$/,
  use: [{
    loader: 'babel-loader',
    options: {
      presets: 'env'
    }
  }],
  exclude: /node_modules/,
},
testで全てのjsファイル(正規表現で指定している)をコンパイル対象としています。
optionspresets: 'env'でES6からES5にコンパイルをしています。
全てのjsファイルがコンパイル対象となっているので、設定ファイルがあるnode_modelsもその対象となってしまっています。それを対象から外すために、exclude: /node_modules/の記述をしています。
sassの設定は下記の通りです。
{
  test: /\.sass$/,
  use: [
    ExtractTextWebpackPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        url: false,
        sourceMap: true,
        minimize: true
      }
    },
    {
      loader: 'postcss-loader',
      options: {
        sourceMap: true,
        plugins: [
          autoprefixer({
            browsers: 'last 2 versions',
            grid: true
          })
        ]
      }
    },
    {
      loader: 'sass-loader',
      options: {
        sourceMap: true
      }
    },
  ]
}
loaderの記述が3つあります。ここで注意したいことがあり、loaderは「下に記述した処理から実行される」ということです。
なので、今回の場合は「sass-loader」→「postcss-loader」→「css-loader」の順で処理が実行されます。
ExtractTextWebpackPluginは、sassをコンパイルした後に「cssファイル」として出力するためのプラグインです。このプラグインを使わずにsassをコンパイルすると、「cssファイル」は出力されずに、「jsファイル」の中にcssが書き出されます。

mode

webpack.dev.jsにはmode: 'development'webpack.prod.jsにはmode: 'production'の記述があると思います。

これは、コンパイルするときに開発用、本番用どちらでコンパイルするかの設定になります。
この設定によりコンパイル時のコードが変わります。

devtool

ソースマップをコンパイル時に作成するかどうかを設定することが出来ます。

何個かオプションがありますが、基本的に以下3パターンだけ覚えていれば問題ないかと思います。

  • devtool: 'inline-source-map':ソースマップの記述がファイル内に追加される
  • devtool: 'source-map':ソースマップが新規ファイルとして出力される
  • 何も記述しない:ソースマップが作成されない

なので、webpack.dev.jsにはソースマップが作成されるような設定をして、webpack.prod.jsにはソースマップが作成されないように何も記述はしていません。

開発用と本番用で処理を分ける

先程、webpack.common.jsには共通の処理内容を、webpack.dev.jswebpack.prod.jsにはそれぞれ開発、本番で分けたい処理内容を記述するとお伝えしました。
開発、本番で処理を分けてwebpackを実行するには、webpack.○○.jsの設定ファイルとpackge.jsonのファイルの編集をします。
まず、webpack.dev.jswebpack.prod.jswebpack.common.jsの内容を読み込ませるためにwebpack-mergeを使います。
webpack-mergeを使うためには、webpack.dev.jswebpack.prod.jsの最初で下記のように宣言します。
const merge = require('webpack-merge')

そして、読み込ませたいファイルを記述します。

const common = require('./webpack.common.js')

最後に、分けたい処理内容を下記のように記述をします。

module.exports = merge(common, {
  // 分けたい処理内容
})

 

次に、packge.jsonscriptに下記のように記述します。

"scripts": {
  "watch": "webpack --config webpack.dev.js",
  "build": "webpack --config webpack.prod.js"
},

webpackを実行する時に、webpack.dev.jsの設定で実行したい場合

webpack --config webpack.dev.js

webpackを実行する時に、webpack.prod.jsの設定で実行したい場合

webpack --config webpack.prod.js

上記のように--configの後に実行したいファイル名を与えることで、そのファイルの設定でwebpackを実行することが出来ます。

※ダウンロードしたファイルのscriptswatchには--watchが記述されていますが、これは開発時にファイルを監視するために記述をしており、処理を分けるということには一切関係ありません。

しかし、毎回このように入力するのは手間なので、scriptsに実行したいコマンドを登録しておきます。

"登録名": "実行したいコマンド"

このようにscriptsに設定をしたら、npmコマンドで登録したコマンドを実行することが出来ます。実行コマンドは下記の通りです。

npm run 登録名

上記コマンドを実行したら"登録名": "実行したいコマンド"の「実行したいコマンド」が実行されます。

まとめ

webpackは非常に便利な機能ですが、初めて使う方からしてみたら最初は全く理解できないかと思います。

私自身これまでGulpを使っており、そこからwebpackを使ってみようとなって色々カスタマイズしようと思ったのですが、最初は全く理解出来ず、色々調べながら少しずつ理解出来るようになりました。

その時に調べて覚えた内容を今回の記事にまとめたつもりなので、少しでもwebpackを使ったりカスタマイズする際に皆様のお役に立てれば幸いです。

この記事で基本的な書き方を理解出来たら、プラグインを追加してみたり、今回はあえて紹介しなかったdev-serverを使ってみたりなど色々なことを試してみてはいかがでしょうか。

 

 

 

 

 

シェアする
フォローする
Web-Guided - web業界で働く方を少しだけ手助けするメディア