webpack打包优化的几个方法总结


Posted in Javascript onFebruary 10, 2020

为什么要优化打包?

  • 项目越做越大,依赖包越来越多,打包文件太大
  • 单页面应用首页白屏时间长,用户体验差

我们的目的

  • 减小打包后的文件大小
  • 首页按需引入文件
  • 优化 webpack 打包时间

优化方式

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、优化 loader 配置

  • 优化正则匹配
  • 通过 cacheDirectory 选项开启缓存
  • 通过 include、exclude 来减少被处理的文件。
module: {
 rules: [
  {
   test: /\.js$/,
   loader: 'babel-loader?cacheDirectory',
   include: [resolve('src')]
  }
 ]
}

3、优化文件路径——省下搜索文件的时间

  • extension 配置之后可以不用在 require 或是 import 的时候加文件扩展名,会依次尝试添加扩展名进行匹配。
  • mainFiles 配置后不用加入文件名,会依次尝试添加的文件名进行匹配
  • alias 通过配置别名可以加快 webpack 查找模块的速度。
resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src'),
  }
 },

4、生产环境关闭 sourceMap

  • sourceMap 本质上是一种映射关系,打包出来的 js 文件中的代码可以映射到代码文件的具体位置,这种映射关系会帮助我们直接找到在源代码中的错误。
  • 打包速度减慢,生产文件变大,所以开发环境使用 sourceMap,生产环境则关闭。

5、代码压缩

  • UglifyJS: vue-cli 默认使用的压缩代码方式,它使用的是单线程压缩代码,打包时间较慢
  • ParallelUglifyPlugin: 开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成

两种方法使用如下:

plugins: [
 new UglifyJsPlugin({
  uglifyOptions: {
   compress: {
    warnings: false
   }
  },
  sourceMap: true,
  parallel: true
 }),

 new ParallelUglifyPlugin({
  //缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回,
  //cacheDir 用于配置缓存存放的目录路径。
  cacheDir: '.cache/',
  sourceMap: true,
  uglifyJS: {
   output: {
    comments: false
   },
   compress: {
    warnings: false
   }
  }
 })
]

6、提取公共代码

  • 相同资源重复被加载,浪费用户流量,增加服务器成本。
  • 每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验。

webpack3 使用 CommonsChunkPlugin 的实现:

plugins: [
 new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function(module, count) {
   console.log(module.resource, `引用次数${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 的实现:

module.exports = {
 optimization: {
  splitChunks: {
   cacheGroups: {
    vendor: {
     priority: 1, //添加权重
     test: /node_modules/, //把这个目录下符合下面几个条件的库抽离出来
     chunks: 'initial', //刚开始就要抽离
     minChunks: 2 //重复2次使用的时候需要抽离出来
    },
    common: {
     //公共的模块
     chunks: 'initial',
     minChunks: 2
    }
   }
  }
 }
}

7、CDN 优化

  1. 随着项目越做越大,依赖的第三方 npm 包越来越多,构建之后的文件也会越来越大。
  2. 再加上又是单页应用,这就会导致在网速较慢或者服务器带宽有限的情况出现长时间的白屏。

1、将 vue、vue-router、vuex、element-ui 和 axios 这五个库,全部改为通过 CDN 链接获取,在 index.html 里插入 相应链接。

<head>
 <link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.7/theme-chalk/index.css" 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 多进程解析和处理文件

  • 由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以 Webpack 需要处理的事情需要一件一件的做,不能多件事一起做。
  • HappyPack 就能让 Webpack 把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
  • HappyPack 对 file-loader、url-loader 支持的不友好,所以不建议对该 loader 使用。

使用方法如下:

1、HappyPack 插件安装: npm i -D happypack
2、webpack.base.conf.js 文件对 module.rules 进行配置

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、在生产环境 webpack.prod.conf.js 文件进行配置

const HappyPack = require('happypack')
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
 new HappyPack({
  // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
  id: 'babel',
  // 如何处理.js文件,用法和Loader配置中一样
  loaders: ['babel-loader?cacheDirectory'],
  threadPool: HappyPackThreadPool
 }),
 new HappyPack({
  id: 'vue', // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
  loaders: [
   {
    loader: 'vue-loader',
    options: vueLoaderConfig
   }
  ],
  threadPool: HappyPackThreadPool
 })
]

总结

  • 比较实用的方法: 按需加载,优化loader配置,关闭生产环境的sourceMap,CDN优化。
  • vue-cli已做的优化: 代码压缩,提取公共代码,再优化空间不大。
  • 根据项目实际需要和自身开发水平选择优化方法,必须避免因为优化产生bug。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
可拖动窗口,附带鼠标控制渐变透明,开启关闭功能
Jun 26 Javascript
jQuery 事件队列调整方法
Sep 18 Javascript
firefox firebug中文入门教程 脚本之家新年特别版
Jan 02 Javascript
javascript删除字符串最后一个字符
Jan 14 Javascript
jQuery实现的一个tab切换效果内部还嵌有切换
Aug 10 Javascript
JQuery拖动表头边框线调整表格列宽效果代码
Sep 10 Javascript
jQuery实现鼠标悬停背景翻转的黑色导航菜单代码
Sep 14 Javascript
JS实现JSON.stringify的实例代码讲解
Feb 07 Javascript
jQuery图片切换动画效果
Feb 28 Javascript
js实现股票实时刷新数据案例
May 14 Javascript
理解Koa2中的async&amp;await的用法
Feb 05 Javascript
使用Vuex实现一个笔记应用的方法
Mar 13 Javascript
JS+HTML5本地存储Localstorage实现注册登录及验证功能示例
Feb 10 #Javascript
node.js制作一个简单的登录拦截器
Feb 10 #Javascript
使用 Vue-TCB 快速在 Vue 应用中接入云开发的方法
Feb 10 #Javascript
jQuery实现简易QQ聊天框
Feb 10 #jQuery
解决vue-cli@3.xx安装不成功的问题及搭建ts-vue项目
Feb 09 #Javascript
Vue中import from的来源及省略后缀与加载文件夹问题
Feb 09 #Javascript
如何基于javascript实现贪吃蛇游戏
Feb 09 #Javascript
You might like
PHP技术开发技巧分享
2010/03/23 PHP
关于PHP内存溢出问题的解决方法
2013/06/25 PHP
PHP中4个加速、缓存扩展的区别和选用建议
2014/03/12 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
PHP实现的折半查找算法示例
2017/12/19 PHP
PHP实现的微信APP支付功能示例【基于TP5框架】
2019/09/16 PHP
laravel 错误处理,接口错误返回json代码
2019/10/25 PHP
node.js中的定时器nextTick()和setImmediate()区别分析
2014/11/26 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
JQuery自适应窗口大小导航菜单附源码下载
2015/09/01 Javascript
js实现内容显示并使用json传输数据
2016/03/16 Javascript
Bootstrap表单Form全面解析
2016/06/13 Javascript
JS实现的图片预览插件与用法示例【不上传图片】
2016/11/25 Javascript
jQuery Validate表单验证插件实现代码
2017/06/08 jQuery
javascript 中select框触发事件过程的分析
2017/08/01 Javascript
JavaScript 中的 this 简单规则
2017/09/19 Javascript
Vue实现用户自定义字段显示数据的方法
2018/08/28 Javascript
JavaScript中import用法总结
2019/01/20 Javascript
Vue自定义指令上报Google Analytics事件统计的方法
2019/02/25 Javascript
Node.js设置定时任务之node-schedule模块的使用详解
2020/04/28 Javascript
js实现复制粘贴的两种方法
2020/12/04 Javascript
[04:10]DOTA2英雄梦之声_第11期_圣堂刺客
2014/06/21 DOTA
python3监控CentOS磁盘空间脚本
2018/06/21 Python
python使用opencv驱动摄像头的方法
2018/08/03 Python
Kears 使用:通过回调函数保存最佳准确率下的模型操作
2020/06/17 Python
Python 获取异常(Exception)信息的几种方法
2020/12/29 Python
GUESS德国官网:美国牛仔服装品牌
2017/02/14 全球购物
Shell如何接收变量输入
2016/08/06 面试题
opencv实现图像几何变换
2021/03/24 Python
退休感言
2014/01/28 职场文书
《藏戏》教学反思
2014/02/11 职场文书
博士生导师推荐信
2014/07/08 职场文书
乒乓球比赛通知
2015/04/27 职场文书
农村党员干部承诺书
2015/05/04 职场文书
欢送领导祝酒词
2015/08/12 职场文书
Python爬虫之爬取某文库文档数据
2021/04/21 Python