webpack打包優(yōu)化的幾個方法總結(jié)
為什么要優(yōu)化打包?
- 項(xiàng)目越做越大,依賴包越來越多,打包文件太大
- 單頁面應(yīng)用首頁白屏?xí)r間長,用戶體驗(yàn)差
我們的目的
- 減小打包后的文件大小
- 首頁按需引入文件
- 優(yōu)化 webpack 打包時間
優(yōu)化方式
1、 按需加載
1.1 路由組件按需加載
const router = [ { path: '/index', component: resolve => require.ensure([], () => resolve(require('@/components/index'))) }, { path: '/about', component: resolve => require.ensure([], () => resolve(require('@/components/about'))) } ]
1.2 第三方組件和插件。按需加載需引入第三方組件
// 引入全部組件 import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) // 按需引入組件 import { Button } from 'element-ui' Vue.component(Button.name, Button)
1.3 對于一些插件,如果只是在個別組件中用的到,也可以不要在 main.js 里面引入,而是在組件中按需引入
// 在main.js引入 import Vue from vue import Vuelidate from 'vuelidate' Vue.use(Vuelidate) // 按組件按需引入 import { Vuelidate } from 'vuelidate'
2、優(yōu)化 loader 配置
- 優(yōu)化正則匹配
- 通過 cacheDirectory 選項(xiàng)開啟緩存
- 通過 include、exclude 來減少被處理的文件。
module: { rules: [ { test: /\.js$/, loader: 'babel-loader?cacheDirectory', include: [resolve('src')] } ] }
3、優(yōu)化文件路徑——省下搜索文件的時間
- extension 配置之后可以不用在 require 或是 import 的時候加文件擴(kuò)展名,會依次嘗試添加擴(kuò)展名進(jìn)行匹配。
- mainFiles 配置后不用加入文件名,會依次嘗試添加的文件名進(jìn)行匹配
- alias 通過配置別名可以加快 webpack 查找模塊的速度。
resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } },
4、生產(chǎn)環(huán)境關(guān)閉 sourceMap
- sourceMap 本質(zhì)上是一種映射關(guān)系,打包出來的 js 文件中的代碼可以映射到代碼文件的具體位置,這種映射關(guān)系會幫助我們直接找到在源代碼中的錯誤。
- 打包速度減慢,生產(chǎn)文件變大,所以開發(fā)環(huán)境使用 sourceMap,生產(chǎn)環(huán)境則關(guān)閉。
5、代碼壓縮
- UglifyJS: vue-cli 默認(rèn)使用的壓縮代碼方式,它使用的是單線程壓縮代碼,打包時間較慢
- ParallelUglifyPlugin: 開啟多個子進(jìn)程,把對多個文件壓縮的工作分別給多個子進(jìn)程去完成
兩種方法使用如下:
plugins: [ new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false } }, sourceMap: true, parallel: true }), new ParallelUglifyPlugin({ //緩存壓縮后的結(jié)果,下次遇到一樣的輸入時直接從緩存中獲取壓縮后的結(jié)果并返回, //cacheDir 用于配置緩存存放的目錄路徑。 cacheDir: '.cache/', sourceMap: true, uglifyJS: { output: { comments: false }, compress: { warnings: false } } }) ]
6、提取公共代碼
- 相同資源重復(fù)被加載,浪費(fèi)用戶流量,增加服務(wù)器成本。
- 每個頁面需要加載的資源太大,導(dǎo)致網(wǎng)頁首屏加載緩慢,影響用戶體驗(yàn)。
webpack3 使用 CommonsChunkPlugin 的實(shí)現(xiàn):
plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function(module, count) { console.log(module.resource, `引用次數(shù)${count}`) //"有正在處理文件" + "這個文件是 .js 后綴" + "這個文件是在 node_modules 中" return module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, './node_modules')) === 0 } }), new webpack.optimize.CommonsChunkPlugin({ name: 'common', chunks: 'initial', minChunks: 2 }) ]
webpack4 使用 splitChunks 的實(shí)現(xiàn):
module.exports = { optimization: { splitChunks: { cacheGroups: { vendor: { priority: 1, //添加權(quán)重 test: /node_modules/, //把這個目錄下符合下面幾個條件的庫抽離出來 chunks: 'initial', //剛開始就要抽離 minChunks: 2 //重復(fù)2次使用的時候需要抽離出來 }, common: { //公共的模塊 chunks: 'initial', minChunks: 2 } } } } }
7、CDN 優(yōu)化
- 隨著項(xiàng)目越做越大,依賴的第三方 npm 包越來越多,構(gòu)建之后的文件也會越來越大。
- 再加上又是單頁應(yīng)用,這就會導(dǎo)致在網(wǎng)速較慢或者服務(wù)器帶寬有限的情況出現(xiàn)長時間的白屏。
1、將 vue、vue-router、vuex、element-ui 和 axios 這五個庫,全部改為通過 CDN 鏈接獲取,在 index.html 里插入 相應(yīng)鏈接。
<head> <link rel="stylesheet" rel="external nofollow" /> </head> <body> <div id="app"></div> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script> <script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script> <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script> <script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script> <!-- built files will be auto injected --> </body>
2、在 webpack.config.js 配置文件
module.exports = { ··· externals: { 'vue': 'Vue', 'vuex': 'Vuex', 'vue-router': 'VueRouter', 'element-ui': 'ELEMENT', 'Axios':'axios' } },
3、卸載依賴的 npm 包,npm uninstall axios element-ui vue vue-router vuex
4、修改 main.js 文件里之前的引包方式
// import Vue from 'vue' // import ElementUI from 'element-ui' // import 'element-ui/lib/theme-chalk/index.css' // import VueRouter from 'vue-router' import App from './App.vue' import routes from './router' import utils from './utils/Utils' Vue.use(ELEMENT) Vue.use(VueRouter) const router = new VueRouter({ mode: 'hash', //路由的模式 routes }) new Vue({ router, el: '#app', render: h => h(App) })
8、使用 HappyPack 多進(jìn)程解析和處理文件
- 由于運(yùn)行在 Node.js 之上的 Webpack 是單線程模型的,所以 Webpack 需要處理的事情需要一件一件的做,不能多件事一起做。
- HappyPack 就能讓 Webpack 把任務(wù)分解給多個子進(jìn)程去并發(fā)的執(zhí)行,子進(jìn)程處理完后再把結(jié)果發(fā)送給主進(jìn)程。
- HappyPack 對 file-loader、url-loader 支持的不友好,所以不建議對該 loader 使用。
使用方法如下:
1、HappyPack 插件安裝: npm i -D happypack
2、webpack.base.conf.js 文件對 module.rules 進(jìn)行配置
module: { rules: [ { test: /\.js$/, use: ['happypack/loader?id=babel'], include: [resolve('src'), resolve('test')], exclude: path.resolve(__dirname, 'node_modules') }, { test: /\.vue$/, use: ['happypack/loader?id=vue'] } ] }
3、在生產(chǎn)環(huán)境 webpack.prod.conf.js 文件進(jìn)行配置
const HappyPack = require('happypack') // 構(gòu)造出共享進(jìn)程池,在進(jìn)程池中包含5個子進(jìn)程 const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 }) plugins: [ new HappyPack({ // 用唯一的標(biāo)識符id,來代表當(dāng)前的HappyPack是用來處理一類特定的文件 id: 'babel', // 如何處理.js文件,用法和Loader配置中一樣 loaders: ['babel-loader?cacheDirectory'], threadPool: HappyPackThreadPool }), new HappyPack({ id: 'vue', // 用唯一的標(biāo)識符id,來代表當(dāng)前的HappyPack是用來處理一類特定的文件 loaders: [ { loader: 'vue-loader', options: vueLoaderConfig } ], threadPool: HappyPackThreadPool }) ]
總結(jié)
- 比較實(shí)用的方法: 按需加載,優(yōu)化loader配置,關(guān)閉生產(chǎn)環(huán)境的sourceMap,CDN優(yōu)化。
- vue-cli已做的優(yōu)化: 代碼壓縮,提取公共代碼,再優(yōu)化空間不大。
- 根據(jù)項(xiàng)目實(shí)際需要和自身開發(fā)水平選擇優(yōu)化方法,必須避免因?yàn)閮?yōu)化產(chǎn)生bug。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS 實(shí)現(xiàn)獲取驗(yàn)證碼 倒計(jì)時功能
這篇文章主要介紹了JS 實(shí)現(xiàn)獲取驗(yàn)證碼 倒計(jì)時功能,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-10-10JavaScript空數(shù)組的every()方法實(shí)踐
every()方法用于檢測數(shù)組中的所有元素是否都滿足指定條件, 本文主要介紹了JavaScript空數(shù)組的every()方法實(shí)踐,具有一定的參考價值,感興趣的可以了解一下2024-03-03DOM節(jié)點(diǎn)的替換或修改函數(shù)replaceChild()用法實(shí)例
這篇文章主要介紹了DOM節(jié)點(diǎn)的替換或修改函數(shù)replaceChild()用法,實(shí)例分析了replaceChild()替換DOM節(jié)點(diǎn)的使用技巧,需要的朋友可以參考下2015-01-01javascript類型系統(tǒng) Window對象學(xué)習(xí)筆記
這篇文章主要介紹了javascript類型系統(tǒng)之Window對象,整理關(guān)于Window對象的學(xué)習(xí)筆記,感興趣的小伙伴們可以參考一下2016-01-01input+select(multiple) 實(shí)現(xiàn)下拉框輸入值
昨天做一個網(wǎng)站時,需要實(shí)現(xiàn)下拉框能夠輸入,從功能上講是要實(shí)現(xiàn)用戶在文本框輸入值時,能夠從后讀出數(shù)據(jù)彈出下拉選項(xiàng)2009-05-05微信小程序點(diǎn)擊圖片實(shí)現(xiàn)長按預(yù)覽、保存、識別帶參數(shù)二維碼、轉(zhuǎn)發(fā)等功能
這篇文章主要介紹了微信小程序點(diǎn)擊圖片實(shí)現(xiàn)長按預(yù)覽、保存、識別帶參數(shù)二維碼、轉(zhuǎn)發(fā)等功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07JavaScript實(shí)現(xiàn)點(diǎn)擊自動選擇TextArea文本的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)點(diǎn)擊自動選擇TextArea文本的方法,涉及javascript中focus()、select()方法的使用技巧,非常簡單實(shí)用,需要的朋友可以參考下2015-07-07