ReactでのWebpackの設定の仕方と解説【Babel,ESlint,Sass(CSS)】

ReactでのWebpackの設定の仕方と解説【Babel,ESlint,Sass(CSS)】

webpackを使っていて、バージョンを上げるとハマり、色々と設定を触ったりインストールのしなおしをしたので、ついでに最初からインストールし設定していく手順を残しておきます。

 

 

 

環境は以下になります

$node -v
v8.12.0

 

使用するプロジェクト内で

$npm init -y

をすることでパッケージファイル管理のpackage.jsonができる。

package.jsonを編集して以下のように書き加えます。

  "name": "(プロジェクトフォルダの名前が入る)",
  "version": "1.0.0",
  "description": "", // ←ここに説明を書き加える
  "main": "index.js",
  "scripts": {  // script内を以下のようにする。
    "start": "webpack-dev-server --mode production",
    "webpack": "webpack -d",
  },
 ...(以下省略)

 

次にnpmパッケージをどんどんインストールしていきます。

今回はReactを使うのでReactを入れています。

$npm i react react-dom
$npm i webpack webpack-dev-server
$npm i eslint eslint-loader eslint-plugin-react
$npm i css-loader style-loader babel-loader
$npm i sass-loader node-sass

(※ i は install の略)

npm オプションの詳しいことは公式のここにあります。(https://docs.npmjs.com/misc/config)

 

・1行目はReactに関するパッケージ

・2行目はwebpackとローカルでサーバをたてるためのdev-server

・3行目はESlintに関するパッケージ

・4行目はcssに関するパッケージとBabelのパッケージ

・5行目でSassを読み込む(コンパイル)に必要なパッケージ

 

を入れています。

 

インストールしたパッケージはpackage.jsonの、

dependencesに追加されています。確認してみると

 ...(省略) 
 "dependencies": {
    "babel-cli": "^6.26.0",
    "babel-loader": "^8.0.4",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^2.1.0",
    "eslint": "^5.10.0",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-react": "^7.11.1",
    "node-sass": "^4.11.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.28.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.12"
  }
}

こんな感じになっていると思います。

 

それからpackage.jsonと同じ階層に以下のファイル(ディレクトリ)を新しく作成していきます。

.babelrc

.eslintrc.json

webpack.config.js

public/index.html

src/index.js

src/index.scss

 

 

順にファイルの中身を書いていきます。

.babelrc

{ 
 "presets": ["@babel/preset-env", "@babel/preset-react"]
  // babelには多くのプラグインがあるが、プリセットを使う事で誰でも簡単に使えるようになっている。ここではES6とJSXを含むReact対応のプリセットを使う設定をしている。 
}

 

.eslintrc.json

{
  "env": { // ESLintが使用される環境の設定
    "browser": true, // JSをブラウザで動かす
    "es6": true      // ES&を使う
  },
  "parserOptions": { // パーサーの設定
    "sourceType": "module", // 
    "ecmaFeatures": {
        "experimentalObjectRestSpread": true,
        "jsx": true
    }
  },
  "plugins": ["react"], // React用のプラグインを使う
  "extends": ["eslint:recommended", "plugin:react/recommended"], // ルールのデフォルトを設定(ESlintのお勧めを設定している)
  "rules": {
    "no-console": "off" // console.logを使えるようにする
  }
}

 

webpack.config.js

// [定数] webpack の出力モードを指定します
// 'production' か 'development' を指定
const MODE = 'development';


// ソースマップの利用有無(productionのときはソースマップを利用しない)
const enabledSourceMap = (MODE === 'development');

module.exports = [{
      // モード値を production に設定すると最適化された状態で、
      // development に設定するとソースマップ有効でJSファイルが出力される
      // mode: MODE,

      entry: { // アプリ起動時に動作するJSソースファイルを指定する
        app: "./src/index.js"
      },
      output: { // 出力されるファイル名、パス名を指定する
        path: __dirname + '/public/js', //絶対パスで指定しないといけない
        filename: "[name].js" //[name]とするとentryのキーが使われる(この場合app.jsという名前になる)
      },
      devServer: { // 開発用サーバの設定
        contentBase: __dirname + '/public', // 公開するルートディレクトリ(index.htmlがある場所)
        port: 8080, // ポート番号
        publicPath: '/js/' // webpackが出力するJSのあるディレクトリー
      },
      devtool: "#inline-source-map", // 出力されるファイルではなく、元のソースコードを使ってデバッグできるようにmapファイルを作る設定
      module: { // ファイルの種類ごとにloaderを指定するルール決め
        rules: [{
          test: /\.js$/, // 対象となるファイルの拡張子を決める(jsファイルの時)
          enforce: "pre", 
          exclude: /node_modules/, // npmでインストールされたjsは対象外とする
          loader: "eslint-loader" // eslint-loaderを実行する 
        }, {
          test: /\.css$/, // cssファイルの時
          loader: ["style-loader","css-loader"] // css-loaderとstyle-loaderを実行する
        }, {
          test: /\.js$/, // jsファイルの時
          exclude: /node_modules/, 
          loader: 'babel-loader' // babel-loaderを実行する
        }, {
          test: /\.scss/, // scssファイルの時
          use: [
            // linkタグに出力する機能
            'style-loader', // style-loaderの実行
            // CSSをバンドルするための機能
            {
              loader: 'css-loader', // css-loaderの実行
              options: {
                // オプションでCSS内のurl()メソッドの取り込みを禁止する
                url: false,
                // ソースマップの利用有無
                sourceMap: enabledSourceMap,

                // 0 => no loaders (default);
                // 1 => postcss-loader;
                // 2 => postcss-loader, sass-loader
                importLoaders: 2
              },
            },
            {
              loader: 'sass-loader', // sass-loaderの実行
              options: {
                // ソースマップの利用有無
                sourceMap: enabledSourceMap,
              }
            }
          ],
        },
      ]},
      resolve: {
        extensions: ['.js', '.jsx'],
      }
}]

Webpackはソースファイルを元にloaderを実行してBabelの変換などがされたjsファイルを出力します。これが利用されることになるので、その変換の過程の設定をこのファイルでしています。(主に入力するソースをentry, 出力するファイルをoutputで指定、loaderによる変換をmoduleのruleで設定しています)

 

 

public/index.html

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, intial-scale=1, shrink-to-fit=no">
   <meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1" />
   <link rel="stylesheet" href="style.css">
   <title>React App</title>
</head>
<body>
  <div id="contents"></div>
  <script type="text/javascript" src="js/app.js" charset="utf-8"></script>
</body>
</html>

 

 

src/index.js

import React from 'react'
import ReactDOM from 'react-dom'
// import文を使ってSassファイルを読み込む。
import './main.scss';

ReactDOM.render(
  <h1>サンプル</h1>,
  document.getElementById('contents')
);

 

src/index.scss

$red: #FF3333;
h1 {
  color: $red;
}

 

とりあえず意味は置いておき、これで

$npm start

をしてエラーがでなかったらlocalhost:8080にアクセスすれば

問題なく次のように表示されていると思います。

これでReactとSassを使う環境ができました!

 

 

もしも次のようなBabelのエラーが出た場合は

    ERROR in ./src/index.js
    Module build failed (from ./node_modules/babel-loader/lib/index.js):
    Error: Plugin/Preset files are not allowed to export objects, only functions. 

以下の二つのコマンドでパッケージを追加して再度やってみると上手くいくと思います。(バージョンの関係なのだと思いますが、この辺はあまりよく分かっていません…)

npm i @babel/preset-env
npm i @babel/preset-react

 

 

では順にReactを除くパッケージを解説していきます。

 

 

まずBabel(babelパッケージ)ですが、これはES6記法をES5に変換してくれるツールです。これでES6で書いても、全ブラウザで完全に対応できるようになります。ES6を書くなら必須のツールです。

 

次にESlintです。これでJSの構文チェックを行ってくれます。実際にブラウザに反映させる前に間違いがあればエラーを出してチェックしてくれるので、開発効率を高めてくれます。

 

次にCSS関連(sass-loader, css-loader, style-loader)です。

役割としては

・sass-loader: scssファイルをコンパイルしてcssに変換

・css-loader: cssファイルをJSで扱えるようにする。

・style-loader: cssのスタイルを適用してくれる。

というものになります。

 

素のJSではCSSは読み込めませんが、 css-loaderを使う事で、JSでCSSを扱うことができるようになります。index.jsの

import './main.scss';

これでscssを取り込んでいますが、これでscssデータを取得できるのはまずsass-loaderでcssに変換した後にcss-loaderによってJSで扱えるようにしているから、となります。

 

ただ、 css-loaderだけではそのscss, cssファイルを読み込めても、スタイルを反映させることまではできません。そのため、実際に読み込んだscss, cssのスタイルを反映してくれるのがstyle-loaderになります。つまりsass-loader, css-loaderとstyle-loaderは必ずセットで使う事になります。

 

ここでもう一度webpack.config.jsファイルのmoduleのscssファイルの設定の部分を見てほしいのですが、今言ったloaderの実行順と、ファイルに書かれているloaderの順が逆になっていると思います。これはmoduleのloaderの実行順が後ろからになっているからですので、気を付けておきたいところです。

 

 

ちなみに、webpack.config.jsのソースの下でも少し書きましたが、npm startでサーバーを立ち上げて実行する際には、実行時に各ソースファイルからloaderを実行して新たに出力されたファイルが読み込まれてブラウザに反映されています。ちなみにこのソースファイルから変換を施して新たにJSファイルを出力する一連の流れをバンドルと言います。

 

今回だとバンドルによってpublic/js/app.jsファイルが作成されています。

 

バンドルされているため、scssファイルをコンパイルしたcssファイルを見たいと思ってもこのままでは見れません。これを見るにはcssファイルだけを別に出力してくれるnpmのパッケージ(mini-css-extract-plugin)を入れないといけないのですが、これは今回の内容の範囲外なので割愛します。

これに関しては以下のところが参考になるかもしれません。

【webpack 4】環境構築からJSとCSSを別出力まで(備忘録)

 

 

それから

resolve: {
 extensions: ['.js', '.jsx'],
}

という部分ですが、ここは実際にReactを書いていく上で別のjs/jsxファイルをインポートするとき、例えばcomponents/Hoge.jsxファイルを読み込むときは、以下のようなコードを書くのですが、

import Hoge from 'components/Hoge'

上のresolveがないとエラーが出てしまいます。拡張子を省いている場合ファイル解決ができません。このファイル解決のためにresolveを設定しています。

 

 

最後にgit管理する場合, とりあえずは.gitignoreの設定は以下のようにしておくと良さそうです。

node_mosules/
public/**
!public/index.html

node_modulesは npm installですぐに生成できるものなので管理する必要はなく、public/はwebpackで出力されるファイルなので、実行すれば良いだけなのでこれも必要はないという感じです。

 

 

まとめていて、webpack周りの良い勉強にもなりました。

理解して、快適にWebpack, Reactを使っていきたいですね。

 

 

 

※コンパイルは成功しているけど、次のようなWarningが出ている場合

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (250 kB).
This can impact web performance.

WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (250 kB). This can impact web performance.


WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

 

解決できるならしたいですがファイルサイズのデフォルト設定値が厳しく難しかったりするので、警告を単に消すだけでもいいと思います。

 

 

消し方ですが、

 

webpack.config.jsファイルの、resolveの下に次の一文を追加します。

resolve: {
  extensions: ['.js', '.jsx'],
},
performance: { hints: false } // 追加

これで警告が消えます。

 

 

 

参考リンク

webpackでCSSやSASSを使う

webpackの設定をdevとproductionで分ける一例

最新版で学ぶwebpack 4入門 – スタイルシート(CSSやSass)を取り込む方法

パフォーマンス警告の対処法