webpackの使い方

# npmを使えるように
```
npm  init
```

package.jsonが生成される

```
"private": "true", // プライベートにする
  "devDependencies": { // 公開しないようにする
    "css-loader": "^5.0.1",
    "webpack": "^5.15.0",
    "webpack-cli": "^4.3.1"
  }
```

## インストールの基本

### バージョンを確認
```
npm view velocity-animate
```

### 開発環境用のプラグイン --save-devをつけてインストールする
```
npm install --save-dev webpack@4.41.6
```

### 実行環境用のプラグイン --saveをつけてインストールする
```
npm install --save velocity-animate@1.5.2 jquery@3.7.0 
```

package.json
![Screenshot 2023-06-18 14.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/b4192d10-21ca-e998-a2f4-a76527a4f54c.png)

## 最初に作るもの

- src フォルダ
- index.js
- webpack.config.js

```webpack.config.js
const path = require('path') // pathの設定

module.exports = {
    entry: './src/javascripts/main.js', // srcのメインの読み込み先
    output: {
        path: path.resolve(__dirname, './dist'), // 出力する場所
        filename: "./javascripts/main.js"
    },
}
```

## scripts 関連

```package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server",
    "build:dev": "webpack",
    "build:production": "webpack --mode production"
  }
```

### webstormにnpmを設定する

![Screenshot 2023-06-17 16.13.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/66cee0c4-2203-d996-bca1-2215b4c9fc2e.png)


# webpack設定関連

## webpackインストール

```
npm view  webpack
npm install --save-dev webpack@4.41.6
npm view webpack-cli
npm install --save webpack-cli@hogehoge
```

- srcフォルダを作る
- ./src/main.js を作る
- ./webpack.config.js を作る

## webpack ビルド
```
npx webpack --mode development // 開発環境
npx webpack --mode production // 本番環境用

```

```webpack.config.js
const path = require('path') // pathの設定

module.exports = {
    mode: "development",
    entry: './src/javascripts/main.js', // srcのメインの読み込み先 
    output: {
        path: path.resolve(__dirname, './dist'), // 出力する場所 絶対パスのみ指定可能
        filename: "./javascripts/main.js"
    },
}
```

## web-dev-serverを使う

### web-dev-serverをインストール
```
 npm install webpack-dev-server@4.15.1 --save-dev
```

### サーバー立ち上げ
```
 npx webpack serve --mode=development
```

#### scripts
```package.json
"start": "webpack-dev-server --config webpack.dev.js",
```
:::note warn
webpack-mergeでの記述なので注意
:::

```webpack.dev.js
const path = require('path');

module.exports = merge(commonConfig, {
    mode: 'development',
    devServer: { // サーバー
        // open: true // 自動で開く
        port: 3000,
        static: {
            directory: path.resolve(__dirname, 'public'), // 出力
        }
    }
});
```


:::note warn
cliの相性がよくなくて立ち上がらなかったのでcliのバージョンをあげた
```
 npm install webpack-cli@5.1.4 --save-dev
```
:::

参考 https://qiita.com/syuuu/items/69485076f11a06530200
@syuuu さんより

## キャッシュ対策

jsファイルにハッシュを付与することでキャッシュ対策する

```webpack.commno.js
module.exports = {
    // entry: './src/app.js', // srcのメインの読み込み先
    entry: {
        app: './src/javascripts/app.js', // app.jsを読み込む
        another: './src/javascripts/another.js', // another.jsを読み込む
        other: './src/javascripts/other.js', // other.jsを読み込む
    },
    output: {
        path: path.resolve(__dirname, 'public'), // 出力する場所 絶対パスのみ指定可能
        filename: "javascripts/[name].[contenthash].js", // ハッシュを付属させる
        chunkFilename: "javascripts/[name].[contenthash].js", // ハッシュを付属させる
    },
}

```

## distのファイルを一度削除する

### clean-webpack-plugin インストール

```
npm install --save-dev clean-webpack-plugin@3.0.0
```

```webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
    },
    module: {
    },
    plugins: [
       new CleanWebpackPlugin(),
    ]
}
```

## index.js 
- cssの読み込み
- javascriptsの呼び出しを行っている

```src/javascripts/index.js
import my from './my'; // javascriptsの中から呼び出し同じ階層
import '../stylesheets/main.css'; // cssの呼び出し違う階層だから..で上に上げている

my(); // javascripts/my.jsのmy関数を呼び出し
```

# CSS関連

## css-loader
```
npm install --save-dev css-loader@5.0.1
```

## style-loader
```
npm install --save-dev style-loader@2.0.0
```
::: note warm
mini-css-extract-pluginを使うならこれは不要になる
:::

```webpack.config.js
module: {
        rules: [
            {
                test: /\.css/, // .cssのファイルを検知する \.は正規表現のドット検知するため
                use: [
                    {
                        loader: "style-loader"// 処理するモジュール
                    },
                    {
                        loader: "css-loader" // 読み込むモジュール
                    }
                ]
            }
        ]
    }
```

:::note warn
useは下から上に読み込まれるので注意する
:::

## mini-css-extract-plugin

```
npm install --save-dev mini-css-extract-plugin@1.3.4
```

:::note warn
これを入れた場合 style-loaderが不要になるためアンイストールする
:::

```webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /\.css/, // .cssのファイルを検知する \.は正規表げのドット検知するため
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader // 処理する, dist/main.cssを作成する
                    },
                    {
                        loader: "css-loader" // 読み込むモジュール
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: './stylesheets/main.css' // 出力されるcssの名前を変える
        }),
    ]
}

```

./main.cssが生成される

:::note warn
useは下から上に読み込まれるので注意する
プラグインを変数に入れる
pluginsをmodulesの下に追加
:::


# sass関連

## sass-loaderインストール
```
npm install --save-dev sass-loader@12.4.0
```

```webpack.confing.js
module.exports = {
    mode: "development",
    module: {
        rules: [
            {
                test: /\.css|sass|scss/, // .cssのファイルを検知する \.は正規表げのドット検知するため
                use: [
                    // {
                    //     loader: "style-loader"// 処理するモジュール
                    // },
                    {
                        loader: MiniCssExtractPlugin.loader //
                    },
                    {
                        loader: "css-loader" // 読み込むモジュール
                    },
                    {
                        loader: "sass-loader" // sass読み込み
                    }
                ]
            },
        ]
    },
    plugins: [
        
    ],
}
```

:::note warn
useは下から上に読み込まれるので注意する
:::

## node-sass

```
npm install --save-dev node-sass@9.0.0 
```



## source-mapを作る
```webpack.config.js
{
                        loader: "css-loader", // 読み込むモジュール
                        options: {
                            sourceMap: true, // 元のscssファイルをブラウザに表示させる 本番環境ではfalseにする
                        }
                    },
```

![Screenshot 2023-06-17 15.41.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/79b42881-c0a3-51e1-07f8-3cc7165036d9.png)

![Screenshot 2023-06-17 15.41.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/3a51d0de-0ce8-db1a-46a8-cc4085644e32.png)



# HTML関連

## html-webpack-plugin と html-loader
インストール

```
 npm install --save-dev html-webpack-plugin@5.0.0
 npm install --save-dev html-loader@1.3.2 // requireで画像を読み込まなくて済むように
```

```webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
    },
    module: {
        rules: [
            {
                test: /\.pug/,
                use: [
                    {
                        loader: 'html-loader',
                    },
                ],
            },
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/templates/index.html", // 読み込み先
            filename: "index.html"// 出力ファイルネーム
        }),
    ]
}

```

index.htmlが生成される

:::note warn
useは下から上に読み込まれるので注意する
プラグインを変数に入れる
pluginsをmodulesの下に追加
:::

# pug関連

##  pug-html-loaderインストール

```
npm install --save-dev pug-html-loader@1.1.5
```

```webpack.config.js

module.exports = {
    entry: './src/javascripts/main.js', // srcのメインの読み込み先
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: "./javascripts/main.js" //// 出力されるfileの名前を変更
    },
    module: {
        rules: [
            {
                test: /\.pug/,
                use: [
                    {
                        loader: 'html-loader',
                    },
                    {
                        loader: 'pug-html-loader',
                        options: {
                            pretty: true,
                        },
                    },
                ],
            },
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            // template: "./src/templates/[name].html", // 読み込み先(htmlの場合)
            template: "./src/templates/index.pug", // 読み込み先(pugの場合)
            // filename: "[name].html"// 出力ファイルネーム
            filename: "index.html"// 出力ファイルネーム
        }),
        new HtmlWebpackPlugin({
            // template: "./src/templates/[name].html", // 読み込み先(htmlの場合)
            template: "./src/templates/access.pug", // 読み込み先(pugの場合)
            // filename: "[name].html"// 出力ファイルネーム
            filename: "access.html"// 出力ファイルネーム
        }),
    ]
}

```

# javascript 関連

## 特定のページに特定のjsを読み込ませる

``` webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    // entry: './src/app.js', // srcのメインの読み込み先
    entry: {
        app: './src/javascripts/app.js', // app.jsを読み込む
        another: './src/javascripts/another.js', // another.jsを読み込む
        other: './src/javascripts/other.js', // other.jsを読み込む
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/html/index.html", // 読み込み先
            // filename: "index.html"// 出力ファイルネーム
            chunks: ['app'], // app.htmlだけで読み込ませたいjsファイルを記載 entryでしたファイル
        }),
        new HtmlWebpackPlugin({
            filename: "another.html",
            template: "./src/html/another.html", // 読み込み先
            chunks: ['another'], // another.htmlだけで読み込ませたいjsファイルを記載 entryでしたファイル
        }),
        new HtmlWebpackPlugin({
            filename: "other.html",
            template: "./src/html/other.html", // 読み込み先
            chunks: ['other'], // other.htmlだけで読み込ませたいjsファイルを記載 entryでしたファイル
        }),
    ],
}

```

## 共通のライブラリを抽出する

```webpack.common.js
module.exports = {
    // entry: './src/app.js', // srcのメインの読み込み先
    entry: {
        app: './src/javascripts/app.js', // app.jsを読み込む
        another: './src/javascripts/another.js', // another.jsを読み込む
        other: './src/javascripts/other.js', // other.jsを読み込む
    },
    optimization: {
        splitChunks: {
            chunks: 'initial',
            cacheGroups: {
                vendor: { // node_modulesが対象
                    test: /node_modules/, // 分割の対象を指定
                    name: 'vendor', // 付けたいファイル名
                },
                vendorsModules: { // 自作さたjsで共通して使わているところを切り出す
                    // chunks: 'initial',
                    test: /src[\\/]javascripts[\\/]modules/, // 指定
                    name: 'vendor-modules', // ファイル名
                    minSize: 0, // 分割するファイルの最小サイズ(キロバイト)
                    minChunks: 2, // モジュールが共通で使われいる最少個数
                },
            },
        },
    },
}

```

node_modulesで共通のものはvendor.jsで抽出される
自作した共通のjsはvendor-modules.jsで抽出される

https://v4.webpack.js.org/plugins/split-chunks-plugin/


## トランスコンパイルする

ES5に対応するためにES6を変換する必要がある

### babel-loader インストール
```
 npm install --save-dev babel-loader@8.2.2
```

### babel/core インストール
```
npm install --save-dev @babel/core@7.12.10
```

### babel/preset-env インストール
```
npm install --save-dev @babel/preset-env@7.12.11
```

```webpack.common.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/, // 対象ファイル
                exclude: /node_modules/, // 除外ファイル
                loader: "babel-loader",
            },
        ],
    },
}
```

```babel.config.js
module.exports = {
    presets: ['@babel/preset-env'],
}
```

### 対象外にしたブラウザの指定

.browserslistrcを作成する

```.browserslistrc
defaults
```

おすすめサイト 
https://coliss.com/articles/build-websites/operation/work/target-browsers-between-different-front-end-tools.html

https://github.com/browserslist/browserslist


### ポリフィルを取り込む方法

#### corejsをインストールする

```
npm install --save-dev core-js@3.31.0 
```

babel.config.jsを作る

corejsがデフォルトが2なのでbabel.config.jsで3にする

:::note alert
srcの中に入れないように注意!!
:::


```babel.config.js
module.exports = {
    presets: [
        [
            '@babel/preset-env',
            {
                useBuiltIns: 'usage',
                corejs: 3, // 必ず3にするデフォルトは2
                // debug: true, // 使い終わったらコメントアウトする
            },
        ],
    ],
};

```

debugをtrueにしてビルドすると対象の古いブラウザに合わせてポリフィル(es6未満のに合わせる)を作成する

### ソースマップ作成

```webpack.confing.js
devtool: 'source-map',
```

![Screenshot 2023-06-17 15.42.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/fb963f82-14cf-2977-a91f-0dc9cfa5f6b1.png)


```webpack.confing.js
module.exports = {
    mode: "development",
    devtool: 'source-map',
    module: {
        rules: [
            {
                test: /\.js/, // jsファイルを検知する
                exclude: /node_modules/, // 除外することを明記
                use: [
                    {
                        loader: "babel-loader", //
                        options: {
                            presets: [
                                ['@babel/preset-env', {'targets': '> 0.25%, not dead'}] // 0.25%以上のシェアがあり サポートが終了していないブラウザと指定している
                            ]
                        }
                    }
                ]
            },
        ]
    },
    plugins: [
        
    ],
}
```

# 画像関連

## image-webpack-loader インストール

```
npm install --save-dev image-webpack-loader@7.0.1
```

```webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.(eot|svg|ttf|woff|woff2|png|jpg|jpeg|gif)/,
                type: "asset/resource", //webpack5から
                generator: {
                    filename: 'images/[path][name][ext]' //webpack5から
                },
                use: [
                    // { // webpack4まで
                    //     loader: 'file-loader',
                    //     options: {
                    //         esModule: false,
                    //         name: 'images/[name].[ext]',
                    //     }
                    // },
                    {
                        loader: "image-webpack-loader", // 画像の圧縮
                        options: {
                            mozjpeg: { // オプション
                                progressive: true,
                                quality: 65, // 画質下げ
                            }
                        }
                    }
                ]
            },
        ]
    },
    plugins: []
}
```

# よく使うライブラリ

## jQuery

実行環境なので-devはいらない

```
npm install --save jquery@3.7.0 
```

```app.js
import $ from 'jquery'; // jqueryを$で扱うようにしている

$('body').append(result);
velocity($('h1'), 'fadein', {duration: 2000, loop: true});
```

## webpack-merge

webpack.config.js を 共通, 開発, 本番に分ける

### インストール

```
npm install --save-dev webpack-merge@5.9.0 
```

```webpack.common.js
const path = require('path') // pathの設定

module.exports = {
    entry: './src/app.js', // srcのメインの読み込み先
    output: {
        path: path.resolve(__dirname, 'public'), // 出力する場所 絶対パスのみ指定可能
        filename: "javascripts/bundle.js"
    },
}

```

```webpack.dev.js
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.common'); // ディレクトリの書きミスに注意

module.exports = merge(commonConfig, {
    mode: 'development',
    // watch: true, ファイの更新があるbuildする
})

```

```webpack.prod.js
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.common'); // ディレクトリの書きミスに注意

module.exports = merge(commonConfig, {
    mode: 'production',
})
```

```package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
```

## terser-webpack-plugin

console.logを削除
ライセンスの抽出 また それを出力しないようにする

インストール
```
npm install --save-dev terser-webpack-plugin@5.3.9 
```

```webpack.prod.js
const TerserPlugin = require('terser-webpack-plugin');

module.exports = merge(commonConfig, {
    optimization: {
        minimizer: [
            new TerserPlugin({
                extractComments: false, // ライブラリーのライセンスファイルを削除
                terserOptions: {
                    compress: {
                        drop_console: true // console.logの表示を削除
                    }
                }
            })
        ]
    }
})

```

### ソースマップ作成

:::note alert
絶対の開発環境のみで使う!!
本番環境禁止!!
:::

```webpack.dev.js
module.exports = merge(commonConfig, {
    devtool: 'eval-cheap-module-source-map', // ソースマップ作成 // 書き方が昔と違うので注意
});

```

どのファイルーでエラーを起こしているかわかる
![Screenshot 2023-06-18 16.53.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/687c63c6-d9f9-23c0-894a-d6145e7f57d7.png)

https://webpack.js.org/configuration/devtool/#development

## clean-webpack-plugin
buildする前にファイルを自動で削除させる

```
npm install --save-dev clean-webpack-plugin@3.0.0
```

```webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
    },
    module: {
    },
    plugins: [
       new CleanWebpackPlugin(),
    ]
}
```

## eslint
jsのコードに一貫性を持たせるツール

### インストール

```
npm install --save-dev eslint@8.43.0 
npm install --save-dev eslint-webpack-plugin@4.0.1
```

```webpack.common.js
const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = {
    plugins: [
        new ESLintPlugin({
            extensions: ['.js' ],
            exclude: 'node_modules',
            fix: true, // 自動修正にするか
        }),
    ],
}
```

```.eslintrc.js
module.exports = {
    root: true, // trueにするとこの設定があるディレクトリーよりも親階層上の設定ファイルを探しにいかなくなる
    env: { // 検証するjavascriptの実行環境
        browser: true, // console.logでエラーを発生させないか
        es2020: true, // es2020までの構文を利用してもエラーが発生しなくなる
    },
    parserOptions: {
        sourceType: "module", // importやexportの構文を使ってもエラーが発生しなくなる
    },
    extends: ['eslint:recommended'], // 外部が勧めるeslintのルールを指定 今回はeslintがおすすめ設定を指定している
    rules: {
        'prefer-const':'error', // 更新しない変数にconstが使われいたらエラーが出るようにしている
    },
}
```

https://eslint.org/docs/latest/use/configure/

## prettier

空白やコーテーションマークに一貫性を持たせる

### インストール

```
 npm install --save-dev prettier@2.8.8
npm install --save-dev eslint-config-prettier@8.8.0 
npm install --save-dev eslint-plugin-prettier@4.2.1 
```

```.eslintrc.js
module.exports = {
    extends: [
        'eslint:recommended', // 外部が勧めるeslintのルールを指定 今回はeslintがおすすめ設定を指定している
        'plugin:prettier/recommended', // prettierを有効にする こちら必ず最後に追加する
    ],
}
```

```.prettierrc.js
module.exports = {
    singleQuote: true,
};
```

https://prettier.io/docs/en/options.html

## auto prefixer

### インストール
```
npm install --save-dev postcss-loader@7.3.3
```

```
npm install --save-dev autoprefixer@10.4.14 
```

### 設定

```webpack.common.js
module.exports = {
  module: {
      {
        test: /\.scss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader, //
          },
          {
            loader: 'css-loader', // 読み込むモジュール
            options: {
              sourceMap: true, // 元のscssファイルをブラウザに表示させる 本番環境ではfalseにする
              // importLoaders: 2, // Sass+PostCSSの場合は2を指定
            },
          },
          {
            loader: 'postcss-loader',
          },
          {
            loader: 'sass-loader', // sass読み込み
          },
        ],
      },
    ],
  },
};
```

:::note warn
順番を間違えないように
:::

```postcss.config.js
// eslint-disable-next-line no-undef
module.exports = {
  // eslint-disable-next-line no-undef
  plugins: [require('autoprefixer')],
};
```

```.browserslitsrc.js
defaults
```
## purge-webpack-plugin

CSSフレームワークの使ってないCSSの部分をカットする

### 設定

```webpack.common.js
const path = require('path'); // pathの設定
const glob = require('glob');
const {PurgeCSSPlugin} = require('purgecss-webpack-plugin');

// eslint-disable-next-line no-undef
module.exports = {
  plugins: [
    // 使っていないCSSをカット
     new PurgeCSSPlugin({
       paths: glob.sync(
         `${path.join(__dirname, 'src/')}/**/*`,
         {nodir: true},
       ),
    }),
  ],
};
```