WebPack・複数のJavaScriptモジュールを結合してみた

久々の投稿です、フロントエンド開発を日々業務で行ってるんですが、既存のシステムですと当然WebPackをはじめとした環境構築もできているので、一から自分がセットアップする機会はありませんし、設定をいじる機会もそうありません。ですがフロントエンドエンジニアとしてWebPackくらい、一から導入した事がないのはまずいと思ったのが今回のきっかけです。

今回はWebPackの数ある機能で代表的なビルド機能を試してみようと思います。WebPackのビルド機能でできる事は、`複数のモジュールをひとつにまとめた「Bundleファイル」に書き出す`という事です。

####そもそも複数のモジュールをひとつにまとめる理由は何なのか？

我々エンジニアは開発時にJavaScriptファイル（モジュール）を機能ごとに細かく分割します。その方が、可読性、メンテナンス性も高いからですね。しかし、JSの仕様を決めるEcmaScriptでは外部モジュールのimport, export, requireの仕様、ルールはあるけど、JSという言語自体にはまだそれらの文法が実装されてない。（Node.jsとか、他の言語は複数ファイルを結合する機能がある）

また、我々が普段使うブラウザも同様に、`複数のJavaScriptファイル（モジュール）を結合する機能（import, export）`がありません。

なので複数のモジュールを一つにバンドル（まとめて）して、ブラウザが読める様にしてあげようという背景がありました。

→それをやってくれるのが`WebPack`というモジュールバンドルツールなのです！


###WebPackについて：
JavaScriptのモジュールの依存関係を解決し、複数のモジュールを１つのJSファイルに結合して出力してくれる。起点となるモジュールが依存するモジュールを次々に辿り、適切な順序になる様に結合してくれる。JSファイルだけでなく、画像、CSSにも対応していて、各種プラグインで拡張して様々な変換が可能。
 —JavaScript Primerから引用


#####前段はこれくらいで、実際にやっていきたいと思います。

今回は、以下３つのファイルにモジュールを分割しました。

```
js/
  ├ Model.js データを管理
  ├ View.js Viewを管理
  └ App.js
index.html
```
Model.js、View.js２つのモジュールをApp.jsでimportして使います（つまり、App.jsが起点となるエントリーポイント）それをindex.htmlで読み込んで使うという具合です。

実際のコードを乗せると長くなるので割愛しますが、イメージはこんな感じのスライドショーです。
![スクリーンショット 2020-12-22 9.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/02335daf-86a4-9b5c-9303-3c60aeaf0995.png)
表示する画像のURLの配列、何番目を表示するかのデータをModelが持ち、
矢印のクリック、今表示する画像のSRCなどをViewが持ってる感じです。


```
<script type="text/javascript" src="js/App.js"></script>
```
↑こんな風にHTML側でApp.jsを読み込めば、動きそうですが、。

```App.js:1 Uncaught SyntaxError: Cannot use import statement outside a module```
こんなエラーが吐かれてしまって動きません。前述の通りJSにもブラウザにもファイルを結合する機能（import, export）がないからです。

###では、Webpackを入れてみましょう。

まずnpm initしてpackage.jsonを作ります。

```
npm init
```
 

続いて、Webpack、Webpack CLIをnpm経由でインストール（yarnでもOKです）

```
npm install webpack --save-dev
npm install webpack-cli --save-dev
```


`webpack.config.js` ファイルをルート配下に作ります。
これにWebPackの各種設定を記述していきます。
エントリーポイント、bundleファイルの出力場所を記述

```
module.exports = {
  // モードの設定、v4系以降はmodeを指定しないと、webpack実行時に警告が出る
  mode: 'development',
  // エントリーポイントの設定
  entry: './js/App.js',
  // 出力の設定
  output: {
    // 出力するファイル名
    filename: 'bundle.js'
  }
};
```

package.jsonにbuildコマンドを設定

```
  "scripts": {
    "build": "webpack"
  },
```

これで準備完了です。
`npm run build` コマンドを実行すると、App.js、Model.js、View.jsがバンドルされてbundleファイルが生成されます。

この時点でのファイルの構成はこんな感じです。

```
dist/
  └ bundle.js　//これが一つにまとまったビルドファイル
js/
  ├ Model.js データを管理
  ├ View.js Viewを管理
  └ App.js
index.html
package-lock.json
package.json
webpack.config.js
```

HTML側で読み込むJSファイルのパスを書き出されたbundleファイルに指定（デフォルトだとdist/bundle.jsです）

```
<script type="text/javascript" src="dist/bundle.js"></script>
```

これで、HTML側で問題なく動作します。

モジュール、バンドル、ビルドというWebPackの基本的な概念の理解が深まりました。

#### WebPackは各種プラグインで色々と機能を拡張できる

ここまでは本当に基本的なWebPackの使い方の紹介ですが、WebPackは本体にない機能などを拡張して使う事ができます。外部のプラグインをnpmなどでインストールし、Webpack.config.js、package.jsonに設定を記述して使う事ができます。

今回は試しに`Babel`を入れてみようと思います。

####Babelとは？
Babelはトランスパイルするプラグインで、トランスパイルとは、JavaScriptのコードをある書き方から別の書き方へと変換するツールです。今回はES6をES5にトランスパイルする為に使います。


プログラミング言語→プログラミング言語に変える事を「トランスパイル」といいます。
プログラミング言語→機械言語はコンパイルと言います。（Javaとか）

Babelは設定次第で、TS→JS、Sass→CSSという変換も可能です。

WebPack本体に、Babelを入れるのに、必要なプラグインは以下の３つ
```・babel-loader
・babel-core
・babel-preset
```

インストールができたら、webpack.config.jsのmoduleのrulesに以下を追記します。

```
  module:{
    rules:
    [
        {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader"
        }
    ]
}
```

さらに.babelrcというファイルを作り以下を記述しておきます。

```
{
  "presets": ["@babel/env"]
}
```

これにより、buildした時にBabelが動き、ES6からES5に変換されます。

bundle.jsを確認すると、Class構文が_classCallCheckに変換されていて動作も問題ありません。

簡単ではありましたが、WebPackは外部プラグインを取り込んで拡張していくという感覚をつかめました、またWebPack周りで新たな試みや発見があったら記事にしようと思います。

本記事を書くにあたり、こちらの記事も参考にしました。
https://qiita.com/soarflat/items/28bf799f7e0335b68186