提升webpack打包速度
webpack打包文件体积过大,怎么提升速度?
借助webpack visualizer可视化插件,来看构建的情况。
这个问题要具体情况具体分析,看看打包文件有哪些块头比较大,哪些不常改变,最好列一个list,分类优化。下面提供8种方法,仅供参考。
一、区分配置文件,去除不必要的插件。
前端开发环境通常分为两种:开发环境和生产环境,我们可以创建两个配置文件来区分开发环境和生产环境。
webpack.config.dev.js,用于开发环境,需要日志输出,sourcemap,热模块替换,错误报告等。
webpack.config.prod.js,用于生产环境,需要做代码压缩,对文件名进行hash处理等。
//安装webpack-merge npm install --save-dev webpack-merge
//webpack.config.common.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
//webpack.config.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.config.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
});
//webpack.config.prod.js
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.config.common.js');
module.exports = merge(common, {
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({
sourceMap: true
})
]
});
在webpack.config.common.js中,我们设置了entry和output配置,并且在其中引入这两个环境公用的全部插件。在webpack.config.dev.js中,我们添加了推荐的devtool(强大的 source map)和简单的devServer配置。在webpack.config.prod.js中,我们引入了UglifyJSPlugin。
修改package.json文件
"scripts": {
"dev": "webpack-dev-server --open --config webpack.config.dev.js",
"prod": "webpack --config webpack.config.prod.js"
}
二、合理使用CommonsChunkPlugin插件,提取公用代码。
该方法适用于开发环境和生产环境,具体用法在下面有介绍。
三、通过externals配置来引用外部文件的方式,提取第三方库。
{
externals: {
'react': 'React'
}
}
<script src="//cdn.com/vue.min.js"></script> <script src="/build/bundle.js"></script>
该方法适用于生产环境。
四、利用DllPlugin和DllReferencePlugin预编译资源模块,提取第三方库。
const vendors = [
'vue','vue-router',
// ...其它库
];
module.exports = {
output: {
path: 'build',
filename: '[name].js',
library: '[name]'
},
entry: {
"lib": vendors
},
plugins: [
new webpack.DllPlugin({
path: 'manifest.json',
name: '[name]',
context: __dirname
})
]
};
该方法适用于开发环境和生产环境。
五、压缩代码
使用tree shaking,即先用es6语法import,export,再引入删除引用代码的压缩工具UglifyJsPlugin。
new webpack.optimize.UglifyJsPlugin({
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
compress: {
//在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
//用于压缩的时候去除log
drop_debugger: true,
drop_console: true,
//内嵌定义了但是只用到一次的变量
collapse_vars: true,
//提取出现多次但是没有定义成变量去引用的静态值
reduce_vars: true
}
})
加入了这个插件之后,编译的速度会明显变慢,所以一般只在生产环境启用。如果服务器端可以开启gzip压缩,优化的效果更明显。
另外,可以通过webpack-parallel-uglify-plugin来提升压缩速度,原理是采用多核并行压缩的方式提升速度。
let ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
let os = require('os');
new ParallelUglifyPlugin({
workerCount: os.cpus().length,
cacheDir: '.cache/',
uglifyJS: {
output: {
comments: false
},
compress: {
warnings: false
}
}
})
该方法适用于生产环境。
var HappyPack = require('happypack');
const os = require('os');
const HappyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
//启动线程池
let happyPackConfig = {
plugins: [
new HappyPack({
id:'jsx',
threadPool: HappyThreadPool,
cache: true,
loaders: ['babel-loader']
})
]
}
{
test: /.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'HappyPack/loader?id=jsx'
}
}
七、代码分割
分离代码,实现缓存资源和并行加载资源。
对于大型app而言,将所有代码都放在一个文件中是不高效的,尤其是一些代码块只要某些情况下才需要加载。webpack有一个特性,就是能够对项目进行代码分割。代码分割不只是提取通用代码放入可分享的块,更重要的是可以将代码分割成按需加载的块。代码分割可选择,可定义分割点,下面介绍几种分割代码的方法。
1、entry
当项目多入口点时,必须改写默认的output.filename选项,否则每个入口点都会写入相同的文件。
A、多个入口文件,打包在一起;
'use strict';
const webpack = require("webpack");
module.exports = {
context: __dirname + "/src",
entry: {
app: ["./file1.js", "./file2.js", "./file3.js"]
},
output: {
path: __dirname + "/dist",
filename: "[name].bundle.js"
}
};
打包结果:所有文件会按数组顺序一起打包到dist/app.bundle.js文件中。
B、多个入口文件,分开打包。
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
file1: "./file1.js",
file2: "./file2.js",
file3: "./file3.js"
},
plugins: [
new HTMLWebpackPlugin({
title: 'Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
打包结果:dist/file1.bundle.js、dist/file2.bundle.js、dist/file3.bundle.js。
2、CommonsChunkPlugin插件
防止重复,移除重复的依赖模块。
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
file1: "./file1.js",
file2: "./file2.js",
file3: "./file3.js"
},
plugins: [
new HTMLWebpackPlugin({
title: 'Code Splitting'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common' // 指定公共bundle的名称。
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
3、动态import
ES2015模块加载规范定义了import()方法来运行时动态地加载ES2015模块,webpack2将import()作为分割点并将被请求的模块放到一个单独的chunk中,import()接收模块名作为参数,并返回一个Promise。
//webpack.config.js
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
// src/index.js
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}).catch(error => 'An error occurred while loading the component');
}
getComponent().then(component => {
document.body.appendChild(component);
});
在注释中使用了webpackChunkName,这样做会导致我们的bundle被命名为lodash.bundle.js,而不是[id].bundle.js 。
4、commonjs的require.ensure
require.ensure(dependencies, callback);
require.ensure方法确保回调时,dependencies里的每个依赖都会被同步的引入,require作为参数传递到回调函数中。require.ensure只加载模块,并不执行。
require.ensure(["module-a", "module-b"], function(require) {
var a = require("module-a");
// ...
});
5、AMD的require
reuqire(dependices, callback);
调用时,所有依赖都被加载,callback函数中能得到依赖暴露出来的对象。AMD的require加载并执行模块,在webpack中,模块由左向右执行,允许省略回调函数。
require(["module-a", "module-b"], function (a, b) {// ...})
6、按需加载
像d3,echarts,lodash,antd,比较大,没必要全部加载。
let d3 = Object.assign({},
require("d3-selection"),
require("d3-transition"),
require("d3-shape")
);
//为d3.event加上get方法,获取d3Selection.event
Object.defineProperty(d3,"event", {get: function() { return d3Selection.event; }});
// 引入echarts主模块
var echarts = require('echarts/lib/echarts');
//引入柱状图
require('echarts/lib/component/bar');
//引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
//基于准备好的dom,初始化echarts
var myChart = echarts.init(document.getElementById('main'));
//绘制图表
myChart.setOption({
title: { text:'走向社会'},
tooltip:{},
xAxis:{ data:['2013年','2014年','2015年','2016年','2017年','2018年']},
yAxis: {},
series: [{
name: '技术积累',
type: 'bar',
data: [5,8,11,15,19,23]
}]
})
## 安装lodash相关插件 cnpm i -S lodash-webpack-plugin babel-plugin-lodash
//配置webpack.config.js
var LoashModuleReplacementPlugin = require('lodash-webpack-plugin');
{
...,
plugins: [
...,
new LodashModuleReplacementPlugin({
'collections': true,
'shorthands': true
})
]
}
//在.babelrc中增加lodash配置
{
"plugins": [..., "lodash"]
}
//引用一次,即可调用任意函数,而不会完全打包 import _ from 'lodash'; _.add(1,2); //打包时,只会引入add函数
八、缓存不常修改的库文件
不要在开发环境下使用[chunkhash],因为这会增加编译时间。将开发和生产模式的配置分开,并在开发模式中使用[name].js的文件名,在生产模式中使用[name].[chunkhash].js文件名。
1、output.filename
var path = require("path");
var webpack = require("webpack");
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");
var WebpackChunkHash = require("webpack-chunk-hash");
module.exports = {
entry: {
vendor: "./src/vendor.js",
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].[chunkhash:8].js",
chunkFilename: "[name].[chunkhash:8].js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "manifest"],
minChunks: Infinity
}),
new webpack.HashedModuleIdsPlugin(),
new WebpackChunkHash(),
new ChunkManifestPlugin({
filename: "chunk-manifest.json",
manifestVariable: "webpackManifest"
})
]
};
提升webpack打包速度的更多相关文章
- 优化webpack打包速度方案
基本原理要么不进行打包:要么缓存文件,不进行打包:要么加快打包速度. 不进行打包方案: 1,能够用CDN处理的用CDN处理,比如项目引入的第三方依赖jquery.js,百度编辑器 先进行打包或者缓存然 ...
- webpack打包速度和性能再次优化
一. 改单dll为双dll 因为上图原因,使用CommonsChunkPlugin时,导致其打包出来的vendors.js内的模块ID会因为其他文件引用模块数量的变化而变化. 所以现利用DllPlug ...
- 优化Webpack打包速度
1. Webpack 可以配置 externals 来将依赖的库指向全局变量,从而不再打包这个库,比如对于这样一个文件: import React from 'react'; console.lo ...
- 解决webpack打包速度慢的解决办法
技巧1 webpack在打包的时候第一次总是会做很长的准备工作,包括加载插件之类的.在刚接触webpack的时候总是webpack一下-测一下-改一下-再webpack一下,这种方式最后让很多人崩溃了 ...
- Webpack 打包优化之速度篇
在前文 Webpack 打包优化之体积篇中,对如何减小 Webpack 打包体积,做了些探讨:当然,那些法子对于打包速度的提升,也是大有裨益.然而,打包速度之于开发体验和及时构建,相当重要:所以有必要 ...
- webpack打包性能分析
1. 如何定位webpack打包速度慢的原因 首先需要定位webpack打包速度慢的原因,才能因地制宜采取合适的方案,我们可以在终端输入: webpack --profile --json > ...
- Webpack 打包太慢? 试试 Dllplugin
webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~ 1. 介绍 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 rea ...
- vuecli中配置webpack加快打包速度
webpack4中webpack 的DllPlugin插件可以将常见的库文件作为dll文件来,每次打包的时候就不用再次打包库文件了. 但是游鱼西在vuecli中已经去除这个选项,意识到带来的打包速度提 ...
- 如何将 iOS 工程打包速度提升十倍以上
如何将 iOS 工程打包速度提升十倍以上 过慢的编译速度有非常明显的副作用.一方面,程序员在等待打包的过程中可能会分心,比如刷刷朋友圈,看条新闻等等.这种认知上下文的切换会带来很多隐形的时间浪费. ...
随机推荐
- Shell入门及实践
解释器 解释器是一种命令解释器,主要作用是对命令进行运行和解释,将需要执行的操作传递给操作系统内核并执行 #!/bin/bash(默认),指定解释器 #!/bin/bash #这是第一个shell脚本 ...
- mysql数据库建表的基本规范
1.创建表的时候必须指定主键,并且主键建立后最好不要再有数据修改的需求 mysql从5.5版本开始默认使用innodb引擎,innodb表是聚簇索引表,也就是说数据通过主键聚集( 主键下存储该行的数据 ...
- JavaProperties类、序列化流与反序列化流、打印流、commons-IO整理
Properties类 Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串. 特点: 1.Hashtable的子类 ...
- Numpy 系列(八)- 广播机制
什么是广播 我们都知道,Numpy中的基本运算(加.减.乘.除.求余等等)都是元素级别的,但是这仅仅局限于两个数组的形状相同的情况下. 可是大家又会发现,如果让一个数组加1的话,结果时整个数组的结果都 ...
- 使用 gzexe 快速加密解密文件内容
使用 gzexe 快速加密解密文件内容 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.使用sshpass工具编写远程管理脚本 1>.安装依赖包 [root@node101 ...
- (转)如何阅读OpenStack源码
1 关于该项目 本项目使用在线绘图工具web sequencediagrams完成,目标是图形化OpenStack的所有操作流程,通过操作序列图能快速学习Openstack的工作原理,理清各个组件的关 ...
- VMware 设置网络
在VMware上安装 系统完成后,设置虚拟网络 这里的VMware 版本为 14. 本文以window server 2016 为例. 在虚拟机上菜单栏中, 编辑 >> 虚拟网络编辑器 ...
- DirectX11 With Windows SDK--21 鼠标拾取
前言 拾取是一项非常重要的技术,不论是电脑上用鼠标操作,还是手机的触屏操作,只要涉及到UI控件的选取则必然要用到该项技术.除此之外,一些类似魔兽争霸3.星际争霸2这样的3D即时战略游戏也需要通过拾取技 ...
- NOI-OJ 1.12 ID:10 素数对
整体思路 本题涉及大量素数的使用,故使用埃拉拖色尼算法提前计算出素数表可以避免大量.重复的计算. 判断素数对很简单,使用两个变量p1和p2代表素数表中的第一个和第二个素数,依次在表中向后移动,判断p2 ...
- [Luogu P1144]最短路计数
emmmm这个题看起来非常复杂,实际上仔细一分析发现到一个点最短路的个数就是所有前驱最短路个数之和.如果在图上表示也就是以1为根的bfs搜索树,一个点的最短路个数等于每一个能够向它扩展的所有点的最短路 ...