# Webpack
# 時空背景,SPA越來越熱門,導致前端要管理的js越來越多,而js會根據前端元件或功能分成許多檔案方便開發管理,但瀏覽器同時載入時會造成網路連線效能不好,且某些js檔案有執行順序的要求。
# 主要目的是為了將許多js檔在正確執行順序的同時轉成單一js檔,而ES6轉ES5及CSS bundle等為額外功能

# Module System

# 建立webpack.config.js,output的path必須是絕對路徑

# package.json scripts修改

# bundle後檔案大小反而變大

# 產生的bundle.js

# 其實大概長這樣,和一些處理優化等功能

# Babel with Webpack




# Webpack 1使用loaders,而Webpack2使用module rules設定loader

# 建立.babelrc指定presets

# 將CommonJS改為ES2015測試能否正確執行

# CSS with Webpack



# css loader的use陣列順序是有差的,會從最後面的css-loader開始執行

# 預設css會透過js直接包成style塞進head中,而不是另外包成css檔引入

# 將全部css包成css檔引入

# use其實就是loader



# plugins和loaders的差別
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/308

# 常見的plugins
https://ithelp.ithome.com.tw/articles/10185569

# Image with Webpack
resize應該用壓縮比較好


# url-loader和file-loader的差別

https://v4.webpack.js.org/loaders/url-loader/
https://awdr74100.github.io/2020-03-09-webpack-urlloader-fileloader/
# 因舊版Webpack安裝url-loader遇到困難,所以統一使用最新的Webpack 5,並將許多套件更新和修改webpack.config.js,另外也刪除.babelrc
```
"devDependencies": {
"@babel/core": "^7.19.6",
"@babel/preset-env": "^7.19.4",
"babel-loader": "^9.0.0",
"css-loader": "^6.7.1",
"file-loader": "^6.2.0",
"image-webpack-loader": "^8.1.0",
"mini-css-extract-plugin": "^2.6.1",
"style-loader": "^3.3.1",
"url-loader": "^4.1.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
}
```
webpack.config.js
```
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js",
},
module: {
rules: [
{
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
test: /\.js$/,
},
// {
// use: ["style-loader", "css-loader"],
// test: /\.css$/,
// },
{
use: [MiniCssExtractPlugin.loader, "css-loader"],
test: /\.css$/,
},
{
use: [
{
loader: "url-loader",
options: {
limit: 40000,
},
},
"image-webpack-loader",
],
test: /\.(jpe?g|png|gif|svg)$/,
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "style.css",
}),
],
};
module.exports = config;
```


# 添加publicPath防止圖片等資源路徑錯誤


# 更新:publicPath應該設為"",以html為相對目錄,避免webpack-dev-server失敗



https://stackoverflow.com/questions/39833239/how-to-change-webpack-dev-server-output-publicpath-relative-to-root
# Code Splitting




# System.import,新版Webpack為import就好



# 有export dafault的話要另外呼叫default



# 沒有export dafault的話


# Dynamic Imports產生的bundle

# 更多Code Splitting設定
https://webpack.docschina.org/guides/code-splitting/
https://webpack.js.org/guides/code-splitting/
# exclude避免node_modules不必要的轉換(原本就是ES5了)

# vendor指第三方套件那些

# 因為vendor更新頻率相比自己寫的code較低,且就算vendor更新我們也要主動套用(package.json),所以可以將vendor code給code split出來,透過瀏覽器cache減少使用者再次下載vendor code的時間


# 將需要vendor的套件抽離出來,並且修改entry和filename

# 將bundle和vendor重複的modules抽取出來選擇放在vendor

# 新版Webpack使用dependOn將共同的modules只放在dependOn指定的entry或optimization.splitChunks

https://webpack.docschina.org/guides/code-splitting/
# 使用html-webpack-plugin自動插入script link tag

# 若不指定template預設會自動產生基本的html

# Chunk Hashing for Cache Busting


# 舊版Webpack需設定CommonsChunkPlugin

# 新版Webpack需設定optimization.runtimeChunk


# 將Webpack的runtime code抽離成manifest.js


https://awdr74100.github.io/2020-04-06-webpack-splitchunksplugin/

https://webpack.docschina.org/configuration/optimization/#optimizationruntimechunk
# hash、chunkhash和contenthash的區別

https://ithelp.ithome.com.tw/articles/10200454
https://blog.51cto.com/u_14115828/3733990
https://webpack.docschina.org/guides/caching/
# 修改Dynamic Import的檔案vendor的chunkhash也會改變
# 使用rimraf清除整個build資料夾,或使用clean-webpack-plugin,新版Webpack可以將clean設為true


# 用webpack-dev-server進行開發,mode要設development才有只build剛剛儲存的檔案,其他沿用cache,production會全部重build
# webpack-dev-server並不會將build完的檔案存到硬碟裡,而是存在記憶體中,所以只能開發使用

# webpack-dev-server --open或webpack serve --open,--open為自動開啟瀏覽器,新版Webpack可以devServer的open設為true

# devServer設定,因為webpack-dev-server產生的html js css等資源在記憶體中,所以static的publicPath要設為"",以html為相對目錄


https://webpack.js.org/configuration/dev-server/
# 舊版React Router with Code Splitting
# jsx改為純object,另外重複import若想重構成迴圈處理要小心,因為webpack是source code替換import的,不會先執行迴圈完再去搜尋import替換,要小心

改為


# 新版React Router可以使用webpack內建的import或react.lazy,另外要確保babel不會去轉換import語法導致webpack搜尋不到

https://zh-hant.reactjs.org/docs/code-splitting.
# Webpack production
# 舊版webpack透過內建的DefinePlugin將process.env.NODE_ENV設為production,好讓react知道

# scripts傳入NODE_ENV參數,webpack -p表示webpack為production(舊版,新版為設定mode屬性)

# 新版webpack的prod環境(mode屬性)會自動配置DefinePlugin,所以只需要將mode設為production就好,並且會自動使用TerserWebpackPlugin壓縮

https://webpack.docschina.org/guides/production#specify-the-mode

https://zh-hant.reactjs.org/docs/optimizing-performance.html#webpack
https://webpack.docschina.org/plugins/terser-webpack-plugin/

https://webpack.docschina.org/guides/production/#minification
# 新版Webpack根據環境拆分config,在scripts指定使用哪個config
# 透過webpack-merge拆分common、dev、prod config


# 修改scripts

https://webpack.docschina.org/guides/production/
# Source Mapping
https://webpack.docschina.org/guides/production#source-mapping
https://juejin.cn/post/6960941899616092167
# 動態網頁(跟後端互動)有兩種方式,這裡實作第二種



# prod就不需要webpack server了

# 透過webpack-dev-middleware將webpack用express包起來,缺點是無法hot reload(可能是Windows的問題)

# dev和prod環境
# prod deploy之前要先build
# server routes必須在app.get('*')之前,不然會無效
# 有些providers會自動設NODE_ENV=production,例如Heroku,AWS就不會,所以要手動設
dev
```
node server.js
```
prod
```
NODE_ENV=production node server.js
```
