中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

webpack學習教程之前端性能優化總結

發布時間:2020-10-20 22:44:34 來源:腳本之家 閱讀:170 作者:前端小豪 欄目:web開發

前言

webpack學習教程之前端性能優化總結

曾幾何時,我們是如上圖的方式引入JS資源的,相信現在很少遇見了。近年來Web前端開發領域朝著規范開發的方向演進。體現在以下兩點:

1、MVC研發構架。多多益處(邏輯清晰,程序注重數據與表現分離,可讀性強,利于規避和排查問題...)

2、構建工具層出不窮。多多益處(提升團隊協作,以及工程運維,避免人工處理瑣碎而重復的工作)

  • 模塊化開發
  • 將前端性能優化理論落地,代碼壓縮,合并,緩存控制,提取公共代碼等
  • 其他的還包括比如你可以用ES 6 或CoffeeScript寫源碼,然后構建出瀏覽器支持的ES5

所以,前端這么好玩,如果還有項目沒有前后端分離的話,真的是守舊過頭了。

主流構建工具

市面上有許多構建工具,包括Grunt、Gulp、browserify等,這些和WebPack都是打包工具。但WebPack同時也具備以下特點:

相比Grunt,WebPack除了具備豐富的插件外,同時帶有一套加載(Loader)系統。使它支持多種規范的加載方式,包括ES6、CommonJS、AMD等方式,這是Grunt、Gulp所不具備的。

從代碼混淆的角度來看,WebPack更加的極致

代碼分片為處理單元(而不是文件),使得文件的分片更為靈活。

P.S.此處只做簡單的比較,不論孰優孰劣。其實工具都能滿足需求,關鍵是看怎么用,工具的使用背后是對前端性能優化的理解程度。

引言

最近在用webpack優化首屏加載性能,通過幾種插件之后我們上線前后的速度快了一倍,在此就簡單的分享下吧,先上個優化前后首屏渲染的對比圖。

webpack學習教程之前端性能優化總結

可以看到總下載時間從3800ms縮短到1600ms。

我們在用webpack時一般都會選擇多入口文件吧,為的就是將自己的源碼跟第三方庫代碼分離。這是之前的代碼,

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui','echarts']
},
output: {
 path: config.build.assetsRoot,
 filename: utils.assetsPath('js/[name].[chunkhash].js'),
 chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}

echarts非常大,所以打包時的vendor.js大概為1.2MB(經過gzip壓縮之后),而且首頁沒有用到echarts,所以我之后使用了externals將第三方庫以cdn的方式去引入,下面是優化過的代碼

entry: {
 entry: './src/main.js',
 vendor: ['vue', 'vue-router', 'vuex', 'element-ui']
 },
 // 這里的output為base中的output,不是生產的output
 output: {
 path: config.build.assetsRoot,
 filename: '[name].js',
 libraryTarget: "umd",
 publicPath: process.env.NODE_ENV === 'production' ?
  config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 externals: {
 echarts: 'echarts',
 _: 'lodash'
 },

webpack學習教程之前端性能優化總結

webpack學習教程之前端性能優化總結

這就是優化前后的對比。

然后我們要到html中以script標簽的形式去引externals中的cdn。之后就可以在相應的文件中import了,他的好處是不管你在多少vue文件中引用多少次,他都不會打包到所有的trunk(這里的trunk'指的是按需加載,一會詳細說明)中,這是用webpack-bundle-analyzer插件展示的效果。

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
new BundleAnalyzerPlugin({
  // 可以是`server`,`static`或`disabled`。
  // 在`server`模式下,分析器將啟動HTTP服務器來顯示軟件包報告。
  // 在“靜態”模式下,會生成帶有報告的單個HTML文件。
  // 在`disabled`模式下,你可以使用這個插件來將`generateStatsFile`設置為`true`來生成Webpack Stats JSON文件。
  analyzerMode: 'server',
  // 將在“服務器”模式下使用的主機啟動HTTP服務器。
  analyzerHost: '127.0.0.1',
  // 將在“服務器”模式下使用的端口啟動HTTP服務器。
  analyzerPort: 8888, 
  // 路徑捆綁,將在`static`模式下生成的報告文件。
  // 相對于捆綁輸出目錄。
  reportFilename: 'report.html',
  // 模塊大小默認顯示在報告中。
  // 應該是`stat`,`parsed`或者`gzip`中的一個。
  // 有關更多信息,請參見“定義”一節。
  defaultSizes: 'parsed',
  // 在默認瀏覽器中自動打開報告
  openAnalyzer: true,
  // 如果為true,則Webpack Stats JSON文件將在bundle輸出目錄中生成
  generateStatsFile: false, 
  // 如果`generateStatsFile`為`true`,將會生成Webpack Stats JSON文件的名字。
  // 相對于捆綁輸出目錄。
  statsFilename: 'stats.json',
  // stats.toJson()方法的選項。
  // 例如,您可以使用`source:false`選項排除統計文件中模塊的來源。
  // 在這里查看更多選項:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  logLevel: 'info' //日志級別。可以是'信息','警告','錯誤'或'沉默'。
 })

webpack學習教程之前端性能優化總結

webpack學習教程之前端性能優化總結

我們會看到,沒用externals和用了externals后所有的js中都不會出現類似echarts和lodash的庫出現(就算你import一萬次他都不會打包一次,厲害吧~~)。

對于externals再說兩點——

1.externals中的key是import中使用的

import lodash from "_";
import echarts from "echarts";

2.externals中的value是window下調用的

webpack學習教程之前端性能優化總結

然后我們再來聊聊為什么output使用trunkhash不用trunk,這是為了持久化緩存。簡單說下兩者的區別——

trunk:每次build之后的版本,就是說所有的build之后的文件hash值一致,比如我只改了一個文件,最后所有的文件hash都會變,這樣所有的文件都不會走cache,這樣緩存就失去了意義。

trunkhash:根據每個文件生成不同的hash值,當文件變化時hash會改變且只會改變相應的文件

然后我們肯定是要用到CommonsChunkPlugin,這個插件是用來抽取公共代碼的,基本上99%的配置都是長這樣子或者類似這樣子用兩個不同的commonschunkPlugin,但這從某方面來說并沒有實現真正意義上的持久化緩存,這個一會我會通過webpack打包原理來詳細解釋其中的原因。。。。。。

new webpack.optimize.CommonsChunkPlugin({
 names: ['vendor','manifest']
})

在沒用這個插件之前,我們的main.js和vendor.js會是這樣子。。。

webpack學習教程之前端性能優化總結

大家會看到我們這兩個文件會有公共的部分,比如vue和element-ui,所以我們要抽取公共代碼到vendor中,所以我們可以先這樣配置

new webpack.optimize.CommonsChunkPlugin({
 name: 'vendor',
}),

但這樣的話雖然可以提取公共代碼,但我們會把runtime(webpack運行時的代碼,一會在打包原理中會再次提到)也放到vendor中,這里面會維護一個trunk的文件列表,類似于這樣,就是說我們改任意的代碼,這個table里面的hash會變,所以vendor的hash也會變

,所以這沒有實現真正的持久化緩存。這個hash table是按需緩存的打包出來的trunk包,一般都是通過require.ensure(就是vue-router中配置的page對應頁面,按需加載)

webpack學習教程之前端性能優化總結

所以我們就把name改為names,就是上面那個配置。因為使用這個插件,我們會把公共代碼抽到第一個name中,把runtime放到最后一個name中,也就是我們所謂的“manifest”文件。

并且這個文件會比較小,通常都是2kb左右,所以build后會生成一個script標簽,但這樣的話就多了一個http請求,所以我們可以用另外一個插件(InlineManifestWebpackPlugin)將manifest.js內聯進去。就會長這樣子

webpack學習教程之前端性能優化總結

再回到我們的CommonsChunkPlugin,現在我們隨便改任何已存在的文件,vendor.js的hash都不會變,是的,貌似這就實現了持久化緩存。但是當我們新增一個模塊,并且在入口文件中import一下,我們的vendor就會跟main一起變。很奇怪對吧,我們明明已經做了自己的源碼跟第三方庫分離,為什么vendor還會變(到現在應該沒有任何一篇博客對此進行詳細的說明)。下面我就詳細的給大家解釋下我的看法,如果大家發現有不對的地方還請指正。

再解釋為什么之前,我們先簡單了解下webpack的打包規則。

webpack一個entry對應一個bundle,這個bundle包括入口文件和其依賴的模塊。其他按需加載的則打包成其他的bundle。還有一個比較重要的文件時manifest,它是最先加載的,負責打包其他的bundle并按需加載和執行。

manifest是一個自執行函數,熟悉angular的同學看第一行應該很了解,因為anguar1.3版本的源碼中啟動就是angular.bootstrap,對,這里也是一樣。里面的modules變量就是對應模塊函數,它是webpack處理的基本單位,就是說對應打包前的一個文件

webpack學習教程之前端性能優化總結

這是js源文件,

webpack學習教程之前端性能優化總結

webpack學習教程之前端性能優化總結

這是打包后的文件,

webpack學習教程之前端性能優化總結

所有的模塊函數索引都是連續的(每個js文件生成一個trunkid!!!!!),像這種 /* 4 */ 對應的就是js文件,他通過打包就變成了一個個trunkid,仔細看會看到咱們打包前js文件里的export和require依賴都會統一轉換成webpack模塊。咱們說的webpackJsonp就是除manifest之外打包其他的文件的函數體。

簡單說下main吧,這個圖的trunkid是連續的,為了在一張圖上顯示,我截掉了trunk3-7.

webpack學習教程之前端性能優化總結

這里面一共有三個參數,第一個是我當前文件的trunkid,它是唯一標識符,就是指main的trunkid,第二個就是打包的所有文件的模塊函數,第三個是我要立即執行的trunkid模塊函數。

ok,介紹這些就足夠了。

然后我們再回過頭來看看為什么我們所謂的commonschunkPlugin會變。剛才說過,有幾個js就有幾個trunkid。

所以當我們新加一個js并引入到main入口時,webpack再次打包,我的main文件會多一個模塊函數,剛剛說過trunkid是依次遞增的而且不會重復。所以對應的vendor的id會+1,就是這么細微的變化導致hash變了。

webpack學習教程之前端性能優化總結

webpack學習教程之前端性能優化總結

webpack學習教程之前端性能優化總結

大家仔細看,這兩個vendor都是10272行,唯一的不同就是我要自執行這個vendor庫,這里我引用的jquery,所以這個文件只有jquery,自執行肯定要有模塊函數,trunkid+1,所以hash會變。我們再好好回憶一下,其實這也說明了這個插件的意義,我就是要抽出公共的庫,OK,這個插件做到了,但是因為webpack打包機制,不同文件生成不同turnkid,所以這是美中不足的一點。再回想一下,我們一般是不會隨便修改main.js的,所以從另一角度上來說這就是實現了持久化緩存。但我如果就是想保持vendor的hash不變要怎么辦呢?

webpack學習教程之前端性能優化總結

這段代碼就可以實現,沒錯,如果你對vue-cli了如指掌,這就是vue-cli的官方demo,至于為什么可以,這個我后續會跟大家解釋(實在是寫不動了。。。)。

最后再給大家介紹一個超級好用的東西,就是cdn。我們現在的需求是想讓圖片走cdn,讓js走線上路徑,但官方的解釋是通過修改config文件做cdn變化,這樣做的話我的所有輸出都會走cdn,那所有的ajax請求就跨域了呀。

webpack學習教程之前端性能優化總結

一開始我的解決方案是,在源文件中挨個替換,這樣會比較慢,更重要的是,cdn圖片也是有hash值的,當我以后替換圖片時,還得重新改相應的hash。有什么方法能讓他自動去獲取hash呢。

沒錯,我們需要在url-loader中單獨配置cdn,做到js訪問線上路徑,靜態資源使用cdn,兩者互不影響。

webpack學習教程之前端性能優化總結

簡單提醒一下,url-loader不能檢測到js中的background,所以我們凡是在js中引用的地址,必須在外面先import這張圖片,url-loader才會解析并打包。

今天就先到這里吧,改天繼續。。。。。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

苏州市| 织金县| 阿克苏市| 鹰潭市| 信丰县| 湘阴县| 简阳市| 南召县| 和顺县| 油尖旺区| 仁寿县| 永嘉县| 旬阳县| 宜春市| 英吉沙县| 海安县| 龙川县| 类乌齐县| 诸城市| 交城县| 广德县| 方城县| 固始县| 凤凰县| 八宿县| 丹寨县| 镇康县| 定西市| 宜宾县| 应城市| 文成县| 鸡东县| 达拉特旗| 河津市| 读书| 静海县| 托克逊县| 渝北区| 临武县| 建平县| 嘉峪关市|