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 相关文章推荐
JS实现时间格式化的方式汇总
Oct 16 Javascript
jQuery实现倒计时按钮功能代码分享
Sep 03 Javascript
jQuery Ajax使用实例
Apr 16 Javascript
快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突
Apr 15 Javascript
jquery基本选择器匹配多个元素的实现方法
Sep 05 Javascript
JS重载实现方法分析
Dec 16 Javascript
html5 canvas 详细使用教程
Jan 20 Javascript
JS实现AES加密并与PHP互通的方法分析
Apr 19 Javascript
node 命令方式启动修改端口的方法
May 12 Javascript
微信小程序使用二次贝塞尔曲线画波浪
Dec 25 Javascript
jQuery ajax仿Google自动提示SearchSuggess功能示例
Mar 28 jQuery
一文彻底理解js原生语法prototype,__proto__和constructor
Oct 24 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
Discuz板块横排显示图片的实现方法
2007/05/28 PHP
PHP chmod 函数与批量修改文件目录权限
2010/05/10 PHP
php提交表单发送邮件的方法
2015/03/20 PHP
PHP配置把错误日志以邮件方式发送方法(Windows系统)
2015/06/23 PHP
php实现在线通讯录功能(附源码)
2016/05/13 PHP
PHP排序算法之简单选择排序(Simple Selection Sort)实例分析
2018/04/20 PHP
浅谈PHP SHA1withRSA加密生成签名及验签
2019/03/18 PHP
浅谈laravel框架sql中groupBy之后排序的问题
2019/10/17 PHP
基于JQuery 的消息提示框效果代码
2011/07/31 Javascript
JavaScript中的稀疏数组与密集数组[译]
2012/09/17 Javascript
jQuery学习笔记(2)--用jquery实现各种模态提示框代码及项目构架
2013/04/08 Javascript
jQuery实现自定义checkbox和radio样式
2015/07/13 Javascript
Bootstrap每天必学之进度条
2015/11/30 Javascript
js获取本机操作系统类型的两种方法
2015/12/19 Javascript
js捕捉键盘事件和按键键值的方法
2016/10/10 Javascript
JS搜狐面试题分析
2016/12/16 Javascript
如何理解jQuery中的ajaxSubmit方法
2017/03/13 Javascript
JS限制输入框输入的实现代码
2018/07/02 Javascript
jQuery实现简单聊天室
2020/02/08 jQuery
用vue设计一个日历表
2020/12/03 Vue.js
Python Web服务器Tornado使用小结
2014/05/06 Python
python统计日志ip访问数的方法
2015/07/06 Python
python使用jieba实现中文分词去停用词方法示例
2018/03/11 Python
对Python实现简单的API接口实例讲解
2018/12/10 Python
Python函数中参数是传递值还是引用详解
2019/07/02 Python
python pillow模块使用方法详解
2019/08/30 Python
Python + Flask 实现简单的验证码系统
2019/10/01 Python
实现ECharts双Y轴左右刻度线一致的例子
2020/05/16 Python
Linux的文件类型
2016/07/05 面试题
生物制药自我鉴定
2014/01/25 职场文书
陈欧广告词
2014/03/14 职场文书
放飞理想演讲稿
2014/09/09 职场文书
2015教师个人年度工作总结
2015/10/23 职场文书
私人贷款担保书该怎么写呢?
2019/07/02 职场文书
html5中sharedWorker实现多页面通信的示例代码
2021/05/07 Javascript
Python利用机器学习算法实现垃圾邮件的识别
2021/06/28 Python