読もうと思った理由

以前Webpackを少し触ってみたがJavaScriptをバンドルする部分以外の利点や使い方が理解できておらず、Webpackを用いた開発環境でどんなことができるのか、何が便利なのかを実際に体験したいと考えており、目次に記載されているツールやモジュールをみてちょうどいいと感じ他のでやってみることにしまた。

こんな人におすすめ

色々なツールやモジュールを広く浅く紹介されているので、Webpackを用いたフロントエンド開発環境がどのようなものなのかを実際に環境構築をしながら知りたい人におすすめです。
それぞれのツールの応用や細かい設定方法を解説している訳ではないので、すでに紹介されているようなツールを使って開発環境を作れる人がより深い理解をするという目的には適していません。

紹介されている主なライブラリ・ツールなど

NODE_ENVはツールではないですが、キーワードとして記載しています。

  • yarn
  • EditiorConfig
  • Babel
  • Webpack
  • webpack-dev-server
  • html-webpack-plugin
  • ESLint
  • eslint-loader
  • Prettier
  • Flow
  • React
  • css-loader
  • CSSModules
  • mini-css-extract-plugin
  • StyleLint
  • PostCSS
  • postcss-scss
  • Autoprefixer
  • postcss-custom-properties
  • postcss-nesting
  • CSSwring
  • Jest
  • react-test-renderer
  • identity-obj-proxy
  • webpack-merge
  • NODE_ENV

紹介されている主なライブラリ・ツールなどの概要

yarn

npm互換のパッケージマネージャー。
書籍内ではnpmよりyarnがオススメされてました。
yarn.lockを利用してどの端末でも同じバージョンのパッケージをインストールできるから環境が揃えられるのが理由のようです。
npmでもnpm ciコマンドができたのでpackage-lock.jsonをみて再現できるからどちらでもいい気がします。
あなたがnpm installをしてはいけない時

EditorConfig

インデント幅とか改行コードとか最終行に改行を入れるかとかを揃えてくれます。
主要なIDEやエディターはほぼ対応しているので入れておくと余分なdiffの発生や確認コストを減らせますね。
設定はプロジェクトルートに.editorconfigを作成して記述します。
拡張子とかディレクトリ単位で設定を変えることも可能です。
EditorConfig公式

Babel

JavaScriptのトランスパイラです。
ES2015以降のコードを解釈できないブラウザでも解釈できるようにコードを変換してくれます。
単純な構文の変更だけでなく、最適化もしてくれるらしいです!すごい!
設定はプロジェクトルートに.babelrcを作成してどのブラウザまでサポートするかを記述します。
シェアとかバージョンとか最新から何バージョン前とかの指定ができます。

webpack

複数のJavaScriptファイルを1つにまとめたり、開発用のサーバーを立ち上げたりできます。
v4からCLIを使うにはwebpack-cliモジュールも別途インストールする必要があります。
設定はプロジェクトルートにwebpack.config.jsを作成し、Javascriptにはbabel、CSSにはPostCSSを適用させようとか、入出力の設定とか色々できます。
webpackではxxx-loaderのという名前のモジュールで変換が行われます。

webpack-dev-server

webpackが提供している開発サーバーのモジュールです。
設定はwebpack.config.jsに記述します。
どのディレクトリをベースにして表示するのか、ポート、ファイルの更新を検知して自動でブラウザのリロードさせるホットリロードを使うのかといった設定ができます。

html-webpack-plugin

開発サーバー用にHTMLを自動出力するプラグインです。

ESLint

JavaScriptの静的構文チェックツールです。
文法的な間違いや,(カンマ)のつけ忘れなどのミスをチェックしてくれます。
設定はプロジェクトルートに.eslintrcを作成して記述します。
公開されているルールセットを拡張する形で記述することもできます。
書籍内ではairbnbのルールを元にした設定方法が紹介されてました。

eslint-loader

ESLintをビルドごとに自動で実行できるようにするモジュールです。
いちいちコマンドを打たなくていいので便利です。

Prettier

コードフォーマッタです。
設定はプロジェクトルートに.prettierrcを作成して記述します。
設定できる内容(公式ドキュメント)
インデントサイズやインデントスタイルはEditorConginでも設定しますが、EditorConfigはコードを書いているとき、Prettierはコミット時に適用するといったように使い分けたり、併用するパターンなどがあるようです。
チームメンバーにコーディング規約を守らせる。絶対に。
Prettierの導入方法フロントエンド開発で必須のコード整形ツール

Flow

静的型チェックツールです。
JavaScriptに対して型のサポートとチェックをしてくれます。
Reactと同じFacebook製なのでReactと相性がいいらしいです。
設定はプロジェクトルートに.flowconfigを作成して記述します。
設定できる内容(公式ドキュメント)
JavaScriptのファイル内に@flowのコメントを記述することでFlowの使用を宣言できます。
Flowでの型定義はJavaScriptの構文とは異なるので@babel/preset-flowでトランスパイル時に型定義を消す必要があります。
また、ESLintのルールセットとコンフリクトすることがあるためESLintと併用するときはFlow用のESLintプラグインであるeslint-plugin-flowtypeも必要になります。

React

View部分を担当するJavaScriptのライブラリです。
Reactを使用するには、reactreact-domの2つのモジュールを使います。
また、Babelでトランスパイルするには@babel/preset-reactモジュールが必要になります。

css-loaderとmini-css-extract-plugin

css-loaderJavaScript上でCSSをインポートできるようにします。
mini-css-extract-pluginCSSファイルを作成します。デフォルトではmain.cssという名前で生成されますが、webpackの設定ファイル内でプラグイン読み込み時にfilenameを設定することで任意の名前に変えられます。

StyleLint

CSS向けのLintツールです。
設定はプロジェクトルートに.styleintctを作成して記述します。
ESLintと同じように公開されているルールセットを拡張する形で設定することが可能です。
もちろん独自のルールセットを作成することも可能です。
設定できる内容(公式ドキュメント)

PostCSS

AltCSSのひとつですが、PostCSS自体はただのパーサであるため、単体では動作しません。
プラグインを入れることで様々な機能が使えるようになります。
WebpackでPstCSSを使用するにはpostcss-loaderを読み込む必要があります。
設定はプロジェクトルートにpostcss.config.jsを作成して記述します。

PostCssのプラグイン

  • SassのSCSS記法を使えるようにするpostcss-scss
  • ベンダープレフィックスを自動でつけられるautopirefixer
  • CSS Custom Propertiesの仕様を解釈して、使用できないブラウザ用に変換するpostcss-custom-properties
  • ネスト記法を使えるようにするpostcss-nesting(類似としてpostcss-nested
  • CSSをminifyするCSSwring

CSSModules

自動的にクラス名を割り振ることができます。
異なるファイルで同じクラス名を利用したとしても、完全に異なるクラス名が生成され、命名規則やスタイル汚染での悩みが減らせます。
css-loaderがCSSModulesの機能を持っているためwebpakckの設定で機能を有効化して使用できます。
類似のアプローチとしてCSS in JSやStyledComponentsモジュールなどがあります。

Jest

テストツールです。
JavaScriptのコード、Reactコンポーネントにおけるユニットテストなどができます。
コンポーネントのテストはスナップショットテストというテストが紹介されており、コンポーネントをJSONに変換し変更前後で比較することで意図してない変更が発生していないかを確認します。
スナップショットテストを行うためにはreact-test-renderer、CSSModulesを使っている場合にはidentity-obj-proxyも必要となります。

webpack-merge

Webpackの設定ファイルを分割するのに使用します。
Webpackには開発に使用するdevelopとproductionというmodeがあり、開発時のみ使用するモジュールもどちらでも使用するモジュールも出てきます。
設定ファイルを共通用、開発用、製品用と行った具合に用意して開発用から共通用を読み込むといった使い方ができます。

NODE_ENV

環境変数です。開発環境であるかどうかなどを設定して引き渡します
これによりプラグインを開発環境だけで動作させるなどということが柔軟にできるようになります。

書籍に記載されている内容と変えたこと

基本的に書籍に記載されている内容通りに設定などを行いましたが、一部変更が必要な部分やよりよさそうな方法があったので変更した部分を紹介します。

ブラウザの指定方法を外部ファイル化

書籍ではBabelやAutoprefixerの対象とするブラウザの設定をそれぞれの設定ファイルに記述してましたが、途中で下記の警告が出るようになりました。

  Replace Autoprefixer browsers option to Browserslist config.
  Use browserslist key in package.json or .browserslistrc file.

  Using browsers option cause some error. Browserslist config 
  can be used for Babel, Autoprefixer, postcss-normalize and other tools.

  If you really need to use option, rename it to overrideBrowserslist.

  Learn more at:
  
  https://twitter.com/browserslist

そのため、対象とするブラウザの設定は.browserslistrcを作成し、そこで一元管理するようにしました。
実際の案件でもJavaScriptとCSSで対応するブラウザが異なるといったことは考えにくく、管理コストの観点からも一元管理するのがいいと思います。
上記のメッセージもある通りpakage.jsonに記載する方法もありますが.browserslistrcという独立ファイルの方が可読性が高いと感じました。
ブラウザ指定の記述方法はGithub上に記載があります。

CSSModulesの指定方法が変わっていた

CSSModulesは自動で振るクラス名の形式を設定できますが、書籍内では下記の記載で紹介されていました。(localIdentName部分でクラス名の形式を指定しています。)

module.exportd = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          MiniCSSExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              modules; true,
              importLoaders; 1,
              localIdentName; '[name]_[local]--[hash:base64:5]'
            }
          },
          'postcss-loader'
        ]
      }
    ]
  },
  ...
}

しかしながら、上記の記述ではエラーが発生してしまいました。

ERROR in ./src/css/index.css (./node_modules/css-loader/dist/cjs.js??ref--6-1!./node_modules/postcss-loader/src!./src/css/index.css)
Module build failed (from ./node_modules/css-loader/dist/cjs.js):
ValidationError: Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
 - options has an unknown property 'localIdentName'. These properties are valid:
   object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }
    at validate (/Users/xxxxx/Documents/Study/nekomimi-frontend/node_modules/css-loader/node_modules/schema-utils/dist/validate.js:50:11)
    at Object.loader (/Users/xxxxx/Documents/Study/nekomimi-frontend/node_modules/css-loader/dist/index.js:34:28)

localIdentNameというプロパティはないと出ています。
css-loaderのドキュメントを確認したところmodulues内に記述されていました。

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        loader: 'css-loader',
        options: {
          modules: {
            localIdentName: '[path][name]__[local]--[hash:base64:5]',
          },
        },
      },
    ],
  },
};

こちらに合わせる形で修正をしたところエラーもなく、想定通りにクラス名を振られるようになりました。

上記の変更内容を含め、書籍を読み進めながら記載したコードはGithubに公開しています。

また、著者によるサポート・サンプルリポジトリも公開されています。

ネコミミでもわかるフロントエンド開発環境構築を終えて

WebpackでJavaScriptのバンドル以外に何ができるのだろうかという状態だった私ですが、Webpackで使える様々なツールやモジュールを幅広く知ることができました。また、コードの体裁を揃えるためのツールについて実際に手を動かしながら理解を深めることができました。
案件に合わせてモジュール選定、適切な設定ができるようにはまだまだ深掘りと実践必要だとは思いますが、Webpack色々できて面白い!という気持ちになれました。内容としても難しくないのでこれからモダンなフロントエンドの開発環境を作って行きたいという方にはおすすめです。

この記事を書いた人

Yuki Tomioka

元焼肉店店長からゼロシード株式会社の1人目のwebエンジニアとなる。テクニカルディレクターとして勤務し、WordPressのカスタマイズやアクセス解析や広告運用などに従事。現在は事業会社のフロントエンドエンジニアとして勤務。
タイムチケットで相談も受け付けてます。