亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入理解基于vue-cli的webpack打包優(yōu)化實踐及探索

 更新時間:2019年10月14日 11:30:29   作者:曾培森  
這篇文章主要介紹了基于vue-cli的webpack打包優(yōu)化實踐及探索,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
轉(zhuǎn)眼已經(jīng)是2019年,短短三四年時間,webpack打包工具成為了前端開發(fā)中必備工具,曾經(jīng)一度的面試題都是問,請問前端頁面優(yōu)化的方式有哪些?大家也是能夠信手拈來的說出緩存、壓縮文件、CSS雪碧圖以及部署CDN等等各種方法,但是今天不一樣了,可能你去面試問的就是,請問你是否知道webpack的打包原理,webpack的打包優(yōu)化方法有哪些?所以該說不說的,筆者閑著沒事研究了一下webpack的打包優(yōu)化,可能大家都有看過類似的優(yōu)化文章~ 但是筆者還是希望能夠給大家一些新的啟發(fā)~

1、準備工作:測速與分析bundle

既然我們要優(yōu)化webpack打包,肯定要提前對我們的bundle文件進行分析,分析各模塊的大小,以及分析打包時間的耗時主要是在哪里,這里主要需要用到兩個webpack插件,speed-measure-webpack-plugin和webpack-bundle-analyzer,前者用于測速,后者用于分析bundle文件。

具體配置

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const smp = new SpeedMeasurePlugin({
 outputFormat:"human",
});
module.exports = {
configureWebpack: smp.wrap({
  plugins: [
   new webpack.ProvidePlugin({
    $: "zepto",
    Zepto: "zepto",
   }),
   new BundleAnalyzerPlugin(),
  ],
  optimization: {
   splitChunks: {
    cacheGroups: {
     echarts: {
      name: "chunk-echarts",
      test: /[\\/]node_modules[\\/]echarts[\\/]/,
      chunks: "all",
      priority: 10,
      reuseExistingChunk: true,
      enforce: true,
     },
     demo: {
      name: "chunk-demo",
      test: /[\\/]src[\\/]views[\\/]demo[\\/]/,
      chunks: "all",
      priority: 20,
      reuseExistingChunk: true,
      enforce: true,
     },
     page: {
      name: "chunk-page",
      test: /[\\/]src[\\/]/,
      chunks: "all",
      priority: 10,
      reuseExistingChunk: true,
      enforce: true,
     },
     vendors: {
      name: "chunk-vendors",
      test: /[\\/]node_modules[\\/]/,
      chunks: "all",
      priority: 5,
      reuseExistingChunk: true,
      enforce: true,
     },
    },
   },
  },
 })
}

由于是基于vue-cli腳手架的,所以其實vue-cli中已經(jīng)幫你做了一些優(yōu)化的工作,可以看到,原先項目最初的配置設(shè)置了splitchunk,進行代碼分割,這在大型項目中是很有必要的,畢竟你不希望你的用戶阻塞加載一個5MB大小的JS文件,所以做代碼分割和懶加載是很有必要的。

說遠了,我們來看看這個配置,你需要用smp對配置進行再包裹,因為SpeedMeasurePlugin會對你的其他Plugin對象包裹一層代理,這樣的目的是為了能夠知道plugin開始和結(jié)束的時間~

其次,BundleAnalyzerPlugin就跟普通的plugin一樣,加載plugins數(shù)組的后面即可。

接下來我們看一下最初的打包時間以及包內(nèi)容分析:

可以看到項目中較大的三個包,其中兩個包是我們的第三方依賴,three.js、lottie、lodash、echarts等。

2、開始逐步優(yōu)化

2.1縮小文件查找和處理范圍

這是webpack優(yōu)化中的常規(guī)操作,基本就是對模塊和文件查找的優(yōu)化,以及減少loader對一些不必要模塊的處理,但是vue-cli中的loader并沒有暴露給我們操作,所以其內(nèi)置的loader處理無法由我們進行優(yōu)化,但是其實vue-cli中的配置項已經(jīng)對loader的查找路徑進行了優(yōu)化,如果你的項目也是使用了vue-cli,你可以通過以下命令行查看你現(xiàn)有的配置文件是怎樣的:

npx vue-cli-service inspect > output.js

具體可以翻閱vuecli官方文檔。

resolve:{
 modules: [path.resolve(__dirname, 'node_modules')],
 alias:{
  'three':path.resolve(__dirname, './node_modules/three/build/three.min.js'),
  'zepto$':path.resolve(__dirname, './node_modules/zepto/dist/zepto.min.js'),
  'swiper$':path.resolve(__dirname, './node_modules/swiper/dist/js/swiper.min.js'),
  'lottie-web$':path.resolve(__dirname, './node_modules/lottie-web/build/player/lottie.min.js'),
  'lodash$':path.resolve(__dirname, './node_modules/lodash/lodash.min.js'),
 }
},
module:{
 noParse:/^(vue|vue-router|vuex|vuex-router-sync|three|zepto|swiper|lottie-web|lodash)$/
},
  • 通過modules指定查找第三方模塊的路徑。
  • 通過alias指定第三方模塊直接查找到打包構(gòu)建好的壓縮js文件。
  • 通過module指定noparse,對第三方模塊不再進行分析依賴。

優(yōu)化效果:2s?

可以看到時間就減少了兩三秒,在30s波動,感覺沒有多大差別。

2.2嘗試使用happypack

由于在進行webpack優(yōu)化前,翻閱了很多有關(guān)webapck優(yōu)化的文章,所以筆者也想嘗試一下用happypack來優(yōu)化打包時間。
在想要用happypack進行的打包之前,大抵有這兩種說法:

1、webpack4中已經(jīng)默認是多線程打包了,所以happypack打包效果不明顯;

2、vue不支持happypack打包,需要設(shè)置thread-loader。

但是筆者想了一下,還是試試看把,大不了我只對JS和CSS文件設(shè)置happypack。

但是問題又來了,vue-cli內(nèi)置封裝了loader,這個時候我要怎么拿到它的配置,改寫里面的loader配置呢。

通過翻閱vue-cli的官方文檔我們可以看到以下使用介紹:

configureWebpack
Type: Object | Function
如果這個值是一個對象,則會通過 webpack-merge 合并到最終的配置中。
如果這個值是一個函數(shù),則會接收被解析的配置作為參數(shù)。該函數(shù)及可以修改配置并不返回任何東西,也可以返回一個被克隆或合并過的配置版本。

為此,筆者特地調(diào)試進了vue-cli的源碼一探究竟:

流程介紹:

由于我們執(zhí)行命令行vue-cli-service build,其實是先去node_modules的.bin文件夾下查找相應(yīng)的可執(zhí)行文件,.bin下的vue-cli-service會映射到相應(yīng)的第三方庫內(nèi)的執(zhí)行文件。

所以我們可以找到這個可執(zhí)行文件的地址:

/node_modules/@vue/cli-service/bin/vue-cli-service.js

找到了入口,接下來我們想要進入nodejs的調(diào)試,在以往的開發(fā)中,我們會通過node --inspect app.js的方式啟動一個后臺服務(wù),然后在谷歌瀏覽器里進入調(diào)試界面(F12選擇綠色的那個小按鈕)

但是這里卻犯了難,由于我們的打包構(gòu)建是一次執(zhí)行的,不同于一個后臺服務(wù),是實時監(jiān)聽的,服務(wù)一直啟動著。查閱了一下,如果是普通的nodejs文件想要調(diào)試的話,需要通過這樣的方式:

node --inspect-brk=9229 app.js

所以,為了強行走進去vue-cli的源碼進行調(diào)試,可看vue-cli的處理流程,我們需要這樣輸入以下命令行:

node --inspect-brk=9229 node_modules/@vue/cli-service/bin/vue-cli-service.js build

上面的這個命令行,等價于vue-cli-service build。

通過這樣的方式,我們終于走進了vue-cli的源碼,看了它的執(zhí)行流程,你可以在對應(yīng)的位置打下斷點,查看此時的作用域內(nèi)的變量數(shù)據(jù)。


可以看到vue-cli源碼里的這一段操作,會執(zhí)行我們傳入的函數(shù),判斷函數(shù)有沒有返回值來決定是否要merge進其內(nèi)部配置的config。

通過這段代碼我們可以看出,如果我們configWepack配置為函數(shù),之后通過參數(shù)的形式獲取到config配置項,本身是一個對象,對象是保留引用的形式,所以如果我們直接對傳入的config對象進行修改,就可以實現(xiàn)我們最初的目標(biāo)!修改vue-cli內(nèi)置的loader!

當(dāng)然,除了斷點進入里面看配置,剛才也說了,我們可以通過命令行輸出為一個output文件查看現(xiàn)有的配置。

這里可以給大家截圖看一下vue-cli內(nèi)部的配置:


可能有點廢話了,但是通過斷點的方式,我們可以看到vue-cli其實已經(jīng)對js文件設(shè)置了exclude,同時也幫我們設(shè)置好了cache-loader,意味著webpack常規(guī)的優(yōu)化方式之一,使用cache-loader緩存它也幫我們做了。

回到最初的起點,我們想要處理的是針對JS和CSS的loader,于是模仿大多數(shù)的配置,我進行了以下修改:

 configureWebpack:(config)=>{
  console.log("webpack config start");
  let originCssRuleLoader = config.module.rules[6].oneOf[0].use;
  let newCssRuleLoader = 'happypack/loader?id=css';
  config.module.rules[6].oneOf[0].use = newCssRuleLoader
  config.module.rules[6].oneOf[1].use = newCssRuleLoader
  config.module.rules[6].oneOf[2].use = newCssRuleLoader
  config.module.rules[6].oneOf[3].use = newCssRuleLoader
  ...//other code
 }

嘗試對css的loader配置進行修改。之后對plugins進行一下配置:

plugins: [
  new HappyPack({
   id: 'css',
   threads: 4,
   loaders: originCssRuleLoader
  }),
 ],

本以為這樣就OK了,但是很遺憾的告訴大家,報錯了...


可以看到報錯的內(nèi)容,是在處理vue文件的時候,出了錯誤。

如何解決

筆者百度了,也谷歌了,大抵是說happypack不支持vue-loader,同時,根據(jù)報錯也查了一下處理的方案,通過設(shè)置parallel參數(shù),也還是無效。

筆者甚至懷疑是自己的happypack配置不對,于是我把配置原樣移植配置到另一個非vue項目中,一切運行正常。
答案:此題無解~

原因分析:

由于vue文件中會含有CSS,所以vue-loader會提取出其中的css,交給其他loader處理,vue-loader-plugin會通過在vue文件后面加上查詢字符串來告訴其他loader,針對這個文件要做處理。意味著什么呢?我們的vue-loader在處理文件的時候,通知其他loader處理,但是此時的loader配置已經(jīng)被我們改寫成了happypack,而vue又與happypack不兼容,最終導(dǎo)致了報錯。很遺憾的告訴大家,vue-cli接入happypack--失敗。

(注:這一部分主要是筆者在webpack優(yōu)化過程中的探索,雖然最終不能讓自己的webpack打包很好的優(yōu)化,但是在這個探索的過程中,我們也可以學(xué)到很多~包括 vue-cli對配置對象的處理?如何調(diào)試普通文件nodejs代碼?vue-loader中對vue文件的處理流程?vue-loader-plugin幫我們做了什么事?而這些都是要自己慢慢翻閱,慢慢踩坑去了解的~)

2.3使用dllplugin

和大多數(shù)的webpack優(yōu)化教程一樣,筆者也嘗試了利用dllplugin進行優(yōu)化,該插件的本質(zhì),是提取出我們常用的第三方模塊,單獨打成一個文件包,之后插入到我們的html頁面中,這樣我們以后每次打包,都不需要針對第三方模塊進行處理,畢竟第三方模塊動輒成千上萬行。

流程介紹:

1、配置webpack.dll.js針對第三方庫打包

2、vue.config.js中配置plugin

3、html中引入dll打包出來的js文件。(一般采用部署CDN的方式)

由于項目中有很多大型的第三方庫,類似three、echart等,所以筆者進行了以下配置:(webpack.dll.js)

const webpack = require("webpack")
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
    vuebundle: [
      'vue',
      'vue-router',
      'vuex',
    ],
    utils:[
      'lodash',
      'swiper',
      'lottie-web',
      'three',
    ],
    echarts:[
      'echarts/lib/echarts',
      "echarts/lib/chart/bar",
      "echarts/lib/chart/line",
      "echarts/lib/component/tooltip",
      "echarts/lib/component/title",
      "echarts/lib/component/legend",
    ]

  },
  output: {
    path: path.resolve(__dirname, './static/'),
    filename: '[name].dll.js',
    library: '[name]_library'
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, 'build', '[name]-manifest.json'),
      name: '[name]_library'
    })
  ]
}

針對不同的庫的大小進行劃分,打了三個包,為啥不打成一個包?一個包那就太大了,你并不希望你的用戶加載一個大型JS文件包而阻塞,影響頁面性能。

接下里是vue.config.js的配置:

plugins: [
   new webpack.ProvidePlugin({
    $: "zepto",
    Zepto: "zepto",
   }),
   new DllReferencePlugin({
    manifest: require('./build/echarts-manifest.json'),
   }),
   new DllReferencePlugin({
    manifest: require('./build/utils-manifest.json'),
   }),
   new DllReferencePlugin({
    manifest: require('./build/vuebundle-manifest.json'),
   }),
   new BundleAnalyzerPlugin(),
  ]

引入了DllPlugin。接下來配置HTML:

(由于筆者沒將DLL打包出來的js文件上傳到CDN,所以只能本地自己起個node服務(wù)器返回靜態(tài)資源了)

 <body>
   <div id="app"></div>
  <!-- built files will be auto injected -->
  <script type="text/javascript" src="http://localhost:3000/echarts.dll.js"></script>
  <script type="text/javascript" src="http://localhost:3000/utils.dll.js"></script>
  <script type="text/javascript" src="http://localhost:3000/vuebundle.dll.js"></script>
 </body>

然后npm run serve,開始頁面調(diào)試和開發(fā)~

舒服~

優(yōu)化結(jié)果:


由于少了大型第三方庫,所以時間控制在了20s左右了。優(yōu)化相對比較明顯~

3、優(yōu)化與探索總結(jié)

優(yōu)化到這,基本就結(jié)束了。

webpack常見的優(yōu)化方式,優(yōu)化路徑查找、設(shè)置緩存、happypack以及dllplugin,前兩項vue-cli已經(jīng)幫我們做了一些,而happypack由于不和vue兼容,導(dǎo)致無法接入,dllplugin通過單獨提取第三方庫,取得了明顯優(yōu)化。
當(dāng)然,筆者也嘗試剔除了一些項目中無用的代碼,不過也是不痛不癢。

webpack優(yōu)化方式總結(jié):

1、優(yōu)化模塊查找路徑

2、剔除不必要的無用的模塊

3、設(shè)置緩存:緩存loader的執(zhí)行結(jié)果(cacheDirectory/cache-loader)

4、設(shè)置多線程:HappyPack/thread-loader

5、dllplugin提取第三方庫

當(dāng)然,這是針對開發(fā)的優(yōu)化,如果是針對部署上的優(yōu)化呢?我們可以設(shè)置splitchunk、按需加載、部署CDN等,這里就不展開了。

最后

希望這篇文章能夠大家有所收獲~ webpack已經(jīng)是前端仔必備技能了~有空大家鉆研一下webpack的配置和原理,也是會有所收獲的!謝謝觀看~

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JAVASCRIPT下判斷IE與FF的比較簡單的方式

    JAVASCRIPT下判斷IE與FF的比較簡單的方式

    在JAVASCRIPT當(dāng)中可以通過取當(dāng)前瀏覽器返回值來判斷當(dāng)前使用什么瀏覽器。
    2008-10-10
  • functional繼承模式 摘自javascript:the good parts

    functional繼承模式 摘自javascript:the good parts

    javascript:the good parts 書中Inheritance部分講到了一種functional的繼承方式, 具體這個functional該如何翻譯,就不是很清楚了, 就直接意會一下吧
    2011-06-06
  • 20個常見的JavaScript數(shù)組操作總結(jié)

    20個常見的JavaScript數(shù)組操作總結(jié)

    JavaScript中的Array對象與其他編程語言中的數(shù)組一樣,是一組數(shù)據(jù)的集合。在JavaScript中,數(shù)組里面的數(shù)據(jù)可以是不同類型的,并具有用于執(zhí)行數(shù)組常見操作的方法,本文整理了一些常用的,需要的可以參考一下
    2022-09-09
  • Javascript變量函數(shù)淺析

    Javascript變量函數(shù)淺析

    在javascript變量中可以存放兩種類型的值:原始值和引用值。原始值存儲在棧上的簡單字段,也就是值直接存儲在變量所標(biāo)示的位置內(nèi)。
    2011-09-09
  • babel的使用及安裝配置教程

    babel的使用及安裝配置教程

    babel是一個廣泛使用的轉(zhuǎn)碼器,可以將ES6代碼轉(zhuǎn)化為ES5代碼,從而在現(xiàn)有環(huán)境執(zhí)行。這篇文章主要介紹了babel的使用以及安裝配置,需要的朋友可以參考下
    2018-02-02
  • JS特權(quán)方法定義作用以及與公有方法的區(qū)別

    JS特權(quán)方法定義作用以及與公有方法的區(qū)別

    在構(gòu)造函數(shù)內(nèi)部通過this關(guān)鍵字定義的的方法為特權(quán)方法它的作用為在構(gòu)造函數(shù)外面公開訪問(僅限于實例化的對象),而且還能夠訪問私有成員和方法,感興趣的你可以參考下哈
    2013-03-03
  • webpack HappyPack實戰(zhàn)詳解

    webpack HappyPack實戰(zhàn)詳解

    這篇文章主要介紹了webpack HappyPack實戰(zhàn)詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • js導(dǎo)出txt示例代碼

    js導(dǎo)出txt示例代碼

    很多新手朋友們都不知道js怎么導(dǎo)出txt,下面有個不錯的示例,大家可以參考下
    2014-01-01
  • layer.confirm點擊第一個按鈕關(guān)閉彈出框的方法

    layer.confirm點擊第一個按鈕關(guān)閉彈出框的方法

    今天小編就為大家分享一篇layer.confirm點擊第一個按鈕關(guān)閉彈出框的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • fckeditor粘貼Word時彈出窗口取消的方法

    fckeditor粘貼Word時彈出窗口取消的方法

    這篇文章主要介紹了fckeditor粘貼Word時彈出窗口取消的方法,是應(yīng)用fckeditor時非常實用的技巧,需要的朋友可以參考下
    2014-10-10

最新評論