前言

这几天写腾讯实习生 Mini 项目的时候用上了 React 全家桶,当然同时引入了 Webpack 作为打包工具。但是开发过程中遇到一个很棘手的问题就是,React 加上 React-Router、superagent、eventproxy 这些第三方轮子一共有好几百个 module,Webpack 的打包速度极慢。这对于开发是非常不好的体验,同时效率也极低。
问题分析
我们先来看一下完全没有任何优化的时候,Webpack 的打包速度(使用了jsx和babel的loader)。
下面是我们的测试文件:
//test.js
var react = require('react');
var ReactAddonsCssTransitionGroup = require('react-addons-css-transition-group');
var reactDOM = require('react-dom');
var reactRouter = require('react-router');
var superagent = require("superagent");
var eventproxy = require("eventproxy");
运行
webpack test.js
在我的2015款RMBP13,i5处理器,全SSD下,性能是这样的:
没错你没有看错,这几个第三方轮子加起来有整整668个模块,全部打包需要20多秒。
这意味着什么呢?你每次对业务代码的修改,gulp 或者 Webpack 监测到后都会重新打包,你要足足等20秒才能看到自己的修改结果。
但是需要重新打包的只有你的业务代码,这些第三方库是完全不用重新打包的,它们的存在只会拖累打包性能。所以我们要找一些方法来优化这个过程。
配置externals
Webpack 可以配置 externals 来将依赖的库指向全局变量,从而不再打包这个库,比如对于这样一个文件:
import React from 'react'; console.log(React);
如果你在 Webpack.config.js 中配置了externals:
module.exports = {
externals: {
'react': 'window.React'
}
//其它配置忽略......
};
等于让 Webpack 知道,对于 react 这个模块就不要打包啦,直接指向 window.React 就好。不过别忘了加载 react.min.js,让全局中有 React 这个变量。
我们来看看性能,因为不用打包 React 了所以速度自然超级快,包也很小:
配置externals的缺陷
问题如果就这么简单地解决了的话,那我就没必要写这篇文章了,下面我们加一个 react 的动画库 react-addons-css-transition-group 来试一试:
import React from 'react'; import ReactAddonsCssTransitionGroup from 'react-addons-css-transition-group'; console.log(React);
对,你没有看错,我也没有截错图,新加了一个很小很小的动画库之后,性能又爆炸了。从模块数来看,一定是 Webpack 又把 react 重新打包了一遍。
我们来看一下为什么一个很小很小的动画库会导致 Webpack 又傻傻地把 react 重新打包了一遍。找到 react-addons-css-transition-group 这个模块,然后看看它是怎么写的:
// react-addons-css-transition-group模块
// 入口文件 index.js
module.exports = require('react/lib/ReactCSSTransitionGroup');
这个动画模块就只有一行代码,唯一的作用就是指向 react 下面的一个子模块,我们再来看看这个子模块是怎么写的:
// react模块
// react/lib/ReactCSSTransitionGroup.js
var React = require('./React');
var ReactTransitionGroup = require('./ReactTransitionGroup');
var ReactCSSTransitionGroupChild = require('./ReactCSSTransitionGroupChild');
//....剩余代码忽略
这个子模块又反回去依赖了 react 整个库的入口,这就是拖累 Webpack 的罪魁祸首。
总而言之,问题是这样产生的:
读到这里你可能会有疑问,为什么不能把这个动画库也设置到 externals 里,这样不是就不用打包了吗?
问题就在于,这个动画库并没有提供生产环境的文件,或者说这个库根本没有提供 react-addons-css-transition-group.min.js 这个文件。
这个问题不只存在于 react-addons-css-transition-group 中,对于 react 的大多数现有库来说都有这个依赖关系复杂的问题。
初级解决方法
所以对于这个问题的解决方法就是,手工打包这些 module,然后设置 externals ,让 Webpack 不再打包它们。
我们需要这样一个 lib-bundle.js 文件:
window.__LIB["react"] = require("react");
window.__LIB["react-addons-css-transition-group"] = require("react-addons-css-transition-group");
// ...其它依赖包
我们在这里把一些第三方库注册到了 window.__LIB 下,这些库可以作为底层的基础库,免于重复打包。
然后执行 webpack lib-bundle.js lib.js,得到打包好的 lib.js。然后去设置我们的 externals :
var webpack = require('webpack');
module.exports = {
externals: {
'react': 'window.__LIB["react"]',
'react-addons-css-transition-group': 'window.__LIB["react-addons-css-transition-group"]',
// 其它库
}
//其它配置忽略......
};
这时由于 externals 的存在,Webpack 打包的时候就会避开这些模块超多,依赖关系复杂的库,把这些第三方 module 的入口指向预先打包好的 lib.js 的入口 window.__LIB,从而只打包我们的业务代码。
终极解决方法
上面我们提到的方法本质上就是一种动态链接库(dll)”的思想,这在 windows 系统下面是一种很常见的思想。一个dll包,就是一个很纯净的依赖库,它本身不能运行,是用来给你的 app 或者业务代码引用的。
同样的 Webpack 最近也新加入了这个功能:webpack.DllPlugin。使用这个功能需要把打包过程分成两步:
首先我们来打包ddl包,首先配置一个这样的 ddl.config.js:
const webpack = require('webpack');
const vendors = [
'react',
'react-dom',
'react-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,
}),
],
};
webpack.DllPlugin 的选项中:
运行Webpack,会输出两个文件一个是打包好的 lib.js,一个就是 manifest.json,它里面的内容大概是这样的:
{
"name": "vendor_ac51ba426d4f259b8b18",
"content": {
"./node_modules/react/react.js": 1,
"./node_modules/react/lib/React.js": 2,
"./node_modules/react/node_modules/object-assign/index.js": 3,
"./node_modules/react/lib/ReactChildren.js": 4,
"./node_modules/react/lib/PooledClass.js": 5,
"./node_modules/react/lib/reactProdInvariant.js": 6,
// ............
}
}
接下来我们就可以快乐地打包业务代码啦,首先写好打包配置文件 webpack.config.js:
const webpack = require('webpack');
module.exports = {
output: {
path: 'build',
filename: '[name].js',
},
entry: {
app: './src/index.js',
},
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json'),
}),
],
};
webpack.DllReferencePlugin 的选项中:
DllPlugin 本质上的做法和我们手动分离这些第三方库是一样的,但是对于包极多的应用来说,自动化明显加快了生产效率。
总结
以上就是关于彻底解决Webpack打包慢问题的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# webpack
# 打包太慢
# 打包速度慢
# webpack打包过慢
# 解决webpack打包速度慢的解决办法汇总
# Webpack打包构建太慢试试这几个提升打包速度方案
# 第三方
# 是这样
# 一遍
# 包了
# 解决方法
# 这个问题
# 这样一个
# 要跟
# 本质上
# 看错
# 自己的
# 我也
# 就会
# 都有
# 在这里
# 是一种
# 会有
# 你要
# 这就是
# 没有任何
相关文章:
如何在万网自助建站平台快速创建网站?
如何选择适合PHP云建站的开源框架?
c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】
如何高效生成建站之星成品网站源码?
孙琪峥织梦建站教程如何优化数据库安全?
,购物网站怎么盈利呢?
c++ stringstream用法详解_c++字符串与数字转换利器
如何选择高效可靠的多用户建站源码资源?
建站之星后台搭建步骤解析:模板选择与产品管理实操指南
PHP 500报错的快速解决方法
天津个人网站制作公司,天津网约车驾驶员从业资格证官网?
建站之星如何实现PC+手机+微信网站五合一建站?
赚钱网站制作软件,建一个网站怎样才能赚钱?是如何盈利的?
建站之星如何实现五合一智能建站与营销推广?
如何在建站宝盒中设置产品搜索功能?
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
建站之星客服服务时间及联系方式如何?
建站之星如何配置系统实现高效建站?
如何通过西部建站助手安装IIS服务器?
制作网站的基本流程,设计网站的软件是什么?
,巨量百应是干嘛的?
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?
宝塔面板创建网站无法访问?如何快速排查修复?
建站之星价格显示格式升级,你的预算足够吗?
jQuery 常见小例汇总
制作网站外包平台,自动化接单网站有哪些?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
导航网站建站方案与优化指南:一站式高效搭建技巧解析
平台云上自主建站:模板化设计与智能工具打造高效网站
建站之星免费版是否永久可用?
制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?
C#如何序列化对象为XML XmlSerializer用法
如何在万网开始建站?分步指南解析
黑客如何通过漏洞一步步攻陷网站服务器?
Python如何创建带属性的XML节点
建站之星如何优化SEO以实现高效排名?
开心动漫网站制作软件下载,十分开心动画为何停播?
C#怎么使用委托和事件 C# delegate与event编程方法
建站之星IIS配置教程:代码生成技巧与站点搭建指南
如何制作网站标识牌,动态网站如何制作(教程)?
寿县云建站:智能SEO优化与多行业模板快速上线指南
如何在阿里云购买域名并搭建网站?
已有域名建站全流程解析:网站搭建步骤与建站工具选择
如何挑选最适合建站的高性能VPS主机?
高端智能建站公司优选:品牌定制与SEO优化一站式服务
行程制作网站有哪些,第三方机票电子行程单怎么开?
建站之星各版本价格是多少?
巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成
建站主机无法访问?如何排查域名与服务器问题
如何在IIS管理器中快速创建并配置网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。