Webpack 5設定の基礎

Webpack 5 設定の基礎を下記動画を参考にして学びました。

Windows環境のせいなのか、環境変数の扱いについてはちょっと悩み、動画とは違うやり方になっています。

設定なしで実行可能

webpack は特に設定しなくとも複数の JavaScript をまとめてくれます。いわゆるゼロコンフィグというやつですね。

  • WindowsGit Bash にて次のコマンドを実行します。
$ mkdir webpack-setup
$ cd webpack-setup
$ npm init -y
$ touch index.js
$ touch index.html

これで、VSCodeが開きます。

  • index.html! を入力して2行編集、1行追加。
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Webpackのテスト</title>
</head>
<body>
  <script src="./index.js"></script>
</body>
</html>
  • index.js を編集。
console.log('index.jsから実行');

これをブラウザで表示し、コンソールを見れば上記が表示されます。

  • index.js を編集。
import { greeting } from './greeting';
import { present } from './present';

console.log('index.jsから実行');
console.log(greeting);
console.log(present);
  • greeting.js を追加。
export const greeting = 'どうもこんばんは。ピータンです。';
  • present.js を追加。
export const present= '東京都いなか市在住の56歳です。';

これは次のエラーとなることがブラウザで確認できます。

Uncaught SyntaxError: Cannot use import statement outside a module

  • webpack 及び webpack cliをインストールします。
$ npm i -D webpack webpack-cli
  • 試しに以下のコマンドを打つと色々エラーや警告が出ます。
$ npx webpack

:
ERROR in main
Module not found: Error: Can't resolve './src' in 'C:\\
:

  • ここで、src フォルダを作って、3つの jsファイルを移動します。 もう一回以下のコマンドを実行すると、警告は出るがエラーは消えていて dist フォルダができていて、main.js ができていることがわかります。
$ npx webpack
  • dist\main.js をフォーマット(Shift + Alt + F)すると次の内容です。
(() => {
  'use strict';
  console.log('index.jsから実行'),
    console.log('どうもこんばんは。ピータンです。'),
    console.log('東京都いなか市在住の56歳です。');
})();
  • index.htmldist フォルダに移動し、次のように変更します。
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Webpackのテスト</title>
</head>
<body>
  <script src="./main.js"></script>
</body>
</html>
  • dist\index.html をブラウザで開きコンソールを見ると、期待通り動いていることがわかります。 ここまでsrcフォルダを作っただけで、特に何も設定していないことに注目です。
Consoleでの実行結果の確認

package.jsonでのスクリプトの設定とwebpackのスマートなバンドル

ここでは、webpack.config.js を使って npm run buildWebpackを使用するようにすることと、webpack が単にモジュールを寄せ集めているだけでないことを示します。

  • src\introduce.js を追加します。
import { greeting } from './greeting';
import { present } from './present';

function introduce() {
  console.log(greeting);
  console.log(present);
}

export default introduce;
  • src\index.js を次のように変更します。
import introduce from './introduce';

console.log('index.jsから実行');
introduce();
  • package.jsonbuild スクリプトを追加します。
"scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "build": "webpack"
  },
  • 次のコマンドを実行します。
$ npm run build
  • ブラウザのコンソールを確認すると先程と結果は同じです。しかし、驚くべきことに dist\main.js の内容も先程と同じです。
(() => {
  'use strict';
  console.log('index.jsから実行'),
    console.log('どうもこんばんは。ピータンです。'),
    console.log('東京都いなか市在住の56歳です。');
})();

Babelによるトランスパイリング

ここでは古いブラウザが解釈できる JavaScript への変換をおこないます。@babel/preset-env は最新の JavaScript を余計な手間を使うことなくどのブラウザで使用可能にします。

  • src\index.js を変更します。
import introduce from './introduce';

console.log('index.jsから実行');
introduce();

const info = { age: 56, sports: 'VRボクシング' };
const newInfo = { ...info, address: '東京都いなか市' };
console.table(newInfo);
  • npm run build を実行し dist\main.js をフォーマットして確認すると次の状況です。
(() => {
  'use strict';
  console.log('index.jsから実行'),
    console.log('どうもこんばんは。ピータンです。'),
    console.log('東京都いなか市在住の56歳です。');
  console.table({ age: 56, sports: 'VRボクシング', address: '東京都いなか市' });
})();

なおブラウザのコンソールログへの実行結果は次のとおりです。

コンソールでの実行結果の確認
  • 次のコマンドで Babel 等をインストールします。
$ npm i @babel/core @babel/preset-env babel-loader
  • webpack.config.js ファイルをルートフォルダに作成します。
module.exports = {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\\.js$/,
        exclude: /node_modules/,
        use: {
          // 追加設定は .babelrc
          loader: 'babel-loader',
        },
      },
    ],
  },
};
  • .babelrc ファイルをルートフォルダに作成します。
{
  "presets":["@babel/preset-env"]
}
  • ここで改めて、npm run build を実行し dist\main.js をフォーマットして確認すると次のように、古いブラウザでも動作するコードになっています。
(() => {
  'use strict';
  function e(e, r) {
    var t = Object.keys(e);
    if (Object.getOwnPropertySymbols) {
      var o = Object.getOwnPropertySymbols(e);
      r &&
        (o = o.filter(function (r) {
          return Object.getOwnPropertyDescriptor(e, r).enumerable;
        })),
        t.push.apply(t, o);
    }
    return t;
  }
  function r(r) {
    for (var o = 1; o < arguments.length; o++) {
      var n = null != arguments[o] ? arguments[o] : {};
      o % 2
        ? e(Object(n), !0).forEach(function (e) {
            t(r, e, n[e]);
          })
        : Object.getOwnPropertyDescriptors
        ? Object.defineProperties(r, Object.getOwnPropertyDescriptors(n))
        : e(Object(n)).forEach(function (e) {
            Object.defineProperty(r, e, Object.getOwnPropertyDescriptor(n, e));
          });
    }
    return r;
  }
  function t(e, r, t) {
    return (
      r in e
        ? Object.defineProperty(e, r, {
            value: t,
            enumerable: !0,
            configurable: !0,
            writable: !0,
          })
        : (e[r] = t),
      e
    );
  }
  console.log('index.jsから実行'),
    console.log('どうもこんばんは。ピータンです。'),
    console.log('東京都いなか市在住の56歳です。');
  var o = r(
    r({}, { age: 56, sports: 'VRボクシング' }),
    {},
    { address: '東京都いなか市' }
  );
  console.table(o);
})();
  • webpack.confi.gjsmode: ‘production‘というのを設定することによって、以下の警告が消えました。設定しなくても設定したのと同じ動作はしていました。

モード

mode未指定についての警告
  • ここで、mode: ‘development’ にするとフォーマット後の dist\main.js が52行から116行と増大します。

ソースマップ

  • ブラウザの DevTools のコンソールで行番号をクリックすると、 dist フォルダにあるトランスパイルされたコードが表示されます。
出力元のソースコード
  • これをトランスパイルする前のコードで表示できるとデバッグが楽になります。これをおこなうには、以下の1行を webpackconfig.js に追加します。
module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\\.js$/,
        exclude: /node_modules/,
        use: {
          // 追加設定は .babelrc
          loader: 'babel-loader',
        },
      },
    ],
  },                       // カンマ追加する
  devtool: 'source-map',   // ★ここ
};

watch モード

  • package.jsonbuild スクリプトに —watch を追加して、npm run build を実行した場合、ファイルを監視し続けて、変更があると、dist フォルダの変換結果をリアルタイムに更新してくれます。
"scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "build": "webpack --watch"
  },

dev-server

  • VSCode の拡張機能に Live Server というのがあり、それを使うのもよいのですが、Webpack には、ライブリロードにより開発を迅速化するための webpack-dev-server (通称:dev-server)というものがあります。
  • これは開発専用であり、次でインストールします。
$ npm i -D webpack-dev-server
  • webpackconfig.js に以下を追加します。
devServer: {
    contentBase: './dist',
  },
  • package.jsonstart スクリプトを追加します。
"scripts": {
    "start": "webpack serve",
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "build": "webpack --watch"
  },
  • これで npm start を実行すると dev-server が起動します。
dev-server

出力先の変更

  • 現在は、バンドルされたファイルが dist\main.js に出力されていますが、これを変更したい場合は webpack.config.js を次のようにします。
const path = require('path');

module.exports = {
:
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'public')
  },

:

  devServer: {
    contentBase: './public',
  },
};
  • この例では出力先を public/bundle.js に変更しています。

modeの切り替え

現在、webpackconfig.jsmode: ‘development’, などと設定されていますが、デバッグ中と、リリース時で、いちいちここを手で書き換えるのは不便です。そのようにしない方法を説明します。

  • package.json を次のように書き換えます。
"scripts": {
    "start": "webpack serve",
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "build": "webpack --watch"
  },

↓

"scripts": {
    "start": "webpack serve",
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "build": "set NODE_ENV=production&&giwebpack",
    "build-dev": "webpack --watch"
  },
  • webpackconfig.js を次に変更します。
module.exports = {
  mode: 'development',

↓

const mode =
  process.env.NODE_ENV === 'production' ? 'production' : 'development';

module.exports = {
  mode: mode,

出力先の変更はしていないものをGitHubに格納しました。