webpack打包vue反编译_2020年你必须知道的webpack打包优化方法

ebc0f793052adbd650091b96a7d7d2be.png

3ffe24c8d5b6bb7b253f1097e9bc98d7.gif

本文字数:3534

预计阅读时间:10分钟

随着我们的项目项目越做越大,引入的第三方库会越来越多,打包的依赖也越来越多,每次 build 的时间越来越长,打包出来的文件会越来越大。最糟糕的是单页面应用首页白屏时间长,用户体验差。 此时优化 webpack 打包方法不可回避。下面我们来整理一下常用的webpack打包优化方法。 关于优化,首先我们要明确几个问题:
  1. 我们优化的目标是什么?
  2. 有哪些点可以进行优化?如何优化?

优化的目的

很明显,我们优化的最终目的就是提高页面加载速度,提高产品用户体验,主要包括以下几个方面:

  • 减小打包后的文件大小

  • 首页按需引入文件,减少白屏时间

  • 优化 webpack 打包时间

分析 webpack 打包性能瓶颈

明确目标之后,首先我们来分析一下 webpack 打包性能瓶颈,找出问题所在,然后才能对症下药。

1、webpack-bundle-analyzer 分析体积

webpack-bundle-analyzer 可以扫码打包后内容并构建其成可视化的界面,我们可以在可视化的界面中找出不必要的依赖或者体积过大的包,有针对性地进行优化。

  • vue-cli3 需要安装依赖 webpack-bundle-analyzer

npm install webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins:[
new BundleAnalyzerPlugin(),
]
  • vue-cli2 直接在命令行输入 npm run build --report, 构建完成后会在 8888 端口展示大小

1174f534ebb1bbbbbacc4971a5255a16.png

从以上的界面中,我们可以得到以下信息:
  • 打包出的文件中都包含了什么,以及模块之间的依赖关系
  • 每个文件的大小在总体中的占比,找出较大的文件,思考一下为什么,是否有替换方案,是否使用了它包含了不必要的依赖?
  • 是否有重复的依赖项,对此可以如何优化?
  • 每个文件的压缩后的大小。
2、测量构建时间
我们可以通过 speed-measure-webpack-plugin 测量你的 webpack 构建期间各个阶段花费的时间。
  1. 步骤一:安装依赖包

npm install speed-measure-webpack-plugin --save-dev
  1. 配置 vue.config.js
// 分析打包时间
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
// ...
module.exports = {
configureWebpack: smp.wrap({
plugins: [new BundleAnalyzerPlugin()]
})
}
打包构建后会看到以下输出

3c3a7d21096b8e58fb8d51a7cd9630dc.png

从以上的界面中,我们可以得到以下信息:

  • 分析整个打包总耗时;
  • 每个插件和 loader 的耗时情况;

找出问题所在后我们开始来总结一下优化方法。

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')]
}
]
}

注意:保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用此 loader。

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

  • extension 配置之后可以不用在 require 或是 import 的时候加文件扩展名,会依次尝试添加扩展名进行匹配。
  • alias 通过配置别名可以加快 webpack 查找模块的速度。
  resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
  • module.noParse:让 webpack 忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。因为如 jQueryechart 等库庞大又没有采用模块化标准,让 webpack 去解析这些文件耗时又没有意义。
module:{
noParse:/jquery/, //不去解析jquery中的依赖库
...
},

4、生产环境关闭 sourceMap

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

5、代码压缩

uglifyJsPlugin 是 vue-cli 默认使用的压缩代码方式,用来对js文件进行压缩,从而减小js文件的大小,加速load速度。它使用的是单线程压缩代码,打包时间较慢,所以可以在开发环境将其关闭,生产环境部署时再把它打开。

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

ParallelUglifyPlugin 开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成,每个子进程其实还是通过 UglifyJS 去压缩代码,但是变成了并行执行。

ParallelUglifyPlugin 还可以缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回。

plugins: [
new ParallelUglifyPlugin({
//cacheDir 用于配置缓存存放的目录路径。
cacheDir: '.cache/',
sourceMap: true,
uglifyJS: {
output: {
comments: false
},
compress: {
warnings: false
}
}
})
]

打包速度和打包后的文件大小对比

方法文件大小打包速度
不用插件14.6M32s
UglifyJsPlugin12.9M33s
ParallelUglifyPlugin7.98M17s

从上面可以看出,无论是打包时间还是打包后的文件大小,ParallelUglifyPlugin的方法都是最优的。

6、提取公共代码

在用 webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue 我们希望能和自己的代码分离开,这样既能减小打包的总体积,也能避免单个包体积过大。

webpack 社区有以下两种方案:

6.1、CommonsChunkPlugin 及 splitChunks

webpack3 使用 CommonsChunkPlugin 的实现:

CommonsChunkPlugin主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,从而导致加载时间过长,这是webpack 优化打包的一大利器。

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
})
]

CommonsChunkPlugin 的配置参数

  • name:可以是已经存在的chunk(一般指入口文件)对应的name,那么就会把公共模块代码合并到这个chunk上;否则,会创建名字为name的commons chunk进行合并
  • filename:指定commons chunk的文件名。
  • chunks:指定source chunk,即指定从哪些chunk当中去找公共模块,省略该选项的时候,默认就是entry chunks
  • minChunks:既可以是数字,也可以是函数,还可以是Infinity。

webpack4 使用 splitChunks 的实现:splitChunks 是webpack有一个默认配置,这也符合webpack4的开箱即用的特性

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

这是在一个额外的独立的 webpack 设置中创建一个只有 dll 的 bundle(dll-only-bundle)。这个插件会生成一个名为 manifest.json 的文件,这个文件是用来让 DLLReferencePlugin 映射到相关的依赖上去的。

使用步骤如下

6.2.1、在build下创建 webpack.dll.config.js

const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
vendor: [
'vue-router',
'vuex',
'vue/dist/vue.common.js',
'vue/dist/vue.js',
'vue-loader/lib/component-normalizer.js',
'vue',
'axios',
'echarts'
]
},
output: {
path: path.resolve('./dist'),
filename: '[name].dll.js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.resolve('./dist', '[name]-manifest.json'),
name: '[name]_library'
}),
// 建议加上代码压缩插件,否则dll包会比较大。
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
}

6.2.2、在 webpack.prod.conf.js 的 plugin 后面加入配置

new webpack.DllReferencePlugin({
manifest: require('../dist/vendor-manifest.json')
})

6.2.3、package.json文件中添加快捷命令(build:dll)

  "scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js",
"build:dll": "webpack --config build/webpack.dll.conf.js"
}

生产环境打包的时候先npm run build:dll命令会在打包目录下生成 vendor-manifest.json 文件与 vendor.dll.js 文件。然后npm run build生产其他文件。

6.2.4、根目录下的入口index.html加入引用

<script type="text/javascript" src="./vendor.dll.js">script>

7、CDN 优化

CDN 的全称是 Content Delivery Network,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN 的关键技术主要有内容存储和分发技术。

随着项目越做越大,依赖的第三方 npm 包越来越多,构建之后的文件也会越来越大。再加上又是单页应用,这就会导致在网速较慢或者服务器带宽有限的情况出现长时间的白屏。此时我们可以使用CDN的方法,优化网络加载速度。

7.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" />
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>

body>

7.2、在 webpack.config.js 配置文件

module.exports = {
···
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'element-ui': 'ELEMENT',
'Axios':'axios'
}
},

7.3、卸载依赖的 npm 包

npm uninstall axios element-ui vue vue-router vuex

7.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、多进程解析和处理文件

由于运行在 Node.js 之上的 webpack 是单线程模型的,所以 webpack 需要处理的事情需要一件一件的做,不能多件事一起做。当 webpack 需要打包大量文件时,打包时间就会比较漫长。

以下两个方法能让 webpack 在同一时刻处理多个任务发挥多核 CPU 电脑的功能,提升构建速度。

8.1、thread loader

把这个 thread loader 放置在其他 loader 之前, 放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行。

在 worker 池(worker pool)中运行的 loader 是受到限制的。例如:

  • 这些 loader 不能产生新的文件。
  • 这些 loader 不能使用定制的 loader API(也就是说,通过插件)。
  • 这些 loader 无法获取 webpack 的选项设置。

每个 worker 都是一个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。

module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: path.resolve('src'),
use: ['thread-loader', 'expensive-loader']
}
]
}
}
8.2、HappyPack

HappyPack 能让 webpack 把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。要注意的是 HappyPack 对 file-loader、url-loader 支持的不友好,所以不建议对该 loader 使用。

使用方法如下:

8.2.1. HappyPack 插件安装

npm i -D happypack

8.2.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']
}
]
}

8.2.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
})
]

注意,当项目较小时,多线程打包反而会使打包速度变慢。

总结

  1. 比较实用的方法: 按需加载,优化 loader 配置,关闭生产环境的 sourceMap,CDN 优化。
  2. vue-cli 已做的优化:代码压缩,提取公共代码,我们可以再根据自身需要进行相关配置优化。
  3. 一切优化因以不影响业务代码为前提。
f28e3955682a38515bb82839f5d3503e.png 也许你还想看 如何设计一款暗度陈仓的反爬虫 2020-03-26 20个你不得不知道的数组reduce高级用法 2020-02-13

聚焦全栈,专注分享 TypeScript、Web API、Node.js、Deno 等全栈干货。

f7e44b381ea210aca5c696114dbe2a17.png

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了优化webpack打包vue项目,你可以考虑以下几个方面: 1. 使用代码分割:将代码拆分成多个小块,按需加载,减小初始加载的文件大小。可以使用webpack的SplitChunksPlugin插件来进行代码分割。 2. 使用懒加载:对于一些不常用或者较大的模块,可以使用懒加载的方式来延迟加载,减小初始加载的文件大小。可以通过vue-router的异步路由或者webpack的import函数来实现。 3. 压缩代码:使用webpack的UglifyJsPlugin插件来压缩代码,减小文件体积。 4. 使用缓存:通过设置webpack的output.filename和output.chunkFilename选项来生成带有hash的文件名,以便浏览器能够缓存文件,减少重复请求。 5. 图片优化:将图片进行压缩和转换为base64编码,以减小文件大小。可以使用url-loader或者file-loader插件来处理图片。 6. 清除无用代码:使用webpack的Tree Shaking特性去除未使用的代码,减少输出文件体积。 7. 配置合理的Devtool选项:在开发环境中使用sourcemap来方便调试代码,而在生产环境中使用cheap-source-map或者none等选项来减小构建时间和文件大小。 8. 优化打包时的性能:使用happypack插件来多线程处理webpack的loader和babel-loader,使用ParallelUglifyPlugin插件来并行压缩代码,提高构建速度。 以上是一些常见的webpack打包vue项目的优化方法,你可以根据具体情况选择适合你项目的优化策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值