1. <dd id="erndk"></dd>
                1. ??四年前端教你使用externals解決chunk-vendors.js過大問題

                  紅塵煉心 2020/6/14 11:25:41

                  本文用項目例子是用Vue Cli3搭建的Vue項目如果小伙伴有做過首屏加載時間優化,應該會遇到chunk-vendors.js這個文件,巨大無比,加載時間超長,是首屏加載時間過長的罪魁禍首之一。 下面通過一個實際的項目來演示,先通過插件webpack-bundle-analyzer來可視化地查看chunk-…

                  本文用項目例子是用Vue Cli3搭建的Vue項目

                  如果小伙伴有做過首屏加載時間優化,應該會遇到chunk-vendors.js這個文件,巨大無比,加載時間超長,是首屏加載時間過長的罪魁禍首之一。

                  下面通過一個實際的項目來演示,先通過插件webpack-bundle-analyzer來可視化地查看chunk-vendors.js這個文件里面地內容。

                  npm install webpack-bundle-analyzer --save-dev
                  復制代碼

                  在vue.config.js中引入這插件

                  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
                  module.exports={
                      configureWebpack:config =>{
                          return {
                              plugins:[
                                  new BundleAnalyzerPlugin()
                              ]
                          }
                      }
                  }
                  復制代碼

                  在上面的分析圖中我們可以看到,最大的兩個js文件,里面都是一些第三方依賴包,那么只要把這些依賴包提取出來,就可以解決chunk-vendors.js過大的問題。下面就教你使用externals來提取這些依賴包,其實應該說用externals來防止這些依賴包被打包。

                  externals的值是個對象,

                  module.exports={
                      configureWebpack:congig =>{
                          externals:{
                              key: value
                          }
                      }
                  }
                  復制代碼

                  其中key是第三方依賴庫的名稱,同package.json文件中的dependencies對象的key一樣。下圖紅框所示

                  其中value值可以是字符串、數組、對象。

                  說起externals,網上已經很多教程了,但是講解都不是很詳細,特別是對value值的講解。如果value值不正確導致的報錯,也不知道怎么去排查和修復。

                  按我的理解value值應該是第三方依賴編譯打包后生成的js文件,然后js文件執行后賦值給window的全局變量名稱。

                  那怎么找這個全局變量名稱呢,教你一個方法。

                  上面所說的js文件就是要用CDN引入的js文件。那么可以通過瀏覽器打開CDN鏈接。由于代碼是壓縮過,找個在線js格式化把代碼處理一下,就可以閱讀代碼了。

                  例如要提取element-ui這個依賴包。其CDN鏈接是unpkg.com/element-ui@…,格式化后代碼如下,是個自執行函數。

                  function(e, t) {
                      "object" == typeof exports && "object" == typeof module ? //判斷環境是否支持commonjs模塊規范
                      module.exports = t(require("vue")) :
                      "function" == typeof define && define.amd ? //判斷環境是否支持AMD模塊規范
                      define("ELEMENT", ["vue"], t) :
                      "object" == typeof exports ? //判斷環境是否支持CMD模塊規范
                      exports.ELEMENT = t(require("vue")) : 
                      e.ELEMENT = t(e.Vue)
                  } ("undefined" != typeof self ? self: this,function(e){
                      //省略...
                  });
                  復制代碼

                  從代碼可以看出element-ui是用UMD模塊規范輸出的,所以

                  • 兼容commonjs模塊規范(在node環境中使用)。
                  • 兼容AMD模塊規范(用require.js引入使用)。
                  • 兼容CMD模塊規范(用sea.js引入使用)。

                  代碼中對各個環境做了判斷,因為是用CDN在public/index.html引入,也就是瀏覽器環境,不符合上面各種環境,最后執行e.ELEMENT = t(e.Vue),其中e為window對象,那么賦值給window的全局變量名稱是ELEMENT。

                  在vue.config.js中配置如下

                  module.exports={
                      configureWebpack:{
                          externals: {
                              'element-ui': 'ELEMENT',
                          }
                      }
                  }
                  復制代碼

                  在public/index.html中引入

                  <body>
                      <div id="app"></div>
                      <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                  </body>
                  復制代碼

                  但是會發現報錯了。

                  回過來看e.ELEMENT = t(e.Vue),是不是發現還需要Vue。那么把Vue依賴包也提取出來。

                  Vue編譯打包生成js文件的CDN鏈接是cdn.bootcdn.net/ajax/libs/v…, 格式化后代碼如下,是個自執行函數。

                  function(t, e) {
                      "object" == typeof exports && "undefined" != typeof module ? 
                      module.exports = e() : 
                      "function" == typeof define && define.amd ? 
                      define(e) : 
                      (t = t || self).Vue = e()
                  } (this,function(){
                      //省略...
                  })
                  復制代碼

                  在瀏覽器中最后執行(t = t || self).Vue = e(),其中t為this,this是window對象。那么賦值給window的全局變量名稱是Vue。 在vue.config.js中配置如下

                  module.exports={
                      configureWebpack:{
                          externals: {
                              'element-ui': 'ELEMENT',
                              'vue': 'Vue',
                          }
                      }
                  }
                  復制代碼

                  在public/index.html中引入

                  <body>
                      <div id="app"></div>
                      <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
                  </body>
                  復制代碼

                  重新npm run dev后刷新頁面,發現還是報錯。

                  回到public/index.html,vue在element-ui后面引入,難怪會報錯,vue一定要在element-ui之前引入,修改一下

                  <body>
                      <div id="app"></div>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
                      <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                  </body>
                  復制代碼

                  刷新頁面,沒有報錯了。

                  這樣講解是不是很清晰了,知道value值是從哪里來的。遇到錯誤知道排查和修復。

                  接下來繼續把vue-router依賴和xlsx依賴提取了

                  vue-router編譯打包生成js文件的CDN鏈接是cdn.bootcdn.net/ajax/libs/v…, 格式化后代碼如下。

                   var t, e;
                   t = this,
                   e = function(){
                      //省略...
                   },
                    "object" == typeof exports && "undefined" != typeof module ? 
                    module.exports = e() : 
                    "function" == typeof define && define.amd ? 
                    define(e) : 
                    (t = t || self).VueRouter = e();
                  復制代碼

                  在瀏覽器中最后執行((t = t || self).VueRouter = e(),其中t為this,this是window對象。那么賦值給window的全局變量名稱是VueRouter。 在vue.config.js中配置如下

                  module.exports={
                      configureWebpack:{
                          externals: {
                              'element-ui': 'ELEMENT',
                              'vue': 'Vue',
                              'vue-router': 'VueRouter',
                          }
                      }
                  }
                  復制代碼

                  在public/index.html中引入

                  <body>
                      <div id="app"></div>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
                      <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                  </body>
                  復制代碼

                  重新npm run dev后刷新頁面,正常無報錯,繼續提取xlsx依賴包。

                  xlsx編譯打包生成js文件的CDN鏈接是cdn.bootcdn.net/ajax/libs/x…, 格式化后代碼如下。

                  var XLSX = {};
                  function make_xlsx_lib(e){
                      //省略...
                  }
                  if (typeof exports !== "undefined") make_xlsx_lib(exports);
                  else if (typeof module !== "undefined" && module.exports) make_xlsx_lib(module.exports);
                  else if (typeof define === "function" && define.amd) define(function() {
                      if (!XLSX.version) make_xlsx_lib(XLSX);
                      return XLSX
                  });
                  else make_xlsx_lib(XLSX);
                  var XLS = XLSX,
                  復制代碼

                  發現這下子不好判斷,賦值給window的全局變量名稱是那個了。先猜測是XLSX, 在public/index.html中引入

                  <body>
                      <div id="app"></div>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
                      <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js"></script>
                  </body>
                  復制代碼

                  把public/index.html這個文件丟到瀏覽器打開,然后在控制臺輸入window.XLSX,看看有沒有值。

                  有值不為undefined,說明賦值給window的全局變量名稱是XLSX。那么在vue.config.js中配置如下

                  module.exports={
                      configureWebpack:{
                          externals: {
                              'element-ui': 'ELEMENT',
                              'vue': 'Vue',
                              'vue-router': 'VueRouter',
                              'xlsx': 'XLSX'
                          }
                      }
                  }
                  復制代碼

                  重新npm run dev后刷新頁面,正常無報錯。

                  用externals提取第三方依賴包后,代碼原先引入依賴的地方,要不要去改動呢?比如main.js中

                  import ElementUI from 'element-ui';
                  Vue.use(ElementUI);
                  復制代碼

                  是可以不要去改動的,除非你把<script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>放在app.js后面引入。 在public/index.html中這么寫

                  <body>
                      <div id="app"></div>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
                      <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js"></script>
                  </body>
                  <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
                  復制代碼

                  編譯打包后,發現dist/index.html

                  <script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>已經放在app.js后面引入。

                  刷新瀏覽器,就發現報錯

                  只要你把main.js中去掉這段代碼就行。

                  import ElementUI from 'element-ui';
                  Vue.use(ElementUI);
                  復制代碼

                  刷新瀏覽器,無報錯。

                  網上很多教程都講到要把這段代碼去掉,不然會報錯,其實錯誤原因根本不在這里。

                  前面提到element-ui的CDN鏈接放在app.js后面引入,但是main.js里面代碼都會編譯打包到app.js中,執行app.js會遇到

                  import ElementUI from 'element-ui';
                  Vue.use(ElementUI);
                  復制代碼

                  由于你element-ui的CDN鏈接是放在app.js后面加載執行的,這時ElementUI是不存在的,當然會報錯的。

                  所以只要保證element-ui的CDN鏈接放在app.js之前加載的。就不會報錯。換句話來說只要在main.js需要引入的依賴,其CDN鏈接都要放在app.js之前加載,這樣就不要去改代原來引入依賴的代碼。

                  因為app.js是入口文件,有人會問,放在app.js之后加載,不會阻塞app.js的加載和執行。

                  其實并有沒有影響,因為app.js已經用link標簽做了預加載。js文件的加載是并發,誰先加載完先執行誰。

                  用externals提取完第三依賴包后,執行npm run build,分析圖如下

                  和之前對比,兩個大文件的一個已經消失,剩下一個只有81.42KB,和之前的1003.44KB相比是不是小了很多。再看里面的內容,之前的elemen-ui、jquery.js、vue.runtime.esm.js、xlsx.js這些依賴包都消失。優化成效明顯。

                  用externals提取第三方依賴包時,需切記中庸之道。雖然我們的最終目的是減少http請求資源大小,但是過猶不及,提取的過細將會增加http請求數量。

                  隨時隨地學軟件編程-關注百度小程序和微信小程序
                  關于找一找教程網

                  本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。
                  本站提供了軟件編程、網站開發技術、服務器運維、人工智能等等IT技術文章,希望廣大程序員努力學習,讓我們用科技改變世界。
                  [??四年前端教你使用externals解決chunk-vendors.js過大問題]http://www.yachtsalesaustralia.com/tech/detail-139472.html

                  贊(0)
                  關注微信小程序
                  程序員編程王-隨時隨地學編程

                  掃描二維碼或查找【程序員編程王】

                  可以隨時隨地學編程啦!

                  技術文章導航 更多>
                  国产在线拍揄自揄视频菠萝

                        1. <dd id="erndk"></dd>