Webpackについて学ぶ

Webpackなんもわからないのつらいので学びたい

現役エンジニアのためのWebpack環境構築入門 with Babel|Sass|Eslint
まずはudemyで見る
Webpackの設定周り(基礎編)
- webpack.config.jsに書く
- mode
- developやproduction
- 出力結果が変わる(minifyされてないとか)
- devtool
- 出力結果が変わる
- entry
- バンドルの大元のファイル
- 複数指定できる
- デフォルトはindex.jsを読む
- output
- 出力先
- 複数指定もできる
- mode
- 余談
-
node_modules/.bin
には実行コマンドが格納されてる(実態はshファイル)
-

Loaderについて
- jsやsass、css、ファイルなどを読めるようにする
- sass-loader
- sass -> cssに変換するsassのローダー
- css-loader
- css用のwebpackローダー
- style-loader
- jsファイルにバンドルされたstyle情報をhtmlに注入するwebpackの機能を使うためのローダー
- postcss-loader
- autoprefixerなどを読み込むためのローダー
- css -> cssの変換
- autoprefixerはcssを読み込んで、ベンダープレフィックスをつけてくれる
- file-loader
- cssからファイルを読めるようにするローダー
- web fontを読む時にも使う
- name:ハッシュとかもつけられる
- outputPath:出力先
- publicPath:画像をCDNとかに置く時、ドメインを含めたい場合に使ったりする
- sass-loader
- ローダーの設定
- test:ファイルの拡張子を指定
- use:ローダーの指定
- 配列などで記載すると、後ろから順番に実行されるらしい
{
"test": /.scss$/, // 正規表現で記述
"use": ["style-loader","css-loader", "postcss-loader", "sass-loader"] // sass-loaderから順に実行
}

Loaderがバンドルするまでの流れ
この例の場合
{
"test": /.scss$/, // 正規表現で記述
"use": ["style-loader","css-loader", "postcss-loader", "sass-loader"] // sass-loaderから順に実行
}
1. sass-loaderがcssに変換
cssの記法に変換
2. postcss-loaderがautoprefixをつける
--webkitなどのベンダープレフィックスをつける
module.exports = {
plugins: [
require('autoprefixer')
]
};
3. css-loaderで読み込まれて?style-loaderでoutputのjsファイルにバンドルされる
ただのオブジェクトになる
// Module
exports.push([module.i, "h1 {\n font-size: 2em;\n transition: all 0.3s;\n color: blue;\n}\nh1:hover {\n transform: translateX(50px);\n color: red;\n}\n\n.bg {\n background-image: url(" + ___CSS_LOADER_URL_REPLACEMENT_0___ + ");\n background-size: cover;\n width: 100px;\n height: 100px;\n}", ""]);
4. index.htmlにstyleタグとして挿入される
MiniCssExtractPlugin
MiniCssExtractPlugin
を使うと、cssは別ファイルとして出力されるようになるらしい
後述

出力ファイルの命名
- hash:ビルド毎のハッシュ値、差分があると全てのファイルが再計算されるのであまり使わない
- contentHash:コンテンツ毎のハッシュ値、画像とかに使う
- chunkHash:チャンク毎のハッシュ値、jsとcssファイルに同じハッシュ値をつけられる
- webpack.config.jsのoutput単位っぽい(複数entry、複数outputだとその分チャンクが作られそう)

Babel
ES6 -> ES5にトランスパイルしてくれるもの
babel-loader
- webpackのローダー
- トラブルシューティングに色々書いてあって面白いかも
使い方
-
.babelrc
かbabel.config.js
に記載 - targetsとして対象とするブラウザについてのクエリが記載できる
- babelやautoprefixerで使われているクエリの書き方が↓
- https://github.com/browserslist/browserslist
- ブラウザのバージョンはすぐ上がるので
last 1 version
みたいに固定値で書かない方がいいらしい
polyfill
- core-js
- 新しいES記法のポリフィル
- regenerator-runtime
- IE11などで、async functionを使うためのもの
Since @babel/plugin-transform-runtime includes a polyfill that includes a custom regenerator-runtime and core-js,
https://webpack.js.org/loaders/babel-loader/#note-transform-runtime--custom-polyfills-eg-promise-library
@babel/plugin-transform-runtime は、独自の regenerator-runtime と core-js を含むポリフィルを提供します。
今は別のライブラリに切り出されてるのかな

plugin
- Loaderはファイルをトランスパイルしたりする、webpackの元々の目的の機能
- Pluginは広義の機能拡張のこと
- MiniCssExtractPlugin:cssは分離してビルドする
- HtmlWebpackPlugin:htmlに埋め込むjsの名前を動的にして注入する、minifyもしてくれる

HTMLにも画像名を動的に読ませる
html-loaderとHtmlWebpackPluginで設定
処理順番的には下記らしい
- html-loaderでhtmlを読む
- 依存関係に存在するファイルを探しにいく
- file-loaderでファイルを生成する

Minify
mode=productionだとjsのminifyがデフォルトでされてる
- js
- terser-webpack-plugin - css
- optimize-css-assets-webpack-plugin
- css-minimizer-webpack-plugin ← webpack v5以降はこっちらしい
- html
- HtmlWebpackPluginに設定を渡せばできる

webpack-dev-server
webpack-dev-serverでサーバーを立ち上げたり、watchでファイルの変更を検知したりできる

SplitChunks
何度もつかうjQueryみたいなライブラリや、共通utilsなんかは何度もバンドルすると無駄
なので、cacheGroupに登録して、別ファイルとして分割すると良い
下記は、app.jsとは別にファイルを分割する例
-
node_modules
-> vender.jsとして生成 - utilディレクトリ -> utils.jsとして生成
optimization: {
splitChunks: {
chunks: 'all',
minSize: 0,
cacheGroups: {
vendors: {
name: "vendors",
test: /node_modules/,
priority: -10
},
utils: {
name: "utils",
test: /src[\\/]utils/,
},
default: false
}
}
},
- chunksの指定方法によっては、非同期に読み込むファイルを指定できる
- allは全てを分割する指定
- asyncを指定すると、初期ロード時には読まれない
- initialはasyncの逆で、同期的なものをバンドルする、非同期は分割

Resolve
ディレクトリにエイリアスを作る機能
- aliasはそのまま
- jsで使う場合は書いた通りに使える
- scssなどでは
~
をつける<img src="~images/webpack-logo.svg" width="100">
- extentionsは拡張子の省略を可能にする
- modulesはnode_modulesや他のディレクトリの関数を参照できるようにパスを通す

jsconfig.json
VSCodeにパスを通す機能
webpackでmodulesやaliasを登録しただけでは補完が効かないので設定が必要

udemyを見た後だと完全に理解できた(?)