摘要:中在性能優化所做的努力,也大抵圍繞著這兩個大方向展開。因此,將依賴模塊從業務代碼中分離是性能優化重要的一環。大型庫是否可以通過定制功能的方式減少體積。這又違背了性能優化的基礎。接下來可以抓住一些細節做更細的優化。中,為默認啟動這一優化。
前言:在現實項目中,我們可能很少需要從頭開始去配置一個webpack 項目,特別是webpack4.0發布以后,零配置啟動一個項目成為一種標配。正因為零配置的webpack對項目本身提供的“打包”和“壓縮”功能已經做了優化,所以實際應用中,我們可以把精力更多專注在業務層面上,而無需分心于項目構建上的優化。然而從學習者的角度,我們需要了解webpack在項目的構建和打包壓縮過程中做了哪些的優化,以及在原有默認配置上,還可以做哪些性能方面上的改進。一,優化的方向 1.1 項目開發
???????最近在完成vue的單頁面應用后萌生了一個想法,拋棄掉vue-cli的構建配置,從零開始進行webpack優化,并將過程中的思路和體會分享在這篇文章中。webpack的初始配置在我之前寫的另一篇手把手教你從零認識webpack4.0文章中,以下內容也不對基本的webpack配置做過多闡述。
???????對開發者而言,我們希望webpack這個工具可以給我們帶來流暢的開發體驗。比如,當不斷修改代碼時,我們希望代碼的變更能及時的通知瀏覽器刷新頁面,而不是手動去刷新頁面。更進一步的我們希望,代碼的修改只會局部更換某個模塊,而不是整個頁面的刷新。這樣可以使我們不需要在等待刷新中浪費很多時間,大大提高了頁面的開發效率。
1.2 項目部署???????項目部署上線時,性能優化是我們考慮的重點,有兩個方向可以作為核心考慮的點,一個是減少HTTP請求,我們知道在網速相同的條件下,下載一個100KB的圖片比下載兩個50KB的圖片要快,因此,我們要求webpack將多個文件打包成一個或者少量個文件;另一個優化的重點是減少單次請求的時間,也就是盡可能減少請求文件的體積大小。
???????webpack中在性能優化所做的努力,也大抵圍繞著這兩個大方向展開。另外在構建項目中,我們也希望能持續的提高構建效率。
開發環境下,我們依然對代碼的體積有一定的要求,更小的體積可以讓加載速度更快,開發效率更高,當然配置也相對簡單。
// webpack.dev.js 開發環境webpack配置 module.exports = { devServer: { contentBase: path.join(__dirname, "dist"), port: 9000, compress: true, // 代碼壓縮 }, }2.2 模塊熱更新(HMR)
開發過程中,我們希望修改代碼的過程中,頁面能實時且不需要手動的刷新。因此使用HRM, HMR 既避免了頻繁手動刷新頁面,也減少了頁面刷新時的等待,大幅度提高了開發效率。
// webpack.dev.js module.exports = { devServer: { compress: true, hot: true // 開啟配置 }, plugins: [ new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin(), ], }三,構建體積優化 3.1 生產中的sourcemap 模式
webpack 在構建中提供了不少于7種的sourcemap模式,其中eval模式雖然可以提高構建效率,但是構建后的腳本較大,因此生產上并不適用。而source-map 模式可以通過生成的 .map 文件來追蹤腳本文件的 具體位置,進而縮小腳本文件的體積,這是生產模式的首選,并且在生產中,我們需要隱藏具體的腳本信息,因此可以使用 cheap 和module 模式來達到目的。
綜上,在生產的webpack devtool選項中,我們使用 cheap-module-source-map的配置
// webpack.pro.js 生產webpack配置腳本 module.exports = { mode: "production", devtool: "cheap-module-source-map", }3.2 獨立css 文件
以單入口文件而論,通常我們會將頁面的所有靜態資源都打包成一個JS 文件,這已經實現了1.2 中的優化部分,將代碼合并成一個靜態資源,減少了HTTP 請求。
但是接下來,我們需要將css代碼獨立開來,為什么呢?最主要的一點是我們希望更好的利用瀏覽器的緩存,當多帶帶修改了樣式時,獨立的css文件可以不需要應用去加載整個的腳本文件,提高效率。并且,當遇到多頁面的應用時,可以多帶帶將一些公共部分的樣式抽離開來,加載一個頁面后,接下來的頁面同樣可以利用緩存來減少請求。
webpack4.0 中提供了抽離css文件的插件,mini-css-extract-plugin,只需要簡單的配置便可以將css文件分離開來
const MiniCssExtractPlugin = require("mini-css-extract-plugin") module.exports = { ··· plugins: [ new MiniCssExtractPlugin({ filename: "[name].[contenthash].css", chunkFilename: "[name].[contenthash].css" }) ], module: { rules: { test: /.(css|scss)$/, use: [process.env.NODE_ENV == "production" ? MiniCssExtractPlugin.loader : "style-loader", { loader: "css-loader", options: { sourceMap: true }, }, "sass-loader"] } } ··· }
要想優化構建后的體積,不斷減少靜態資源文件的大小,我們希望webpack幫助我們盡可能壓縮文件的體積。對于js 腳本文件而言,webpack4.0 在mode 為‘production’時,默認會啟動代碼的壓縮。除此之外,我們需要手動對html和css 進行壓縮。
???????針對html 的壓縮,只需要對html-webpack-plugin進行相關配置。
// webpack.base.js module.exports = { plugins: [ new HtmlWebpackPlugin({ title: "minHTML", filename: "index.html", template: path.resolve(__dirname, "../index.html"), minify: { // 壓縮 HTML 的配置 collapseWhitespace: true, removeComments: true, useShortDoctype: true } }), ] }
???????針對css 的壓縮, webpack4.0 使用optimize-css-assets-webpack-plugin來壓縮多帶帶的css 文件。
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); module.exports = { plugins: [ new OptimizeCSSAssetsPlugin() ], }
對比之下,我們可以看到明顯的效果,關于壓縮css 更多的配置可以參考optimize-css-assets-webpack-plugin
處理完前端的三大塊js,html,css后, 接下來優化能想到的是處理圖片。前面提到,提升性能的一個重要的條件是降低http請求數,而應用中經常會有大大小小的圖片需要處理,對應用中的小圖標來說,css sprite 是首選,將各種圖標集合成一張大的圖片可以很好的減少網絡請求數。而對于需要獨立開的圖片,且大小在合理范圍內時,我們可以將圖片轉換成 base64位編碼,內嵌到css 中,同樣可以減少請求。
處理圖片資源時,webpack 提供了 file-loader 和url-loader 兩個loaders供選擇,file-loader 和url-loader 的作用,可以用來解析項目中圖片文件的url引入問題。兩者的區別在于,url-loader 可以將小于指定字節的文件轉為DataURL, 大于指定字節 的依舊會使用file-loader 進行解析
// webpack.base.js module.exports = { module: { rules: [{ test: /.(png|jpe?g|gif|svg|ttf|woff2|woff)(?.*)?$/, use: [{ loader: "url-loader", options: { limit: 10000, // 限制大小 } }, ] }, }
處理完雪碧圖和小圖片的base64轉換后,對于大圖片來說,webpack還可以做到對圖片進行壓縮,推薦使用image-webpack-loader,插件提供了多種形式的壓縮,詳細可以參考官網文檔
// webpack.base.js module.exports = { module: { rules: [ { loader: "image-webpack-loader", options: { optipng: { // 使用 imagemin-optipng 壓縮 png,enable: false 為關閉 enabled: true, }, pngquant: { // 使用 imagemin-pngquant 壓縮 png quality: "65-90", speed: 4 }, } } ] } }
效果對比如下:
一個中大型應用中,第三方的依賴,龐大得可怕,占據了打包后文件的一半以上。然而,這些依賴模塊又是很少變更的資源,和css 代碼分離的邏輯相似,分離第三方依賴庫,可以更好的利用瀏覽器緩存,提升應用性能。因此,將依賴模塊從業務代碼中分離是性能優化重要的一環。
webpack4.0 中,依賴庫的分離只需要通過 optimization.splitChunks 進行配置即可。
// webpack.pro.js module.exports = { optimization: { splitChunks: { cacheGroups: { vendor: { chunks: "initial", test: path.resolve(__dirname, "../node_modules"), name: "vendor", // 使用 vendor 入口作為公共部分 enforce: true, }, }, }, }, }
公共庫分離后的結果
正如前面所講,在優化分析中,實際影響體積最大的是 node_modules 的第三方庫,這一部分的優化可以大大的減少打包后的體積。這里我們使用最新的webpack-bundle-analyzer插件來分析打包好后的模塊,它可以將打包后的內容束展示位方便交互的直觀樹狀圖,通過它,可以知道項目大致有哪些模塊組成,哪個模塊占據的體積較大,是否是可替代的。
我們大致可以從幾個方向考慮
1.判斷依賴是否不可或缺,依賴在項目中使用率是否過低。在項目中,可能針對某個運算,某個功能,我們使用了一個龐大的庫,這個庫在體積上的占比較大,而功能使用卻較少。這個時候我們可以尋找體積更小,且功能滿足的替換庫,或者手動實現某些依賴的功能來替換他。
2.大型庫是否可以通過定制功能的方式減少體積。明顯的一個例子是 echart, echart完全版的依賴壓縮后也有幾百k 之多,這顯示是難以接受的?,F實項目中,我們可能只需要少量或者部分的echart 功能,這時我們可以通過制定圖表的形式,下載圖表用到的功能,達到體積最優化。
3.某些不可優化的大型庫是否可以通過外部引用的方式減少文件體積。例如像bootstrap,vue這類無法優化的第三方庫,通過免費開源的cdn服務不但可以減少文件體積,還可以提高網站的加載速度,也是個優化性能的方法
3.7 按需加載前面提到依賴分析的方向中,如果大型庫不可或缺,而且使用率也不算低的時候,我們可以通過按需加載的形式。這種方式實際上是先把你的代碼在一些邏輯斷點處分離開,然后在一些代碼塊中完成某些操作后,立即引用或即將引用另外一些新的代碼塊。這樣加快了應用的初始加載速度,減輕了它的總體體積,因為某些代碼塊可能永遠不會被加載。
webpack中利用require.ensure()實現按需加載,在不使用按需加載的情況下,首屏加載時會把所有的腳本同時加載出來,這往往會拖累首屏顯示時間,帶來不好的用戶體驗。例子來說。當項目需要使用大型的圖表類庫,而首頁并不需要時,按需加載往往比同時加載在用戶體驗上好好得多。
當不需要按需加載的時候,我們的代碼可能是這樣的:
import test from "./components/test.vue" import test2 from "./components/test2.vue"
開啟按需加載時,我們的代碼修改為:
const test = r => require.ensure([], () => r(require("./components/test.vue")), "chunk1") const test2 = r => require.ensure([], () => r(require("./components/test2.vue")), "chunk2")
webpack 配置修改為
output: { ··· chunkFilename: "[name].[hash].js" }
這時編譯出來的文件會從原來的一個,變成了多個小文件。每個路由加載時會去加載不同的資源。特別在首屏的資源加載上進一步優化了應用的體驗。
盡管如此,實際中我們需要根據項目的需求來衡量按需加載的可用性,盡管在首屏優化上取得較大的提升,但按需加載畢竟會將大的文件拆分成多個小文件,增加了http 的請求數。這又違背了性能優化的基礎。所以實際中需要取舍,更需要權衡。
3.8 刪除冗余代碼代碼體積優化到這一步,基本可以優化的地方已經優化完畢了。接下來可以抓住一些細節做更細的優化。比如可以刪除項目中上下文都未被引用的代碼。這就是所謂的 Tree shaking 優化。webpack 4.0中,mode 為production 默認啟動這一優化。但是,如果在項目中使用到babel的 話,需要把babel解析語法的功能關掉。只需要
// .babelrc { "presets": [["env", { "modules": false }]] }四,構建速度優化
說完如何減少項目構建后的大小后,接下來簡單的談一下如何提高構建的速度。實際上webpack的 構建速度,只需要簡單的修改配置便能大幅提高速度。常見的設置如下。
4.1 babel-loader構建時間過長由于babel-loader需要將語法進行轉換,所耗費的時間較長,所以第一步需要限定babel-loader 作用的范圍,讓babel-loader 的搜索和轉換準確的定位到指定模塊。大幅提高構建速度。
例如:
// webpack.base.js module.exports = { module:{ rules: [ { test: /.js$/, include: [resolve("src")],// 限定范圍 use: { loader: "babel-loader", }, },] } }
正因為babel-loader在解析轉換上耗時太長,所以我們希望能緩存每次執行的結果。webpack的loader中剛好有 cacheDirectory 的選項,默認為false 開啟后將使用緩存的執行結果,打包速度明顯提升。
// webpack.base.js module.exports = { module: { rules: [ { test: /.js$/, include: [resolve("src")], use: { loader: "babel-loader?cacheDirectory", }, },] } }4.2 resolve 解析優化
webpack 的resolve 做相關的配置后,也可以讓項目的構建速度加快。具體看下文的配置:
當項目中出現 import "react" 既不是絕對路徑也不是相對路徑時,指定好搜索的路徑,可以不用過多的查詢
盡可能少的使用 resolve.alias 來設置路徑別名,因為會影響到tree shaking 的優化
后綴自動補全盡可能的少。減少路徑查詢的工作
當使用的第三方庫過大,并且不包含import require define 的調用。可以使用noParse讓庫不被loaders 解析
// webpack.base.js module.exports = { resolve: { modules: [ path.resolve(__dirname, "node_modules"), ], extensions: [".js"], // 避免新增默認文件,編碼時使用詳細的文件路徑,代碼會更容易解讀,也有益于提高構建速度 mainFiles: ["index"], }, module: { noParse: function(content){ return /jquery/.test(content) } } }五,結語
webpack性能優化的瓶頸還是集中在構建時間和構建體積上,作為構建工具業界霸主,webpack一直不停的優化構建打包流程。通過對舊有項目的優化也可以對webpack這個工具以及性能優化的知識有更深的了解。
轉載請注明出處 https://blog.csdn.net/yuanyan...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108794.html
摘要:后來經過排查你會發現是由于目前還沒有版本。可以使用該方式解決。這就是我為什么不推薦你使用創建腳手架的原因此文的受眾是想要進階中級的初級前端人員。 最近在知乎看到一個問題,原問題如下: 很奇怪,為什么現在能找到自己手動創建vue腳手架的文章非常少,而且大家似乎對webpack4的熱情并不高,對于想基于vue2.0+webpack4搭建一個腳手架的我來說資料真是少得可憐。難道現在一般的做...
摘要:淺談網站性能之前端性能優化性能優化的目的無非是減少用戶流量消耗,提升用戶首屏體驗,提升用戶訪問速度,讓用戶專注內容本身。前端性能優化減少請求數量基本原理在瀏覽器與服務器進行通信時,主要是通過進行通信。 最近項目慢慢走上正軌,需求趨于平穩,這才想起需要對整站進行性能優化。經過一段時間的學習,結合現在項目的實際性能情況,發現確實有許多地方可以進行優化。于是就開始了我的前端性能優化之旅。以下...
摘要:淺談網站性能之前端性能優化性能優化的目的無非是減少用戶流量消耗,提升用戶首屏體驗,提升用戶訪問速度,讓用戶專注內容本身。前端性能優化減少請求數量基本原理在瀏覽器與服務器進行通信時,主要是通過進行通信。 最近項目慢慢走上正軌,需求趨于平穩,這才想起需要對整站進行性能優化。經過一段時間的學習,結合現在項目的實際性能情況,發現確實有許多地方可以進行優化。于是就開始了我的前端性能優化之旅。以下...
摘要:我們發布了新版本的插件系統,以便事件掛鉤和處理程序是單態的。倒計時按照承諾,我們將從今天開始等待一個月,然后再釋放穩定版。這為我們的插件,加載程序和集成生態系統提供了測試,報告和升級到的時間我們需要您幫助我們升級并測試此測試版。 自8月初以來—當我們將 nex branch?合并到webpack/webpack#master—我們看到了巨大的貢獻! showImg(https://se...
摘要:默認出入口在中,不再強制要求指定和路徑。構建模式提供了兩種構建模式可供選擇和選項描述會將的值設為。如果是,那就會開啟。默認只會對按需加載的代碼做分割。在或更低版本中,如果你想為一個推導出來的定制選項,你不得不在自己的選項中將它重復一遍。 前言 現在距離2018年2月15號webpack4.0.0出來已經有一段時間了,現在已經出了 @vue/cli 3.0,但是樓主還沒試過,聽說很強大,...
閱讀 3967·2021-11-16 11:44
閱讀 5189·2021-10-09 09:54
閱讀 2030·2019-08-30 15:44
閱讀 1678·2019-08-29 17:22
閱讀 2753·2019-08-29 14:11
閱讀 3389·2019-08-26 13:25
閱讀 2324·2019-08-26 11:55
閱讀 1595·2019-08-26 10:37