# Webpack # 時空背景,SPA越來越熱門,導致前端要管理的js越來越多,而js會根據前端元件或功能分成許多檔案方便開發管理,但瀏覽器同時載入時會造成網路連線效能不好,且某些js檔案有執行順序的要求。 # 主要目的是為了將許多js檔在正確執行順序的同時轉成單一js檔,而ES6轉ES5及CSS bundle等為額外功能 ![](https://i.imgur.com/e4fjXR7.png) # Module System ![](https://i.imgur.com/W1ejeOO.png) # 建立webpack.config.js,output的path必須是絕對路徑 ![](https://i.imgur.com/bYF2eUR.png) # package.json scripts修改 ![](https://i.imgur.com/O3XYYMF.png) # bundle後檔案大小反而變大 ![](https://i.imgur.com/mcgT0xy.jpg) # 產生的bundle.js ![](https://i.imgur.com/v14Nq9J.jpg) # 其實大概長這樣,和一些處理優化等功能 ![](https://i.imgur.com/oH9i8U1.png) # Babel with Webpack ![](https://i.imgur.com/PQT3jKg.png) ![](https://i.imgur.com/gyyj65B.png) ![](https://i.imgur.com/4jdMziY.png) ![](https://i.imgur.com/b1x25ry.png) # Webpack 1使用loaders,而Webpack2使用module rules設定loader ![](https://i.imgur.com/56eroQp.png) # 建立.babelrc指定presets ![](https://i.imgur.com/F7WLiHi.png) # 將CommonJS改為ES2015測試能否正確執行 ![](https://i.imgur.com/RO1Mk2Z.png) # CSS with Webpack ![](https://i.imgur.com/mjRyGdl.png) ![](https://i.imgur.com/NBDmuAZ.png) ![](https://i.imgur.com/SFOI2cq.png) # css loader的use陣列順序是有差的,會從最後面的css-loader開始執行 ![](https://i.imgur.com/3GbsRAk.png) # 預設css會透過js直接包成style塞進head中,而不是另外包成css檔引入 ![](https://i.imgur.com/O2EHFus.png) # 將全部css包成css檔引入 ![](https://i.imgur.com/iX5ERQN.png) # use其實就是loader ![](https://i.imgur.com/3nqGA4o.png) ![](https://i.imgur.com/2HNsn71.png) ![](https://i.imgur.com/9QoO6RW.png) # plugins和loaders的差別 https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/308 ![](https://i.imgur.com/g4qVV86.png) # 常見的plugins https://ithelp.ithome.com.tw/articles/10185569 ![](https://i.imgur.com/me0UXQi.png) # Image with Webpack resize應該用壓縮比較好 ![](https://i.imgur.com/uWJNkNN.png) ![](https://i.imgur.com/pIQMcr3.png) # url-loader和file-loader的差別 ![](https://i.imgur.com/UmOGDXO.png) 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; ``` ![](https://i.imgur.com/0bG4fBb.png) ![](https://i.imgur.com/vRYBwzV.png) # 添加publicPath防止圖片等資源路徑錯誤 ![](https://i.imgur.com/idFXswA.png) ![](https://i.imgur.com/SSLZmgf.png) # 更新:publicPath應該設為"",以html為相對目錄,避免webpack-dev-server失敗 ![](https://i.imgur.com/lpePDgz.png) ![](https://i.imgur.com/AvKL7he.png) ![](https://i.imgur.com/q5guhgI.png) https://stackoverflow.com/questions/39833239/how-to-change-webpack-dev-server-output-publicpath-relative-to-root # Code Splitting ![](https://i.imgur.com/KZ9Eche.png) ![](https://i.imgur.com/1FImrRT.png) ![](https://i.imgur.com/K5Qeddc.png) ![](https://i.imgur.com/DYfrFUQ.png) # System.import,新版Webpack為import就好 ![](https://i.imgur.com/XQ11u1N.png) ![](https://i.imgur.com/Sp7UQyT.png) ![](https://i.imgur.com/4lhvT5f.png) # 有export dafault的話要另外呼叫default ![](https://i.imgur.com/YG2DeI1.png) ![](https://i.imgur.com/WWJILTX.png) ![](https://i.imgur.com/eOGZxpC.png) # 沒有export dafault的話 ![](https://i.imgur.com/V3vvpW4.png) ![](https://i.imgur.com/b3llLsw.png) # Dynamic Imports產生的bundle ![](https://i.imgur.com/gdDHIi4.png) # 更多Code Splitting設定 https://webpack.docschina.org/guides/code-splitting/ https://webpack.js.org/guides/code-splitting/ # exclude避免node_modules不必要的轉換(原本就是ES5了) ![](https://i.imgur.com/GJybfXU.png) # vendor指第三方套件那些 ![](https://i.imgur.com/tK2IfI7.png) # 因為vendor更新頻率相比自己寫的code較低,且就算vendor更新我們也要主動套用(package.json),所以可以將vendor code給code split出來,透過瀏覽器cache減少使用者再次下載vendor code的時間 ![](https://i.imgur.com/GH1owXH.png) ![](https://i.imgur.com/JW7tRNc.png) # 將需要vendor的套件抽離出來,並且修改entry和filename ![](https://i.imgur.com/mkyLQX7.png) # 將bundle和vendor重複的modules抽取出來選擇放在vendor ![](https://i.imgur.com/8R4En4b.png) # 新版Webpack使用dependOn將共同的modules只放在dependOn指定的entry或optimization.splitChunks ![](https://i.imgur.com/A0RYXjG.png) https://webpack.docschina.org/guides/code-splitting/ # 使用html-webpack-plugin自動插入script link tag ![](https://i.imgur.com/7xgt2J3.png) # 若不指定template預設會自動產生基本的html ![](https://i.imgur.com/IfUQj7L.png) # Chunk Hashing for Cache Busting ![](https://i.imgur.com/ABCCK0r.png) ![](https://i.imgur.com/CAtc3TO.png) # 舊版Webpack需設定CommonsChunkPlugin ![](https://i.imgur.com/RCIrVMZ.png) # 新版Webpack需設定optimization.runtimeChunk ![](https://i.imgur.com/tOJaigq.png) ![](https://i.imgur.com/oCL7zCH.png) # 將Webpack的runtime code抽離成manifest.js ![](https://i.imgur.com/5OXYqDP.png) ![](https://i.imgur.com/TXb3a62.png) https://awdr74100.github.io/2020-04-06-webpack-splitchunksplugin/ ![](https://i.imgur.com/SEuPBjy.png) https://webpack.docschina.org/configuration/optimization/#optimizationruntimechunk # hash、chunkhash和contenthash的區別 ![](https://i.imgur.com/Iow4bx6.png) 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 ![](https://i.imgur.com/ga0GnTT.png) ![](https://i.imgur.com/TxDVWll.png) # 用webpack-dev-server進行開發,mode要設development才有只build剛剛儲存的檔案,其他沿用cache,production會全部重build # webpack-dev-server並不會將build完的檔案存到硬碟裡,而是存在記憶體中,所以只能開發使用 ![](https://i.imgur.com/FepkpCF.png) # webpack-dev-server --open或webpack serve --open,--open為自動開啟瀏覽器,新版Webpack可以devServer的open設為true ![](https://i.imgur.com/CNaqNQV.png) # devServer設定,因為webpack-dev-server產生的html js css等資源在記憶體中,所以static的publicPath要設為"",以html為相對目錄 ![](https://i.imgur.com/wZRiNRZ.png) ![](https://i.imgur.com/oD1MjJG.png) https://webpack.js.org/configuration/dev-server/ # 舊版React Router with Code Splitting # jsx改為純object,另外重複import若想重構成迴圈處理要小心,因為webpack是source code替換import的,不會先執行迴圈完再去搜尋import替換,要小心 ![](https://i.imgur.com/RyEeDdV.jpg) 改為 ![](https://i.imgur.com/EeOSdnR.png) ![](https://i.imgur.com/h7A495I.png) # 新版React Router可以使用webpack內建的import或react.lazy,另外要確保babel不會去轉換import語法導致webpack搜尋不到 ![](https://i.imgur.com/xcCL5w6.png) https://zh-hant.reactjs.org/docs/code-splitting. # Webpack production # 舊版webpack透過內建的DefinePlugin將process.env.NODE_ENV設為production,好讓react知道 ![](https://i.imgur.com/ndLVdr0.png) # scripts傳入NODE_ENV參數,webpack -p表示webpack為production(舊版,新版為設定mode屬性) ![](https://i.imgur.com/XVaqXFQ.png) # 新版webpack的prod環境(mode屬性)會自動配置DefinePlugin,所以只需要將mode設為production就好,並且會自動使用TerserWebpackPlugin壓縮 ![](https://i.imgur.com/JjbyqF6.png) https://webpack.docschina.org/guides/production#specify-the-mode ![](https://i.imgur.com/zDJhZGQ.png) https://zh-hant.reactjs.org/docs/optimizing-performance.html#webpack https://webpack.docschina.org/plugins/terser-webpack-plugin/ ![](https://i.imgur.com/WMLgJS6.png) https://webpack.docschina.org/guides/production/#minification # 新版Webpack根據環境拆分config,在scripts指定使用哪個config # 透過webpack-merge拆分common、dev、prod config ![](https://i.imgur.com/X0VpEtF.png) ![](https://i.imgur.com/5foDsdk.png) # 修改scripts ![](https://i.imgur.com/2TjsRZf.png) https://webpack.docschina.org/guides/production/ # Source Mapping https://webpack.docschina.org/guides/production#source-mapping https://juejin.cn/post/6960941899616092167 # 動態網頁(跟後端互動)有兩種方式,這裡實作第二種 ![](https://i.imgur.com/Bv4qWbF.png) ![](https://i.imgur.com/xMlhsPD.png) ![](https://i.imgur.com/JU0NqZ7.png) # prod就不需要webpack server了 ![](https://i.imgur.com/K2nPuH1.png) # 透過webpack-dev-middleware將webpack用express包起來,缺點是無法hot reload(可能是Windows的問題) ![](https://i.imgur.com/INYoRhE.png) # 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 ``` ![](https://i.imgur.com/ZhOwuz8.png)