webpackというものを触ってみる - コンパイルにCSSを含める

# はじめに

前回からの続きです。

https://qiita.com/kuro___inu/items/7fe2b0fdc63c3049b775

今回はwebpackのコンパイルにCSSを含めてみたいと思います。

# 環境

- windows10 (wsl2)
- node(v16.18.0)
- yarn(1.22.19)

ディレクトリ構成やファイルの内容は前回の最後から引き続きです。

# 必要なモノをインストール

CSSを含める為に必要なツールをインストールします。

```sh
$ yarn add -D style-loader css-loader
```

# 各種設定

次に `./webpack.config.js` に設定を追加します。

```diff_javascript:./webpack.config.js
// モード
// development:ソースマップが有効
// production:コード圧縮
+ const MODE = "development";
// "development"の場合のみソースマップ有効
+ const enabledSourceMap = MODE === "development";

module.exports = {
-   mode: "development",
+   mode: MODE,

    devtool: "source-map",

    // エントリーポイントのJs
    entry: `./src/index.js`,

    // コンパイルした結果を出力する先の設定
    output: {
        path: `${__dirname}/dist`,
        filename: `main.js`
    },

    // webpack-dev-serverの設定
    devServer: {
        static: "dist",     // 公開するルートディレクトリ
        open: true,         // サーバー起動後自動でブラウザ立ち上げ
        // port: 8081          // ポートを指定したい場合に記述。 デフォルトは8080。
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        // Babelの設定
                        loader: "babel-loader",
                        options: {
                            presets: [
                                "@babel/preset-env"
                            ]
                        }
                    }
                ]
            },
+           {
+               // CSSの設定
+               test: /\.css/,
+               use: [
+                   "style-loader",
+                   {
+                       loader: "css-loader",
+                       options: {
+                           url: false,
+                           sourceMap: enabledSourceMap
+                       },
+                   }
+               ]
+           }
        ]
    },

    // ES5(IE11等)向けにコンパイルする設定
    target: ["web", "es5"]
}
```

# CSSファイルを作成

次にCSSファイルを作成します。

```css:./src/style/main.css
body {
    background-color: #ddd;
    color: #000;
}
```

ディレクトリ構成は以下となります。

```sh
$ tree -I node_modules
.
├── dist
│   ├── index.html
│   ├── main.js
│   ├── main.js.LICENSE.txt
│   └── main.js.map
├── package.json
├── src
│   ├── index.js
│   ├── js
│   │   ├── minus.js
│   │   └── sum.js
│   └── style
│       └── main.css
├── webpack.config.js
└── yarn.lock

4 directories, 11 files
```

# `./src/index.js` でCSSファイルをインポート
次に `./src/index.js` で用意したCSSファイルをインポートします。

```diff_javascript:./src/index.js
import { sum } from "./js/sum";
import { minus } from "./js/minus";

// jQueryをインポートして$で使える様にする。
import jQuery from "jquery";
const $ = jQuery;

// CSSファイルをインポートする。
// ※Jsのインポートとは異なり、拡張子も忘れずにつける。
+ import "./style/main.css"

sum();
sum(5, 4);
minus();
minus(4, 2);


$(() => {
    $("#btn-alert").on("click", (e) => {
        alert($("#message").val());
    });
});
```

# コンパイル

では、コンパイルしてみます。
コンパイル後のディレクトリ構成は以下となります。

```sh
$ tree -I node_modules
.
├── dist
│   ├── index.html
│   ├── main.js
│   ├── main.js.LICENSE.txt
│   └── main.js.map
├── package.json
├── src
│   ├── index.js
│   ├── js
│   │   ├── minus.js
│   │   └── sum.js
│   └── style
│       └── main.css
├── webpack.config.js
└── yarn.lock

4 directories, 11 files
```

CSSを含めたのにファイルが増えたりはしていませんが、 `./dist/main.js` の中に含まれています。
試しにファイルを開いて `#ddd` で検索すると含まれている個所を確認する事ができるかと思います。

# 表示して確認

ローカルサーバーを起動しページの表示を確認して、背景色がグレー(#ddd)となっていれば用意したCSSファイルが反映されているという事になります。

開発者ツールで確認すると、 `<style>` タグが追加され先程用意したCSSファイルの内容が記述されているのを見ることができます。
はじめに2つインストールしましたが以下の様な動きをしているそうです。

| ツール | 役割 |
|:-:|:-:|
|style-loader   | 画面表示時に `<style>` タグを埋め込む。  |
|css-loader   | コンパイル時にCSSファイルを読み込んでまとめる。  |

# この時点でのディレクトリ構成等

```sh
$ tree -I node_modules
.
├── dist
│   ├── index.html
│   ├── main.js
│   ├── main.js.LICENSE.txt
│   └── main.js.map
├── package.json
├── src
│   ├── index.js
│   ├── js
│   │   ├── minus.js
│   │   └── sum.js
│   └── style
│       └── main.css
├── webpack.config.js
└── yarn.lock

4 directories, 11 files
```
```json:package.json
{
  "name": "20221014_webpack",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack",
    "serve": "webpack serve"
  },
  "devDependencies": {
    "@babel/core": "^7.19.3",
    "@babel/preset-env": "^7.19.4",
    "babel-loader": "^8.2.5",
    "css-loader": "^6.7.1",
    "style-loader": "^3.3.1",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "jquery": "^3.6.1"
  }
}
```
```js:webpack.config.js
// モード
// development:ソースマップが有効
// production:コード圧縮
const MODE = "development";
// "development"の場合のみソースマップ有効
const enabledSourceMap = MODE === "development";

module.exports = {
    mode: MODE,

    devtool: "source-map",

    // エントリーポイントのJs
    entry: `./src/index.js`,

    // コンパイルした結果を出力する先の設定
    output: {
        path: `${__dirname}/dist`,
        filename: `main.js`
    },

    // webpack-dev-serverの設定
    devServer: {
        static: "dist",     // 公開するルートディレクトリ
        open: true,         // サーバー起動後自動でブラウザ立ち上げ
        // port: 8081          // ポートを指定したい場合に記述。 デフォルトは8080。
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        // Babelの設定
                        loader: "babel-loader",
                        options: {
                            presets: [
                                "@babel/preset-env"
                            ]
                        }
                    }
                ]
            },
            {
                // CSSの設定
                test: /\.css/,
                use: [
                    "style-loader",
                    {
                        loader: "css-loader",
                        options: {
                            url: false,
                            sourceMap: enabledSourceMap
                        },
                    }
                ]
            }
        ]
    },

    // ES5(IE11等)向けにコンパイルする設定
    target: ["web", "es5"]
}
```

# おわりに

今回の作業でCSSファイルをJsファイルにまとめる事ができました。
これにより、画面を表示する際にCSSファイルをリクエストする必要がなくなります。

次回は、CSSのFWを導入してみたいと思います。

# 参考

https://ics.media/entry/17376/