Webpack打包构建太慢了?试试几个方法
Webpack是个很流行的打包工具,但其打包速度却一直被吐槽着
如果不用上一些打包的优化建议,单单打包两三个文件就能花上好几秒,放上几十个入口文件依赖几百上千个包的话,几分钟十几分钟妥妥的
本文整理了常见的一些方法,部分使用之后就看到了很大改善,部分没什么明显的变化,也可能是项目规模还不够大,先记录一下方法也好
还是太慢了,快快使用Webpack4
一、使用监听模式或热更新热替换
webpack支持监听模式,此时需要重新编译时就可以进行增量构建,增量构建是很快的,基本不到一秒或几秒之内就能重新编译好
注意区分一下开发环境和线上环境,开发环境启用热更新替换
// 开发环境设置本地服务器,实现热更新
devServer: {
contentBase: path.resolve(__dirname, 'static'),
// 提供给外部访问
host: '0.0.0.0',
port: 8388,
// 允许开发服务器访问本地服务器的包JSON文件,防止跨域
headers: {
'Access-Control-Allow-Origin': '*'
},
// 设置热替换
hot: true,
// 设置页面引入
inline: true
}, // 文件输出配置
output: {
// 设置路径,防止访问本地服务器相关资源时,被开发服务器认为是相对其的路径
publicPath: 'http://localhost:8188/dist/js/',
}, // 插件配置
plugins: [
// 热更新替换
new webpack.HotModuleReplacementPlugin()
]
线上环境的编译,加个 --watch 参数就可以了
二、开发环境不做无意义的操作
很多配置,在开发阶段是不需要去做的,我们可以区分出开发和线上的两套配置,这样在需要上线的时候再全量编译即可
比如说 代码压缩、目录内容清理、计算文件hash、提取CSS文件等
三、选择一个合适的devtool属性值
配置devtool可以支持使用sourceMap,但有些是耗时严重的,这个得多试试
四、代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件
自带的JS压缩插件是单线程执行的,而webpack-parallel-uglify-plugin可以并行的执行,在我的小demo中使用后,速度直接从25s变成了14s
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}), ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin') new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false
}
}
}),
五、css-loader使用0.15.0以下的版本
听闻这个版本以上的速度会慢许多,不过在我的小demo中还没看到明显变化
六、使用fast-sass-loader代替sass-loader
fast-sass-loader可以并行地处理sass,在提交构建之前会先组织好代码,速度也会快一些
七、babel-loader开启缓存
babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率
可以加上cacheDirectory参数或使用 transform-runtime 插件试试
// webpack.config.js
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true
}] // .bablerc
{
"presets": [
"env",
"react"
],
"plugins": ["transform-runtime"]
}
八、不需要打包编译的插件库换成全局<script>标签引入的方式
比如jQuery插件,react, react-dom等,代码量是很多的,打包起来可能会很耗时
可以直接用标签引入,然后在webpack配置里使用 expose-loader 或 externals 或 ProvidePlugin 提供给模块内部使用相应的变量
// @1
use: [{
loader: 'expose-loader',
options: '$'
}, {
loader: 'expose-loader',
options: 'jQuery'
}] // @2
externals: {
jquery: 'jQuery'
}, // @3
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
九、使用 DllPlugin 和 DllReferencePlugin
这种方式其实和externals是类似的,主要用于有些模块没有可以在<script>标签中引入的资源(纯npm包)
Dll是动态链接库的意思,实际上就是将这些npm打包生成一个JSON文件,这个文件里包含了npm包的路径对应信息
这两个插件要一起用
首先,新建一个dll.config.js配置文件,先用webpack来打包这个文件
const webpack = require('webpack');
const path = require('path'); module.exports = {
output: {
// 将会生成./ddl/lib.js文件
path: path.resolve(__dirname, 'ddl'),
filename: '[name].js',
library: '[name]',
},
entry: {
"lib": [
'react',
'react-dom',
'jquery'
// ...其它库
],
},
plugins: [
new webpack.DllPlugin({
// 生成的映射关系文件
path: 'manifest.json',
name: '[name]',
context: __dirname,
}),
],
};
在manifest.json文件中就是相应的包对应的信息
然后在我们的项目配置文件中配置DllReferencePlugin 使用这个清单文件
// 插件配置
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json')
}),
十、提取公共代码
使用CommonsChunkPlugin提取公共的模块,可以减少文件体积,也有助于浏览器层的文件缓存,还是比较推荐的
// 提取公共模块文件
new webpack.optimize.CommonsChunkPlugin({
chunks: ['home', 'detail'],
// 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
name: 'common'
}), // 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
// 文件入口配置
entry: {
home: './src/js/home',
detail: './src/js/detail',
// 提取jquery入公共文件
common: ['jquery', 'react', 'react-dom']
},
十一、使用HappyPack来加速构建
HappyPack会采用多进程去打包构建,使用方式还是蛮简单的,但并不是支持所有的loader
首先引入,定义一下这个插件所开启的线程,推荐是四个,其实也可以直接使用默认的就行了
HappyPack = require('happypack'),
os = require('os'),
happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
然后在module的规则里改动一下,引入它,其中 id是一个标识符
{
test: /\.jsx?$/,
// 编译js或jsx文件,使用babel-loader转换es6为es5
exclude: /node_modules/,
loader: 'HappyPack/loader?id=js'
// use: [{
// loader: 'babel-loader',
// options: { // }
// }]
}
然后我们调用插件,设置匹配的id,然后相关的配置可以直接把use:的规则部分套在loaders上
new HappyPack({
id: 'js',
loaders: [{
loader: 'babel-loader',
options: {
// cacheDirectory: true
}
}]
}),
要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下
要注意的第二点是,使用ExtractTextWebpackPlugin提取css文件也不是完全就能转换过来,所以需要小小的改动一下,比如
module: {
rules: [{
test: /\.css$/,
// loader: 'HappyPack/loader?id=css'
// 提取CSS文件
use: cssExtractor.extract({
// 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
fallback: 'style-loader',
use: 'HappyPack/loader?id=css'
// use: [{
// loader: 'css-loader',
// options: {
// // url: false,
// minimize: true
// }
// },
// // 'postcss-loader'
// ]
})
}, {
test: /\.scss$/,
// loader: 'HappyPack/loader?id=scss'
// 编译Sass文件 提取CSS文件
use: sassExtractor.extract({
// 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
fallback: 'style-loader',
use: 'HappyPack/loader?id=scss'
// use: [
// 'css-loader',
// // 'postcss-loader',
// {
// loader: 'sass-loader',
// options: {
// sourceMap: true,
// outputStyle: 'compressed'
// }
// }
// ]
})
}
因为它是直接函数调用的,我们就放到里层的use规则就行了,然后配置插件即可
plugins: [
new HappyPack({
id: 'css',
loaders: [{
loader: 'css-loader',
options: {
// url: false,
minimize: true
}
}]
}),
new HappyPack({
id: 'scss',
loaders: [{
'loader': 'css-loader'
}, {
loader: 'fast-sass-loader',
options: {
sourceMap: true,
outputStyle: 'compressed'
}
}]
}),
十二、优化构建时的搜索路径
在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快
比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径
还可以善于用下resolve alias别名 这个字段来配置
还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的
{
test: /\.jsx?$/,
// 编译js或jsx文件,使用babel-loader转换es6为es5
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: { }
}]
}
十三、(导出编译JSON文件)理一下打包构建涉及的模块,分析看有哪些包是不需要打包的,只打包需要的模块
检查一下代码,看看是不是有不需要引入的模块出现在代码里
webpack编译时加上参数 --json > stat.json 后,可以上传到 webpack-analyse 、webpack-visualizer等分析站点上,看看打包的模块信息
十四、使用ModuleConcatenationPlugin插件来加快JS执行速度
这是webpack3的新特性(Scope Hoisting),其实是借鉴了Rollup打包工具来的,它将一些有联系的模块,放到一个闭包函数里面去,通过减少闭包函数数量从而加快JS的执行速度
new webpack.optimize.ModuleConcatenationPlugin({ })
十五、使用noParse
webpack打包的时候,有时不需要解析某些模块的依赖(这些模块并没有依赖,或者并根本就没有模块化),我们可以直接加上这个参数,直接跳过这种解析
module: {
noParse: /node_modules\/(jquey\.js)/
}
十六、使用异步的模块加载
这个算是可以减小模块的体积吧,在一定程度上也是为用户考虑的,使用require.ensure来设置哪些模块需要异步加载,webpack会将它打包到一个独立的chunk中,
在某个时刻(比如用户点击了查看)才异步地加载这个模块来执行
$('.bg-input').click(() => {
console.log('clicked, loading async.js') require.ensure([], require => { require('./components/async2').log();
require('./components/async1').log();
console.log('loading async.js done');
});
});
十七、以模块化来引入
有些模块是可以以模块化来引入的,就是说可以只引入其中的一部分,比如说lodash
// 原来的引入方式
import {debounce} from 'lodash'; //按模块化的引入方式
import debounce from 'lodash/debounce';
主要是整理过来的,试用了几个方法,首次编译的速度可以从之前半分多钟减小到十秒左右了,当然,开启了热更新替换后简直美不可言
当然还有很多方法没整理出,这些方法是有使用场景的,并不是每个都需要用,需要在自己的项目中尝试,结合配置它的复杂性和带来的效应来权衡。
Webpack打包构建太慢了?试试几个方法的更多相关文章
- Webpack打包进阶
说在前面 由于使用了React直出,页面各项性能指标使人悦目.本篇将深入探讨目前PC部落所采用webpack打包优化策略,以及探讨PC部落并未使用的 webpack Code Splitting 代码 ...
- 使用webpack打包js文件(隔行变色案例)
使用webpack打包js文件(隔行变色案例) 1.webpack安装的两种方式 运行npm i webpack -g全局安装webpack,这样就能在全局使用webpack的命令 在项目根目录中运行 ...
- Webpack 打包太慢? 试试 Dllplugin
webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~ 1. 介绍 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 rea ...
- Vue项目模板--和--webpack自动化构建工具的---项目打包压缩使用
[首先安装node.js]: 1. 从node.js官网下载并安装node,安装过程很简单. 2. npm 版本需要大于 3.0,如果低于此版本需要升级它: # 查看版本 npm -v2.3.0 #升 ...
- 实现webpack的实时打包构建
1. 由于每次重新修改代码之后,都需要手动运行webpack打包的命令,比较麻烦,所以使用`webpack-dev-server`来实现代码实时打包编译,当修改代码之后,会自动进行打包构建.2. 运行 ...
- webpack打包vue文件报错,但是cnpm run dev正常,最后我只想说:是我太笨,还是webpack4.4版本太坑
最近做一个项目,需要使用webpack打包 .vue 文件的单页面应用,调试都正常,使用cnpm run dev 都可以,就是webpack打包时报错.如下: ERROR in ./src/App.v ...
- 研究了一下 Webpack 打包原理,顺手挣了个 AirPods Pro
这些年,Webpack 基本成了前端项目打包构建的标配.关于它的原理和用法的文章在网上汗牛充栋,大家或多或少都看过一些.我也一样,大概了解过它的构建过程以及常用 loader 和 plugin 的配置 ...
- webpack进阶构建项目(一)
webpack进阶构建项目(一) 阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解ba ...
- 零基础学习webpack打包管理
这些天在项目之余的时间学习了webpack打包项目的东西,非常荣幸的找到一些大神的文章来学习,死劲嚼了几天,终于略知一二.在以后的工作上还需继续学习,下面我将分享我这几天学到的一点东西,希望能让我一个 ...
随机推荐
- 【Kafka】
KafkaProducer Kafka消息发布客户端. 线程安全,跨线程共享单个生产者实例通常比拥有多个实例的速度更快. 例子,使用生产者发送包含序列号的字符串作为键/值对的记录: Propertie ...
- HDFS概述(5)————HDFS HA
HA With QJM 目标 本指南概述了HDFS高可用性(HA)功能以及如何使用Quorum Journal Manager(QJM)功能配置和管理HA HDFS集群. 本文档假设读者对HDFS集群 ...
- 五年.net程序员转型Java之路
大学毕业后笔者进入一家外企,做企业CRM系统开发,那时候开发效率最高的高级程序语言,毫无疑问是C#.恰逢公司也在扩张,招聘了不少.net程序员,笔者作为应届生,也乐呵呵的加入到.net程序员行列中. ...
- Web的架构与html5基础知识
图1:完整的Web应用构架 图2:html5的基本结构 head 可添加在头部标签元素有→→title meta style link base script noscript meta 几个重要属性 ...
- Java历程-初学篇 Day02变量,数据类型和运算符
一,数据类型 1,基础数据类型 整型 byte short int long 浮点型 float double 字符型 char 布尔类型 boolean 2,引用类型 String 字符串型 二,变 ...
- Python实战之字符串的详细简单练习
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__' ...
- webpack html
调用了原模板 修改路径 使html放在JS外面 可以传递参数 多个html指定对应chunks 除了某些模块其余的都被引入
- OVS中arp响应的流表的实现
总结: 1.br-int 流表总体是按照Normal 的方式,即常规的交换机的转发方式进行转发.而br-tun 交换机则主要按照流表的方式进行转发. 2.一般情况下,VM发出的ARP请求,会在该VM的 ...
- MxNet新前端Gluon模型转换到Symbol
1. 导入各种包 from mxnet import gluon from mxnet.gluon import nn import matplotlib.pyplot as plt from mxn ...
- Android进程间通信
http://www.cnblogs.com/manuosex/p/3588634.html 一.Linux系统进程间通信有哪些方式? 1.socket: 2.name pipe命名管道: 3.mes ...