溫馨提示×

溫馨提示×

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

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

webpack優(yōu)化的深入理解

發(fā)布時間:2020-08-26 01:12:08 來源:腳本之家 閱讀:147 作者:william 欄目:web開發(fā)

前言

由于前端的快速發(fā)展,相關工具的發(fā)展速度也是相當迅猛,各大框架例如vue,react都有自己優(yōu)秀的腳手架工具來幫助我們快速啟動一個新項目,也正式因為這個原因,我們對于腳手架中最關鍵的一環(huán)webpack相關的優(yōu)化知之甚少,腳手架基本上已經(jīng)為我們做好了相關的開發(fā)準備,但是當我們想要做一些定制化的優(yōu)化操作時,對webpack的優(yōu)化也需要有一定的了解,否則無從下手,接下來就讓我們進入webpack的優(yōu)化世界

構建速度提升

loader提升

loader是webpack中最重要的特性,由于webpack自身只支持JavaScript,因此需要一系列的loader來處理那些非JavaScript模塊,因此在我們用webpack建項目的時候一定會使用一系列的loader,例如:vue-loader、sass-loader、babel-loader等等,就以babel-loader為例,來看具體配置:

module: {
 rules: [{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'babel-loader?cacheDirectory=true',
  options: {
  presets: ['@babel/preset-env'],
  plugins: ['@babel/transform-runtime']
  }
 }]
 }
  • 對于loader來說最常用的就是exclude屬性,用來避免不必要的轉(zhuǎn)譯,上面通過exclude來避免對node_modules中js中進行轉(zhuǎn)譯來提升構建速度,但是這樣帶來的提升效果有限。
  • cacheDirectory是對babel-loader的轉(zhuǎn)譯結果進行緩存,之后的webpack進行構建時,都會去嘗試讀取緩存來避免高耗能的babel重新轉(zhuǎn)譯過程,cacheDirectory可以指定一個緩存目錄或者指定為true,為true時將使用默認的緩存目錄node_modules/.cache/babel-loader。
  • babel對一些公共方法使用了非常小的輔助代碼,默認會注入到每一個需要的文件,這樣就造成重復引入,這時候就需要像上面那樣引入transform-runtime來告訴babel引入runtime來代替注入

第三方庫優(yōu)化

externals

externals提高構建速度的方法就是在構建時不會將指定的依賴包打包到bundle中,而是在運行時再從外部獲取依賴,具體是怎么用的呢?來看個例子:

externals : {
 vue : "Vue",
 vueRouter : "VueRouter",
 vueResource : "VueResource",
 vuex : "Vuex"
},
<script type="text/javascript" src="https//xxxx/vue.famliy.1.1.0.min.js"></script>

上面的例子的將vue全家桶都配置在externals中,然后將壓縮包合成一個js文件放在cdn上面,這樣就不會在構建時將文件打包到bundle中,提升打包速度,同時cdn又可以做緩存,提高訪問速度,美滋滋

DllPlugin

DllPlugin是用來干什么的呢?DllPlugin會將第三方包到一個單獨文件,并且生成一個映射的json文件,打包的生成的文件就是一個依賴庫,這個依賴不會隨著你的業(yè)務代碼改變而被重新打包,只有當它自身依賴的包發(fā)生變化時才會需要重新打包依賴庫,接下來來看具體配置吧:

module.exports = {
 entry: {
 vendor: ['vue', 'vue-router', 'vue-resource', 'vuex']
 },
 output: {
 path: path.join(__dirname, 'dist'),
 filename: '[name].js',
 library: '[name]_hash',
 },
 plugins: [
 new webpack.DllPlugin({
  name: '[name]_[hash]',
  path: path.join(__dirname, 'dist', '[name]-manifest.json'),
  context: __dirname
 })
 ]
}

首先我們需要一個如上面例子那樣的dll配置文件,然后編譯這個配置文件,生成一個vendor.js和一個映射文件vendor-manifest.json,然后再在我們的webpack配置文件中對進行配置:

plugins: [
 new webpack.DllReferencePlugin({
  context: __dirname,
  manifest: require('./dist/vendor-manifest.json')
 })
 ]

這樣就完成配置了,是不是很簡單呢?趕緊動手試試吧

happypack

happypack這是個什么呢?我們都知道webpack是個單線程處理任務的,當又多個任務需要處理的時候,需要排隊,那happypack就是用多線程來處理任務,通過并發(fā)處理來提高任務處理速度,那么這個需要怎么配置呢?來看具體例子:

const happypack = require('happypack')
// 創(chuàng)建并發(fā)池
const threadPool = happypack.ThreadPool({size: os.cpus().length})
module: {
 rules: [{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'happypack/loader?id=happyBabel' // id對應happypack插件id
 }]
 },
plugins: [
 new happypack({
  id: 'happyBabel',
  threadPool: threadPool,
  loaders: ['babel-loader?cacheDirectory']
 })
 ],

減小構建體積

webpack-bundle-analyzer

這個相信大家都很熟悉,就是一個可視化工具,用來查看各個包的大小以及相互之間的依賴關系,配置方法也很簡單,就和插件的配置一樣,來看具體例子:

const bundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins: [
 new bundleAnalyzerPlugin()
 ],

tree shaking

tree shaking指的是什么呢?通常指的是JavaScript上下文中未引用的代碼,怎么理解呢?比如你引用了lodash包,里面有許多和JavaScript相關的便利方法,但你實際只用了其中的一兩個,此時打包時如果把所有的方法都打進去了,是不是很浪費呢?tree shaking的概念就是去除多余代碼。來看一個簡單的例子:

import {plus} from './count'

console.log(plus(1, 2))
function plus(x, y) {
 return x + y
}
function minus(x, y) {
 return x - y
}
export {
 plus,
 minus
}
const path = require('path')

module.exports = {
 entry: {
 main: './src/index.js',
 },
 output: {
 path: path.join(__dirname, 'dist'),
 filename: '[name].js',
 },
 mode: 'development'
}

如上例所示,在入口文件中我們引入count.js中plus方法,我們期望的當然是只會引入plus方法,而不是都引入,但往往不隨人愿,來看結果:


webpack優(yōu)化的深入理解

你會發(fā)現(xiàn)編譯后的代碼中,整個count.js都被編譯進去了,這時候你就需要tree shaking了,接下來看做tree shaking的具體方法

UglifyJsPlugin

這個插件大家一定都用過,使用UglifyJsPlugin就可以在構建的過程中對冗余的代碼進行刪除,在webpack4中只需要將上面mode的值改為production,就會啟用UglifyJsPlugin,是不是很簡單,或許你想知道webpack4中怎么自己配置UglifyJsPlugin,那就來看具體配置吧:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
optimization: {
 minimizer: [
  new UglifyJsPlugin({
  parallel: true,
  cache: true,
  uglifyOptions: {
   compress: {
   drop_console: true,
   reduce_vars: true
   },
   output: {
   comments: false,
   beautify: false
   }
  }
  })
 ]
 }

是的在webpack4中的UglifyJsPlugin是配置在optimization中的minimizer中的,配置是不很簡單呢?趕緊動手嘗試吧

按需加載(import)

這里的import是指webpack中的動態(tài)加載,它的語法和ES6中的動態(tài)加載語法一摸一樣,這是官方推薦的按需加載的方式,還是上面tree shaking的例子,我們只想引入plus方法,我們來看具體怎么使用:

import('./count.js').then((count) => {
 console.log(count.plus(1, 2))
})

我們只需要將入口文件改成上面的形式,其他的都不要變就可以實現(xiàn)按需引入,是不是很簡單呢?在vue中路由的按需加載也可以這么用,來看一個簡單的例子:

function view (name) {
 return new Promise((resolve, reject) => {
 import('../views/' + name + '.vue')
  .then((res) => {
  resolve(res)
  }).catch(e => {
  reject('網(wǎng)絡異常,請稍后再試')
  })
 }).catch(err => {
 throw new Error('err,組件加載失敗')
 })
}

傳入一個名字,動態(tài)引入對應目錄的下的視圖文件,這只是一個簡單的例子,具體的使用形式還是依據(jù)具體的場景

總結

這篇文章簡單的從構建速度和代碼體積兩個方面簡單的介紹了webpack優(yōu)化相關的方法,希望大家都能自己動手去寫一寫,畢竟只有實踐出真知,更何況是編程。

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

向AI問一下細節(jié)

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

AI