webpack最低限


近代的なWeb開発には欠かせないwebpackの最低限のメモ。

## webpackとは何か？

一言で言うと「モジュールバンドラツール」の１つ。ということになりますが、よくわかりませんね。
ここでは「jsファイルやcssやらを（１つの）jsファイルにまとめるためのツール」くらいに思っていてよいかと思います。また、まとめる際にいろいろな処理を入れたりもできます。

実用的にはTypeScriptをコンパイルしてjsして、配置する。React(JSX)をコンパイルして配置するなどでの利用が一般的でしょうかね。


## インストール

とりあえずグルーバルに入れておきます。


```
npm install -g webpack webpack-cli
```

>package.jsonスクリプト中にwebpackを含める場合など結局ローカルインストールが必要になることもあります・・・。


## 使ってみる

では、とりあえず使ってみましょう。

### 作業場所の確保と作業ファイルの作成

作業場所と取り急ぎの作業ファイルを作ります。
index.htmlは生成したjsの動作確認用。index.jsは生成の元となるjsファイルです。

```
mkdir webpack-test
cd webpackptest

touch index.html index.js
```

>別にtouchで作る必要はありません。

### 各ファイルを編集

最低限の記述をします。classは定義してるだけ。bundle.jsはwebpackが生成するアウトプットファイル（js）の想定です。

```html:index.html
<!DOCTYPE html>
<html>
    <body>
        <p class="hello">こんにちは</p>
        <script src="bundle.js"></script>
    </body>
</html>
```

とりあえずhelloとalertを出す命令を記述。

```js:index.js
const hello = () => {
    alert("hello");
}

hello();
```

### webpackを利用する

ではwebpackを使ってコンパイル（バンドルファイルの生成）をします。
index.jsを入力ファイルとし、bundle.jsを出力ファイルとして指定しています。

```bash
webpack index.js -o bundle.js --mode=development
```

>--modeを指定しないとwarningがでるので追記しています。

上記コマンドを実行するとbundle.jsが出力されたと思います。

### 動作確認

では動作確認してみます。
index.htmlを開いてみましょう。helloとalertが表示されるはずです。

![スクリーンショット 2019-12-05 6.43.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/968e4724-899a-5992-4ed2-89aa2f604a16.png "スクリーンショット 2019-12-05 6.43.13.png")



とりあえず動きましたが、ここまでの作業だけなら「index.jsを直接呼べばいいじゃん？」って話です。
では、ファイルを追加、編集してみましょう。

>ただ、入力ファイルを受け取り、何か処理して出力するのだな・・・ということはわかったと思います。

## ファイルを追加してみる

では、ファイルの手を加えて見ましょう。
まず、新しいjsファイルを作ります。

```bash
touch lib.js
```

byeと表示する関数を実装します。

```js:lib.js
module.exports.bye = () => {
    alert("bye");
}
```

>ちなみにmodule.exportsという書き方は、commonjs（古いJS）で利用できる関数や変数をexportする命令です。

で、index.jsでlib.jsを読み込んでみます。

```diff:index.js
+const lib = require('./lib');

const hello = () => {
    alert("hello");
}

hello();
+lib.bye();
```

ここまでできたらwebpackを実行し、bundle.jsを更新します。

```bash
webpack index.js -o bundle.js --mode=development
```

で、再度index.htmlを（更新して）見てみます。
helloにつづき、byeのalertも表示されました。

![スクリーンショット 2019-12-05 6.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/a5a9ad7d-9819-a98f-debb-31f9cf71082c.png "スクリーンショット 2019-12-05 6.48.29.png")

lib.jsを追加しましたが、利用しているのはbundle.jsだけです。
webpackが２つのファイルを1つにまとめて（バンドルして）くれたのがわかります。

## webpack.config.jsを利用する

ここまではwebpackコマンド実行時に各種オプションを渡してきましたが、実用においてはwebpack.config.jsに動作を記述します。
では、上記で指定していたオプションをwebpack.config.jsに記述してみます。

ファイルを生成。

```bash
touch webpack.config.js
```

内容を記述。そんなに難しいことはありません。

```js:webpack.config.js
module.exports = {
    mode: 'development',
    entry: './index.js',
    output: {
        path: __dirname,
        filename: 'bundle.js',
    }
}
```

webpack.config.jsができたら、それがあるディレクトリでwebpackコマンドを実行すると自動的に読み込んで実行してくれます。


```bash
webpack
```

結果は同じです。


## CSSをバンドルしてみる

jsだけでは「まあ、復数でもrequireするだけじゃん」ということになるので、cssもバンドルも試してみたいと思います。

cssを作ります。

```bash
touch styles.css
```

pタグにhelloというclass名を付けていたので、それ用のスタイルを記述します。
ここでは文字を赤くしています。

```css:styles.css
.hello {
    color: red;
}
```

cssを正しくバンドルするためには追加のLoaderといわれるモジュールが必要なのでインストールします。

```bash
npm install --save css-loader style-loader
```

index.jsにてcssをimportします。

```diff:index.js
const lib = require('./lib');
+import './styles.css';

const hello = () => {
    alert("hello");
}

hello();
lib.bye();
```

cssを正しく処理できるようにwebpack.config.jsにローダーに関する設定を追加します。
testにて適用するファイル形式（ここでは.cssという末尾）を指定しています。
useにて適用するローダーを設定しています。css-loader -> style-loaderの順で適用されます。

```diff:webpack.config.js
module.exports = {
    mode: 'development',
    entry: './index.js',
    output: {
        path: __dirname,
        filename: 'bundle.js',
    },
+    module: {
+        rules: [
+            {
+                test: /\.css$/,
+                use: ['style-loader', 'css-loader'],
+            }
+        ]
+    }
}
```

ではwebpackを実行し、index.htmlを確認してみてください。

![スクリーンショット 2019-12-05 7.05.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/76ed7289-70bb-5892-b512-003beb7f8b49.png "スクリーンショット 2019-12-05 7.05.25.png")

linkでcssを取り込んでいるわけでもないのにスタイルができようされています！。どうしてこんなことができるのかはググりましょう。

ここまでで、webpackがweb（だけじゃないけど）に必要な各種リソースを1つのjsファイルにまとめられることがわかりました。
css以外にもjsonや画像等もまとめることができます。もちろん、TypeScript等をコンパイルした結果もOKです。


## onclick等からの呼び出しに対応する（関数化する）

ここまででのサンプルではjsがいきなり実行されていました。サンプルとしてはいいですが、実用性はありません。
そこで、onclick等のeventから関数を利用できるようにコードを変更してみます。

index.jsを下記のようにします。window.関数名という感じにします。

>もっと汎用化するならoutputにlibraryやlibraryTargetを指定する方法もあります。詳しくは[こちら](https://qiita.com/jkr_2255/items/283bc12dd07bc237179e)。

```diff:index.js
const lib = require('./lib');
import './styles.css';

const hello = () => {
    alert("hello");
}

+window.hello = hello;
+window.bye = lib.bye;
```

で、HTMLの方からonclickで読んでみます。

```diff:index.html
<!DOCTYPE html>
<html>
    <body>
        <p class="hello">こんにちは</p>
+        <button onclick="hello()">hello</button>
+        <button onclick="bye()">bye</button>
        <script src="bundle.js"></script>
    </body>
</html>
```

どうでしょう。動きました？（うごくはず）

## Loaderが何をしているか理解する（ために作ってみる）

最後にLoaderが何をしているか作ることで理解してみます。余裕のない人は読み飛ばしてください。

とりあえずテストにつかうファイルを生成します。
ここでは読み込んだテキストデータを大文字にして返すというLoaderを作ってみたいと思います。

```bash
touch test-loader.js test.txt
```

インプットとなるテキストファイル。

```txt:test.txt
abcd
```

ローダー。読み込んで大文字にして（JSON文字列形式）で返します。

```js:test-loader
module.exports = (context, map, meta) => {
    return `module.exports = ${JSON.stringify(context.toUpperCase())}`;
}
```

ローダーを使うように設定します。

```diff:webpack.config.js
module.exports = {
    mode: 'development',
    entry: './index.js',
    output: {
        path: __dirname,
        filename: 'bundle.js',
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
+            {
+                test: /\.txt/,
+                loader: './test-loader.js',
+            }
        ]
    }
}
```

index.jsにてtest.txtをインポートします（実際はローダーで処理してJSでimportできる形式になっているのでimportできます）。

```diff:index.js
const lib = require('./lib');
import './styles.css';
+import upperText from './test.txt';

const hello = () => {
    alert("hello");
}

+console.log(upperText);

window.hello = hello;
window.bye = lib.bye;
```

実行してみます。

![スクリーンショット 2019-12-05 7.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/75cc5b14-af58-5a8a-634b-a82162394430.png "スクリーンショット 2019-12-05 7.43.27.png")

小文字が大文字に変換されて、出力されています。

ま、とりあえずLoaderは特定のファイルを読み込んで必要な処理をするための機能。というレベルの理解でいいかと思います。

## 応用

* とりあえずTypeScriptのトランスパイルで利用する方法は[こちら](https://qiita.com/zaburo/items/26cb6dfb8a631ebbdfbd)。

## 参考

* より詳しい動作が知りたい人は[こちら](https://qiita.com/howdy39/items/48d85c430f90a21075cd)の記事が参考になります。
* ローダーの作成については[こちら](https://o296.com/e/%E7%B0%A1%E5%8D%98%E3%81%AAWebpackloader%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6Webpack%E3%81%A8%E4%BB%B2%E8%89%AF%E3%81%8F%E3%81%AA%E3%82%8B.html)の記事が参考になりました。