ちょっとがんばるWebサイト開発 on Webpack5 - CSSをコピー＆ペーストする

# 前書き

## 本記事のゴール

この記事では、ソースフォルダ `/src` および配信用フォルダ `/dist` を管理するプロジェクトにおいて、Webpackを利用して `/src` フォルダに含まれるCSSファイルを `/dist` フォルダに移動させる（コピー＆ペーストする）方法を理解することを目指します。

:::note info
この記事は同シリーズ別記事 [「ちょっとがんばるWebサイト開発 on Webpack5 - HTMLをコピー＆ペーストする」](https://qiita.com/Sharkkii/items/033e3d8119bfe60f520e) と類似した内容を扱うため、同記事の文章を一部流用しています。ご了承ください。
:::

## この記事で解説する内容

- ソースフォルダ `/src` および配信用フォルダ `/dist` の分割管理について説明します
- `/src` フォルダに含まれるCSSファイルを `/dist` にコピー＆ペーストする方法を説明します
- 簡単な実例を示します

## この記事で解説しない内容

- HTML/JavaScript等CSS以外のファイル形式は取り扱いません

## シリーズ記事

この記事はシリーズ **「ちょっとがんばるWebサイト開発 on Webpack5」** の記事です。
シリーズ全体の概要は [以下のリンク先記事](https://qiita.com/Sharkkii/items/df707cb68f3729493800) にまとめられています。

https://qiita.com/Sharkkii/items/df707cb68f3729493800

:::note info
この記事では **Webpack5** (version5.X.X) を対象としています。
:::

# 背景知識

## ソースフォルダ `/src` ・配信用フォルダ `/dist`

[「ちょっとがんばるWebサイト開発 on Webpack5 - HTMLをコピー＆ペーストする」](https://qiita.com/Sharkkii/items/033e3d8119bfe60f520e#背景知識) の説明を一部改変して引用したものを載せておきます。

> 一般にプロジェクト開発では、ソースコード（開発者が手動で実装したコード）と配信用コード（利用/公開するコード）を分離して管理することがあります。例えば、C/Java言語のようにコンパイルが必要な言語を使用する場合や、ソースコードの一部または全部を非公開にしたい場合にそのような管理方法を採用します。慣例的に、ソースコードは `/src` フォルダに、配信用コードは `/dist` に格納されることが多いです。

## このシリーズ記事における設計思想

[「ちょっとがんばるWebサイト開発 on Webpack5 - HTMLをコピー＆ペーストする」](https://qiita.com/Sharkkii/items/033e3d8119bfe60f520e#背景知識) の説明を一部改変して引用したものを載せておきます。

> このシリーズ記事では、ソースコードの一部または全部に対して各種変換処理/最適化を行うことでWebサイトとして公開する配信用コードを生成することを想定します。そのため、C/Java言語のプロジェクトと同様に、ソースコードと配信用コードを分離して管理することにしています。慣例に倣って、ソースコードを `/src` フォルダに、配信用コードを `/dist` に格納しています。
>
> それに加えて、配信用コードはそのままの形で利用可能であることが望ましいと考えています。すなわち、配信用コードにはWebサイトの公開に必要なものがすべて含まれており、`/dist` ディレクトリ配下のファイル群をWebサーバにアップロードすることで完全なWebサイトになるような設計を目指します。そのため、プロジェクトのビルドの出力結果が完全なWebサイトになるように設定します。
>
> 実践的なプロジェクトでは、すべてのソースファイルに対して変換処理/最適化を行うとは限りません。例えば、ソースCSSファイルをそのままの形で利用/公開したい場合もあるでしょう。そうした場合（実装したソースコードと利用/公開する配信コードが同一の場合）でも、当該ファイルを `/src` フォルダから `/dist` フォルダに移動させる（コピー＆ペースト）するようにします。それによって、Webサーバにアップロードすべきファイル/フォルダを `/dist` フォルダで統一的に管理することができるようになり、配信用コードを選別する時間的コストを削減することができます。
>
> なお、単純なファイル/フォルダのコピー＆ペーストはシェルスクリプト等によっても実現可能ですが、このシリーズ記事ではWebpackを利用して解決することにしています。ビルド作業全体をWebpackに集約することでビルドツールの管理コストも削減することができますし、新たに変換処理/最適化を適用したくなった際にも比較的容易に移行することができるためです。

# 方法

:::note info
サンプルコードをGitHubで公開しています。記事と併せてご覧ください。
**[/website/website-dev-on-webpack5/plain-css-on-webpack5](https://github.com/Sharkkii/sample-codes/tree/develop/website/website-dev-on-webpack5/plain-css-on-webpack5)**
:::

:::note info
実装例の説明では、ファイル/フォルダパスを *ルート相対パス* の形式で記述しています。ここでルートはプロジェクトルートまたはWebサイトのドキュメントルートに相当します。
:::

## 準備

Webpackを含むNode.jsパッケージの利用には [Node.js](https://nodejs.org/ja/) が必要です。
インストールが未実施の場合には、以下のリンクからインストールしておいてください。

https://nodejs.org/ja/

また、動作確認を行うためのNode.jsプロジェクトを作成しておきます。
適当な名前のディレクトリ（ここでは `my-css-project` ）を用意した上で、そのディレクトリにおいて `npm init` コマンドを実行することでNode.jsプロジェクトを新規作成することができます。

```shell:ターミナル
# my-css-projectディレクトリの作成
mkdir /path/to/my-css-project
cd /path/to/my-css-project

# Node.jsプロジェクトの作成
npm init
```

`npm init` コマンドを実行するとプロジェクトに関する情報を入力するよう促されますが、今回は適当な設定にしておいて問題ありません。今後必要に応じて適宜変更しましょう。
コマンド実行完了後、 `/package.json` という設定ファイルが新規作成されていることを確認したら事前準備完了です。

## 手順概要

1. [npmパッケージを導入する](#手順1-npmパッケージを導入する)
CSSのコピー＆ペーストに必要なnpmパッケージ　`webpack` `webpack-cli` `css-loader` `mini-css-extract-plugin` をプロジェクトに追加します。

2. [Webpackの設定ファイルを記述する](#手順2-webpackの設定ファイルを記述する)
CSSをコピー＆ペーストする手順やルールを設定ファイル `/webpack.config.js` に記述します。

3. [CSSファイルを作成する](#手順3-cssファイルを作成する)
動作確認用のCSSファイルを `/src/source.css` を作成します。

4. [Webpackのビルドを実行する](#手順4-webpackのビルドを実行する)
Webpackのビルドを実行することで、CSSファイル `/dist/target.css` を生成（コピー＆ペースト）します。

## 手順詳細

### [手順1] npmパッケージを導入する

今回は [Webpack](https://webpack.js.org/) を利用してCSSファイルのコピー＆ペーストを行います。

まず初めに、Webpackを利用するのに必要な　`webpack` `webpack-cli` パッケージをインストールします。
Webpack5（version5.X.X）をインストールするため、バージョン指定を行っています。

https://webpack.js.org/

```shell:ターミナル
npm install --save-dev webpack@5 webpack-cli@5
```

次に、CSSファイルをコピー＆ペーストするのに必要な　`css-loader` `mini-css-extract-plugin` パッケージをインストールします。

https://www.npmjs.com/package/css-loader

https://www.npmjs.com/package/mini-css-extract-plugin

```shell:ターミナル
npm install --save-dev css-loader mini-css-extract-plugin
```

### [手順2] Webpackの設定ファイルを記述する

Webpackは、適切に設定を記述することで様々な処理を実行することができます。
ここではCSSファイル　`/src/source.css` をコピーして `/dist/target.css` にペーストするための必要最小限の設定を示します。

```js:/webpack.config.js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = function() {
  return {

    mode: "development",

    entry: {
      /**
       * /src/source.css -> OUTPUT_DIRECTORY/target.css
       */
      target: path.resolve(__dirname, "src", "source.css"),
    },

    output: {
      /**
       * OUTPUT_DIRECTORY = /dist
       */
      path: path.resolve(__dirname, "dist"),
    },

    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            /**
             * CssLoader -> MiniCssExtractPluginLoader
             */ 
            MiniCssExtractPlugin.loader,
            "css-loader",
          ],
        }
      ]
    },
    
    plugins: [
      new MiniCssExtractPlugin(),
    ],

  }
}
```

特に注目すべきポイントは以下の2点です。

1) **Webpackのエントリ設定箇所に、入力/出力CSSファイルのパスを指定する**
2) **Webpackのルール設定箇所に、拡張子 `*.css` のファイルに対して2つのローダー `css-loader` および `MiniCssExtractPlugin.loader` を適用するというルールを記述する**

1つ目のエントリ設定は、ソースCSSファイルをWebpackのビルド対象とするために必要なものです。
Webpackは、原則としてエントリ設定で指定されたファイル群とそれが依存するファイル群をビルド対象とし、そのファイル群に対して各種最適化/変換処理を行います。
`entry: { target: path.resolve(__dirname, "src", "source.css") }` という設定を記述することで、ソースCSSファイル `/src/source.css` をWebpackのビルドプロセスに入力することができ、各種最適化/変換処理の結果を配信用ディレクトリに出力することができます[^1]。

2つ目のルール設定は、CSSファイルをコピー＆ペーストするために必要なものです。
Webpackは、ルール設定で指定された内容に従って最適化/変換処理等を行います。
`{ test: /\.css$/ }` および　`{  use: [ MiniCssExtractPlugin.loader, "css-loader" ] }` という設定を記述することで、拡張子 `*.css` のファイルに対して `css-loader` の変換処理と `MiniCssExtractPlugin.loader` の変換処理をこの順で適用することができます。
大雑把に言えば、`css-loader` はCSSスタイル定義をJavaScriptスクリプトとして扱えるようにするもので、`mini-css-extract-plugin` は `css-loader` の出力結果を単一のCSSファイルとして抽出するものです（この記事では詳細を割愛します）。

> [参考] Webpack設定
> - [Webpack - Concepts](https://webpack.js.org/concepts)
> - [Webpack - Loaders](https://webpack.js.org/concepts/loaders/)
> - [Webpack - Plugins](https://webpack.js.org/concepts/plugins/)
> - [Webpack - Module.Rules](https://webpack.js.org/configuration/module/#modulerules)

> [参考] css-loader / mini-css-extract-plugin
> - [css-loader - npm](https://www.npmjs.com/package/css-loader)
> - [mini-css-extract-plugin - npm](https://www.npmjs.com/package/mini-css-extract-plugin)

### [手順3] CSSファイルを作成する

手順2の設定に従ってCSSファイルを作成します。
上記設定ファイル `/webpack.config.js` では入力CSSファイルパスを　`/src/source.css` に指定したので、その位置に `source.css` ファイルを作成しましょう。
ファイル内容はどんなものでも構いませんが、ここでは例として以下のように記述することにします（折りたたみ要素の中にあります）。

<details>
<summary> /src/source.css の入力内容例</summary>

```css:/src/source.css
h1 {
  color: red;
}
```
</details>

### [手順4] Webpackのビルドを実行する

手順1〜3でCSSのコピー＆ペーストのための準備が完了しました！
それではWebpackを用いて `/src/source.css` から `/dist/target.css` を生成（コピー＆ペースト）してみましょう。
ターミナルで `npx webpack` コマンドを実行することでビルド作業が開始します。

```shell:ターミナル
# ディレクトリ移動
cd /path/to/my-css-project

# Webpackコマンド実行
npx webpack
```

ビルドが正常に完了すれば、`/src/source.css` と同一内容のCSSファイル `/dist/target.css` が生成されていることを確認できると思います。`css-loader` の変換プロセスにおいてコメントが挿入されていることに注意してください。プロジェクトの開発段階ではこの情報をデバッグ等に利用することができます。

<details>
<summary>　/dist/target.css の出力内容例</summary>

```css:/dist/target.css
/*!******************************************************************!*\
  !*** css ./node_modules/css-loader/dist/cjs.js!./src/source.css ***!
  \******************************************************************/
h1 {
  color: red;
}
```
</details>

:::note info
手順2のWebpack設定ではモードを開発モード（developmentモード）に設定しました。本番環境において配信用コードを生成する際には、本番モード（productionモード）に設定した上でWebpackのビルド作業を実行しましょう。開発モードから本番モードに切り替えるには、Webpackのモード設定を `{ mode: production }` とするか、Webpackコマンド実行時にオプション `--mode=production` を指定することでそれを実現することができます。本番モード下で上記プロジェクトをビルドすると、コメント挿入なしの出力結果を得ることができます。

```shell
# Webpackコマンド実行（本番モード）
npx webpack --mode=production
```
:::

:::note info
上記のWebpack設定では、CSSのコピー＆ペーストの際に不必要なJavaScriptファイル `/dist/target.js` が生成されるようになっています。不必要なJavaScriptモジュールを削除したい場合には `WebpackRemoveEmptyScripts` プラグイン等を利用しましょう。

> [参考] webpack-remove-empty-scripts プラグイン
> - [webpack-remove-empty-scripts - npm](https://www.npmjs.com/package/webpack-remove-empty-scripts)
:::
# 後書き

**サンプルコード**
**[/website/website-dev-on-webpack5/plain-css-on-webpack5](https://github.com/Sharkkii/tech-blog-code/tree/develop/website/website-dev-on-webpack5/plain-css-on-webpack5)**

[^1]: 基本的に、CSSファイルはHTMLファイルの `<link>` タグを通して読み込まれるもので、CSSファイル単体で扱う場合はそれほど多くありません。そのため、エントリポイントにHTMLファイルを指定することでそれが依存するCSSファイルをビルド対象に含める、というアプローチをとる方が自然かもしれません。この記事では解説しませんが、2つのWebpackプラグイン `html-webpack-plugin` `html-loader` を併せて利用することでそれを実現することができます。