webpack lib怎么打lib包

完整的 webpack2 开发环境与生产环境打包配置
webpack 这一打包神器想必大家早已使用了,不过那差劲的官方文档真是搞晕不少入门者。
之前说 webpack 的文档差,现在必须纠正一下。可能是官方也听到一些文档不好看的话语了,所以…,在 webpack 2 的文档上真是下大功夫了。
更值得学习的是,在使用过程中,发现 webpack2 在错误处理上也引入了大量的文档类提示,对程序员真是太贴心了。
因为这个,把原来的 webpack1 环境改成 webpack2 时,比想象的要顺利的多,按它的提示走就行。
在这里,分享一套完整的 WEBPACK 2 打包配置,笔者已经在实际项目中使用了一年多,没有什么问题。
希望对大家有所帮助。
直接看项目吧
原来的 webpack1 环境在 webpack1 分支上。
基本打包功能
eslint 校验;
使用 ExtractTextPlugin 将 js 和 css 分离,保证打包文件的整洁,最终会生成 /app.js 和 /app.css两个文件,文件名按自己情况随意改;
默认支持 LESS ,其它的如 SASS 自己可以改;
资源文件压缩合并 (废话~);
小于 8KB 的图片会以 base64 打进 CSS 中,其它按 [name].[ext] 的文件名进行输出;
图片压缩,但非常耗时,默认没有开启!img-loader?minimize;
支持最新的 ES6/7 + reactjs 语法,支持 mobx 注解。
一些打包优化,等等…
开发环境使用 webpack-hot-server。
基础启动命令:
$ webpack-dev-server --config webpack-dev-server.config.js --progress --inline --colors --env.app=demo
其中 --env.app=demo 是自定义环境参数,用于指定打包入口文件。
启动后会在本地启一个 server,将打包的结果:一个 JS 和一个 CSS 发布出去,如:
http://localhost:9080/app.js
http://localhost:9080/app.css
代码实时生效,支持 live-load, 比用 webpack --watch 快速的多。
一般基础的功能都包含在内,这里就不多说了,可以自己看代码。
基础启动命令:
$ webpack --config webpack-production.config.js --progress --colors [--watch] --env.app=demo
生产环境中针对公共模块的分离,实现了两种文案,在配置文件中,用大段的 = 注释隔开,两者选其一:
CommonsChunkPlugin,在每次打包中,都会把一些例如:react、react-dom 等公共模块单独打包,实际对每次打包的过程没有什么改善。
DllReferencePlugin,这个方案对公共模块的分离就比较彻底了,在执行这套方案前,先要单独执行一次 dll 的打包:npm run dll,
这样,在对业务代码进行打包时,会通过 mainifest 文件排除 dll 的公共模块,这样会大幅的减少打包时间,打出的 app.js 是纯业务代码,
当然,页面使用时需要将 react.dll.js、router.dll.js、app.js 依次引入。
推荐使用 DllReferencePlugin 的方案,这对于后期的更新上线、多个项目打包的支持都很有优势。
简单的命令行封装
对于生产环境的打包命令,因为一个构建系统要支持多个项目,入口文件各不相同,每次打包都要在配置文件中修改入口文件实在不方便,而且每次的打包命令还挺长的。
因此,写一个简单的 wpbuild.js 脚本,支持要打包项目路径的参数,也省了一堆的 webpack 命令参数。只用调用
node wpbuild.js --(`demo` or `demo/app.jsx`) [--server:启动开发 server] [--watch:生产环境的 watch 模式]
其中指定入口文件是相对 src的路径,参数有两种形式:
可以只写文件夹名称,如 --demo,此时会默认选择 demo/app.jsx 为入口文件
完整的入口文件路径,如 --demo/xxx/app.jsx
// for product
npm run dll (这个是lib打包,只需要一次)
node wpbuild --demo --watch
// for dev
node wpbuild --demo --server
支持 mobx 的注解。内置一个 demo 例子,可以自己尝试。43被浏览1341分享邀请回答4添加评论分享收藏感谢收起45 条评论分享收藏感谢收起查看更多回答14:31:33 UTC
我在按照web pack-howto 中的说明生成了生产配置并将使用cnpm run deploy生成真实文件后,出现这样的warning 搜索没找到太多资料 请大家指教
fengliu@fengdeMacBook-Air [10:24:27] [~/www/webpack-react] [release/1.0 *]
-& % cnpm run deploy
& itfanr-borrow@0.0.1 deploy /Users/fengliu/www/webpack-react
& NODE_ENV=production webpack -p --config webpack.production.config.js
The unused option is deprecated. Please use options.discardUnused instead.
The urls option is deprecated. Please use options.normalizeUrl instead.
The idents option is deprecated. Please use options.mergeIdents instead.
The idents option is deprecated. Please use options.reduceIdents instead.
Hash: a9c5d6b9e6afc081586d
Version: webpack 1.12.0
Time: 31316ms
Chunk Names
+ 304 hidden modules
WARNING in bundle.js from UglifyJs
Dropping side-effect-free statement [./app/main.js:4,0]
Side effects in initialization of unused variable React [./~/amazeui-react/lib/mixins/ClassNameMixin.js:3,0]
Condition always true [./~/amazeui-react/~/classnames/index.js:39,0]
Side effects in initialization of unused variable redraw [./~/amazeui/js/core.js:264,0]
Condition always true [./~/amazeui/~/jquery/dist/jquery.js:9170,0]
Side effects in initialization of unused variable React [./~/amazeui-react/lib/mixins/SmoothScrollMixin.js:8,0]
Condition always true [./~/amazeui-react/~/fecha/fecha.js:256,2]
Dropping unreachable code [./~/amazeui-react/~/fecha/fecha.js:261,0]
Side effects in initialization of unused variable point [./~/amazeui/js/ui.iscroll-lite.js:526,0]
Side effects in initialization of unused variable rf [./~/amazeui/js/ui.iscroll-lite.js:644,0]
Side effects in initialization of unused variable $ [./~/amazeui/js/ui.iscroll-lite.js:3,0]
Non-strict equality against boolean: == false [./~/amazeui/js/ui.flexslider.js:990,0]
Side effects in initialization of unused variable classNames [./~/amazeui-react/lib/FormFile.js:4,0]
Side effects in initialization of unused variable Button [./~/amazeui-react/lib/FormFile.js:6,0]
Side effects in initialization of unused variable AvgGrid [./~/amazeui-react/lib/Titlebar.js:6,0]
Side effects in initialization of unused variable constants [./~/amazeui-react/lib/UCheck.js:11,0]
Side effects in initialization of unused variable $ [./~/amazeui/js/ui.progress.js:3,0]
Dropping unused function appendWeChatSDK [./~/amazeui/widget/wechatpay/src/wechatpay.js:10,0]
Side effects in initialization of unused variable Grid [./app/RightBody.js:7,4]
Side effects in initialization of unused variable Col [./app/RightBody.js:8,4]
Condition always true [./~/jquery/dist/jquery.js:9170,0]
Side effects in initialization of unused variable sourceMap [./~/style-loader/addStyles.js:185,0]
Side effects in initialization of unused variable media [./~/style-loader/addStyles.js:203,0]
Condition always false [./~/style-loader/addStyles.js:23,0]
Dropping unreachable code [./~/style-loader/addStyles.js:24,0]
Condition always false [./~/style-loader!./~/css-loader!./app/css/main.css:10,0]
Dropping unreachable code [./~/style-loader!./~/css-loader!./app/css/main.css:12,0]
Side effects in initialization of unused variable update [./~/style-loader!./~/css-loader!./app/css/main.css:7,0]
08:03:51 UTC
这个有些是第三方库的代码不规范,例如:jquery、amazeui。有些是你的代码不规范,UglifyJs现在还要做lint了?我估计可以配置UglifyJs对于第三方库的代码忽略lint,只lint你的代码,然后你只需要把你的代码不规范的地方修改掉就行了
09:47:58 UTC
晓得了,就是语法不规范的问题啊谢谢
05:26:19 UTC
最后是怎么解决了这个问题的呢?我现在也遇到了这个问题,我的webpack.config.js是这样的:
var webpack = require('webpack');
var path = require('path');
module.exports = {
devtool: 'inline-source-map',
'webpack-dev-server/client?http://127.0.0.1:8080/',
'webpack/hot/only-dev-server',
path: path.join(__dirname, 'build'),
filename:'bundle.js'
resolve: {
modulesDirectories: ['node_modules', 'app'],
extensions: ['','.js']
loaders: [
test:/\.jsx?$/,
exclude:/node_modules/,
'react-hot','babel?presets[]=react,presets[]=es2015'
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin()
运行 webpack之后:
WARNING in bundle.js from UglifyJsCondition always true [./~/react/lib/ReactMount.js:764,0]Dropping side-effect-free statement [./~/react-router/lib/deprecateObjectProperties.js:65,0]Side effects in initialization of unused variable _ret [./~/react-router/lib/deprecateObjectProperties.js:63,0]Condition always true [./~/react/lib/findDOMNode.js:46,0]Condition always true [./~/react/lib/instantiateReactComponent.js:80,0]Dropping unreachable code [./~/react/lib/shouldUpdateReactComponent.js:40,0]Condition always true [./~/react/lib/traverseAllChildren.js:158,0]Condition always true [./~/react-router/lib/Redirect.js:97,0]Side effects in initialization of unused variable _reactRouter [./modules/App.js:2,0]Condition always true [./~/react-router/lib/IndexRedirect.js:58,0]Condition always true [./~/react-router/lib/IndexRoute.js:55,0]Condition always true [./~/react-router/lib/Route.js:50,0]Dropping side-effect-free statement [./~/react-router/lib/getComponents.js:49,0]
Side effects in initialization of unused variable _ret2 [./~/react-router/lib/getComponents.js:47,0]Condition always true [./~/react-router/~/history/lib/createMemoryHistory.js:67,0]Condition always true [./~/react/lib/ReactDOMComponent.js:907,0]Dropping side-effect-free statement [./~/react/lib/ReactEventListener.js:72,0]Dropping unused function handleTopLevelWithPath [./~/react/lib/ReactEventListener.js:98,0]Dropping unused variable DOCUMENT_FRAGMENT_NODE_TYPE [./~/react/lib/ReactEventListener.js:26,0]
14:05:41 UTC
这是uglify的一些警告信息,可以通过以下代码抑制:
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compress: {
warnings: false,彻底解决Webpack打包性能问题a year ago运行webpack test.js
在我的2015款RMBP13,i5处理器,全SSD下,性能是这样的:没错你没有看错,这几个第三方轮子加起来有整整668个模块,全部打包需要20多秒。这意味着什么呢?你每次对业务代码的修改,gulp 或者 Webpack 监测到后都会重新打包,你要足足等20秒才能看到自己的修改结果。但是需要重新打包的只有你的业务代码,这些第三方库是完全不用重新打包的,它们的存在只会拖累打包性能。所以我们要找一些方法来优化这个过程。配置externalsWebpack 可以配置 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 的罪魁祸首。总而言之,问题是这样产生的:Webpack 发现我们依赖了 react-addons-css-transition-group; Webpack 去打包 react-addons-css-transition-group 的时候发现它依赖了 react 模块下的一个叫 ReactTransitionGroup.js 的文件,于是 Webpack 去打包这个文件;ReactTransitionGroup.js 依赖了整个 react 的入口文件 React.js,虽然我们设置了 externals ,但是 Webpack 不知道这个入口文件等效于 react 模块本身,于是我们可爱又敬业的 Webpack 就把整个 react 又重新打包了一遍。读到这里你可能会有疑问,为什么不能把这个动画库也设置到 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包,打包业务代码首先我们来打包ddl包,首先配置一个这样的 ddl.config.js:const webpack = require('webpack');
const vendors = [
'react-dom',
'react-router',
// ...其它库
module.exports = {
path: 'build',
filename: '[name].js',
library: '[name]',
"lib": vendors,
plugins: [
new webpack.DllPlugin({
path: 'manifest.json',
name: '[name]',
context: __dirname,
webpack.DllPlugin 的选项中:path 是 manifest.json 文件的输出路径,这个文件会用于后续的业务代码打包;name 是 dll 暴露的对象名,要跟 output.library 保持一致;context 是解析包路径的上下文,这个要跟接下来配置的 webpack.config.js 一致。运行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 = {
path: 'build',
filename: '[name].js',
app: './src/index.js',
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json'),
webpack.DllReferencePlugin 的选项中:context 需要跟之前保持一致,这个用来指导 Webpack 匹配 manifest.json 中库的路径;manifest 用来引入刚才输出的 manifest.json 文件。DllPlugin 本质上的做法和我们手动分离这些第三方库是一样的,但是对于包极多的应用来说,自动化明显加快了生产效率。赞赏还没有人赞赏,快来当第一个赞赏的人吧!339收藏分享举报文章被以下专栏收录简介 is not defined推荐阅读{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[{&sourceColumn&:{&lastUpdated&:,&description&:&&,&permission&:&COLUMN_PUBLIC&,&memberId&:1360792,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&简介 is not defined&,&urlToken&:&starkwang&,&id&:11622,&imagePath&:&faead8d536.jpeg&,&slug&:&starkwang&,&applyReason&:&0&,&name&:&一只码农的技术日记&,&title&:&一只码农的技术日记&,&url&:&https:\u002F\\u002Fstarkwang&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:4933,&avatar&:{&id&:&faead8d536&,&template&:&https:\u002F\\u002F{id}_{size}.jpeg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\\u002Ffaead8d536_l.jpeg&,&articlesCount&:26},&state&:&accepted&,&targetPost&:{&titleImage&:&https:\u002F\\u002F897c2df2f21aa6b2f9f4a_r.png&,&lastUpdated&:,&imagePath&:&897c2df2f21aa6b2f9f4a.png&,&permission&:&ARTICLE_PUBLIC&,&topics&:[,225],&summary&:&这几天写腾讯实习生 Mini 项目的时候用上了 react 全家桶,当然同时引入了 Webpack 作为打包工具。但是开发过程中遇到一个很棘手的问题就是,react 加上 react-router、material-ui、superagent、eventproxy 这些第三方轮子一共有好几百个 module,Webpack …&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:0,&publishedTime&:&T14:51:58+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:883604,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&彻底解决Webpack打包性能问题&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:11622,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&https:\u002F\\u002F897c2df2f21aa6b2f9f4a_r.png&,&author&:{&bio&:&企鹅培育与饲养&,&isFollowing&:false,&hash&:&d965f32ae58ad3a48a1585a4&,&uid&:68,&isOrg&:false,&slug&:&starkwei&,&isFollowed&:false,&description&:&\u002Fstarkwang&,&name&:&Stark伟&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fstarkwei&,&avatar&:{&id&:&v2-cfafbe3e362ecf37f1d5fcb7f488f13c&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:1360792,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:402137}],&title&:&彻底解决Webpack打包性能问题&,&author&:&starkwei&,&content&:&\u003Cp\u003E这几天写腾讯实习生 Mini 项目的时候用上了 react 全家桶,当然同时引入了 Webpack 作为打包工具。但是开发过程中遇到一个很棘手的问题就是,react 加上 react-router、material-ui、superagent、eventproxy 这些第三方轮子一共有好几百个 module,Webpack 的打包速度极慢。这对于开发是非常不好的体验,同时效率也极低。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E问题分析\u003C\u002Fh2\u003E\u003Cp\u003E我们先来看一下完全没有任何优化的时候,Webpack 的打包速度(使用了jsx和babel的loader)。下面是我们的测试文件:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002Ftest.js\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ereact\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReactAddonsCssTransitionGroup\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'react-addons-css-transition-group'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EreactDOM\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'react-dom'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EreactRouter\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'react-router'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Esuperagent\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&superagent\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eeventproxy\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&eventproxy\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E运行\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Ewebpack test.js\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E在我的2015款RMBP13,i5处理器,全SSD下,性能是这样的:\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fd5aacfff08af1dca999e_b.png\& data-rawwidth=\&780\& data-rawheight=\&124\& class=\&origin_image zh-lightbox-thumb\& width=\&780\& data-original=\&https:\u002F\\u002Fd5aacfff08af1dca999e_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='780'%20height='124'&&\u002Fsvg&\& data-rawwidth=\&780\& data-rawheight=\&124\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&780\& data-original=\&https:\u002F\\u002Fd5aacfff08af1dca999e_r.png\& data-actualsrc=\&https:\u002F\\u002Fd5aacfff08af1dca999e_b.png\&\u003E\u003Cp\u003E没错你没有看错,这几个第三方轮子加起来有整整668个模块,全部打包需要20多秒。\u003C\u002Fp\u003E\u003Cp\u003E这意味着什么呢?你每次对业务代码的修改,gulp 或者 Webpack 监测到后都会重新打包,你要足足等20秒才能看到自己的修改结果。\u003C\u002Fp\u003E\u003Cp\u003E但是需要重新打包的只有你的业务代码,这些第三方库是完全不用重新打包的,它们的存在只会拖累打包性能。所以我们要找一些方法来优化这个过程。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E配置externals\u003C\u002Fh2\u003E\u003Cp\u003EWebpack 可以配置 externals 来将依赖的库指向全局变量,从而不再打包这个库,比如对于这样一个文件:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kr\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReact\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Econsole\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Elog\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003EReact\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E如果你在 Webpack.config.js 中配置了externals:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Emodule\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eexports\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eexternals\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'window.React'\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F其它配置忽略...... \u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E};\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E等于让 Webpack 知道,对于 react 这个模块就不要打包啦,直接指向 window.React 就好。不过别忘了加载 react.min.js,让全局中有 React 这个变量。\u003C\u002Fp\u003E\u003Cp\u003E我们来看看性能,因为不用打包 React 了所以速度自然很快,包也很小:\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002F5d26d23ef6e3ed2a9c04e0_b.png\& data-rawwidth=\&740\& data-rawheight=\&130\& class=\&origin_image zh-lightbox-thumb\& width=\&740\& data-original=\&https:\u002F\\u002F5d26d23ef6e3ed2a9c04e0_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='740'%20height='130'&&\u002Fsvg&\& data-rawwidth=\&740\& data-rawheight=\&130\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&740\& data-original=\&https:\u002F\\u002F5d26d23ef6e3ed2a9c04e0_r.png\& data-actualsrc=\&https:\u002F\\u002F5d26d23ef6e3ed2a9c04e0_b.png\&\u003E\u003Cbr\u003E\u003Ch2\u003E配置externals的缺陷\u003C\u002Fh2\u003E\u003Cp\u003E问题如果就这么简单地解决了的话,那我就没必要写这篇文章了,下面我们加一个 react 的动画库 \u003Cb\u003Ereact-addons-css-transition-group\u003C\u002Fb\u003E 来试一试:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kr\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReact\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003Cspan class=\&kr\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReactAddonsCssTransitionGroup\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'react-addons-css-transition-group'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Econsole\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Elog\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003EReact\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002F304ea169f738e890a4e87d_b.png\& data-rawwidth=\&744\& data-rawheight=\&122\& class=\&origin_image zh-lightbox-thumb\& width=\&744\& data-original=\&https:\u002F\\u002F304ea169f738e890a4e87d_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='744'%20height='122'&&\u002Fsvg&\& data-rawwidth=\&744\& data-rawheight=\&122\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&744\& data-original=\&https:\u002F\\u002F304ea169f738e890a4e87d_r.png\& data-actualsrc=\&https:\u002F\\u002F304ea169f738e890a4e87d_b.png\&\u003E\u003Cp\u003E对,你没有看错,我也没有截错图,新加了一个很小很小的动画库之后,性能又爆炸了。从模块数来看,一定是 Webpack 又把 react 重新打包了一遍。\u003C\u002Fp\u003E\u003Cp\u003E我们来看一下为什么一个很小很小的动画库会导致 Webpack 又傻傻地把 react 重新打包了一遍。找到\u003Cb\u003E react-addons-css-transition-group\u003C\u002Fb\u003E 这个模块,然后看看它是怎么写的:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F react-addons-css-transition-group模块\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F 入口文件 index.js\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Emodule\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eexports\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'react\u002Flib\u002FReactCSSTransitionGroup'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E这个动画模块就只有一行代码,唯一的作用就是指向 react 下面的一个子模块,我们再来看看这个子模块是怎么写的:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F react模块\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F react\u002Flib\u002FReactCSSTransitionGroup.js\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReact\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'.\u002FReact'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReactTransitionGroup\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'.\u002FReactTransitionGroup'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003EReactCSSTransitionGroupChild\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'.\u002FReactCSSTransitionGroupChild'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F....剩余代码忽略\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E这个子模块又反回去依赖了 react 整个库的入口,这就是拖累 Webpack 的罪魁祸首。\u003C\u002Fp\u003E\u003Cp\u003E总而言之,问题是这样产生的:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003EWebpack 发现我们依赖了\u003Cb\u003E react-addons-css-transition-group\u003C\u002Fb\u003E;\u003C\u002Fli\u003E\u003Cli\u003E Webpack 去打包\u003Cb\u003E react-addons-css-transition-group\u003C\u002Fb\u003E 的时候发现它依赖了 react 模块下的一个叫 ReactTransitionGroup.js 的文件,于是 Webpack 去打包这个文件;\u003C\u002Fli\u003E\u003Cli\u003EReactTransitionGroup.js 依赖了整个 react 的入口文件 React.js,\u003Cb\u003E虽然我们设置了 externals ,但是 Webpack 不知道这个入口文件等效于 react 模块本身\u003C\u002Fb\u003E,于是我们可爱又敬业的 Webpack 就把整个 react 又重新打包了一遍。\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E读到这里你可能会有疑问,为什么不能把这个动画库也设置到 externals 里,这样不是就不用打包了吗?\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E问题就在于,这个动画库并没有提供生产环境的文件,或者说这个库根本没有提供 react-addons-css-transition-group.min.js 这个文件。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E这个问题不只存在于\u003Cb\u003E react-addons-css-transition-group\u003C\u002Fb\u003E 中,对于 react 的大多数现有库来说都有这个依赖关系复杂的问题。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E初级解决方法\u003C\u002Fh2\u003E\u003Cp\u003E所以对于这个问题的解决方法就是,手工打包这些 module,然后设置 externals ,让 Webpack 不再打包它们。\u003C\u002Fp\u003E\u003Cp\u003E我们需要这样一个 lib-bundle.js 文件:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&nb\&\u003Ewindow\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003E__LIB\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&react\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&react\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&nb\&\u003Ewindow\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003E__LIB\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&react-addons-css-transition-group\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&react-addons-css-transition-group\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F ...其它依赖包\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E我们在这里把一些第三方库注册到了 \u003Cb\u003Ewindow.__LIB\u003C\u002Fb\u003E 下,这些库可以作为底层的基础库,免于重复打包。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E然后执行 \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Ewebpack lib-bundle.js lib.js\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E得到打包好的 \u003Cb\u003Elib.js\u003C\u002Fb\u003E。然后去设置我们的 externals :\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ewebpack\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'webpack'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Emodule\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eexports\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Eexternals\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'window.__LIB[\&react\&]'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react-addons-css-transition-group'\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'window.__LIB[\&react-addons-css-transition-group\&]'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 其它库\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F其它配置忽略...... \u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E};\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E这时由于 externals 的存在,Webpack 打包的时候就会避开这些模块超多,依赖关系复杂的库,把这些第三方 module 的入口指向预先打包好的\u003Cb\u003E lib.js\u003C\u002Fb\u003E 的入口 \u003Cb\u003Ewindow.__LIB\u003C\u002Fb\u003E,从而只打包我们的业务代码。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E终极解决方法\u003C\u002Fh2\u003E\u003Cp\u003E上面我们提到的方法本质上就是一种\u003Cb\u003E“动态链接库(dll)”\u003C\u002Fb\u003E的思想,这在 windows 系统下面是一种很常见的思想。\u003Cb\u003E一个 dll 包,就是一个很纯净的依赖库,它本身不能运行,是用来给你的 app 或者业务代码引用的。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E同样的 Webpack 最近也新加入了这个功能:\u003Cb\u003Ewebpack.DllPlugin\u003C\u002Fb\u003E。使用这个功能需要把打包过程分成两步:\u003C\u002Fp\u003E\u003Col\u003E\u003Cli\u003E 打包ddl包\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E 引用ddl包,打包业务代码\u003C\u002Fli\u003E\u003C\u002Fol\u003E\u003Cp\u003E首先我们来打包ddl包,首先配置一个这样的 \u003Cb\u003Eddl.config.js\u003C\u002Fb\u003E:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kr\&\u003Econst\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ewebpack\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'webpack'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&kr\&\u003Econst\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Evendors\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react-dom'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s1\&\u003E'react-router'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F ...其它库\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E];\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&nx\&\u003Emodule\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eexports\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eoutput\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Epath\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'build'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Efilename\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'[name].js'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Elibrary\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'[name]'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E},\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eentry\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&lib\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Evendors\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E},\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eplugins\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Enew\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ewebpack\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003EDllPlugin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E({\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Epath\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'manifest.json'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Ename\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'[name]'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Econtext\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003E__dirname\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}),\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E};\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cb\u003Ewebpack.DllPlugin\u003C\u002Fb\u003E 的选项中:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cb\u003Epath \u003C\u002Fb\u003E是 \u003Cb\u003Emanifest.json\u003C\u002Fb\u003E 文件的输出路径,这个文件会用于后续的业务代码打包;\u003C\u002Fli\u003E\u003Cli\u003E\u003Cb\u003Ename \u003C\u002Fb\u003E是 dll 暴露的对象名,要跟 \u003Cb\u003Eoutput.library\u003C\u002Fb\u003E 保持一致;\u003C\u002Fli\u003E\u003Cli\u003E\u003Cb\u003Econtext \u003C\u002Fb\u003E是解析包路径的上下文,这个要跟接下来配置的 webpack.config.js 一致。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E运行Webpack,会输出两个文件一个是打包好的 \u003Cb\u003Elib.js\u003C\u002Fb\u003E,一个就是 \u003Cb\u003Emanifest.json\u003C\u002Fb\u003E,它里面的内容大概是这样的:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&name\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s2\&\u003E\&vendor_ac51ba426d4f259b8b18\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&content\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Freact.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Flib\u002FReact.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E2\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Fnode_modules\u002Fobject-assign\u002Findex.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Flib\u002FReactChildren.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E4\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Flib\u002FPooledClass.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E5\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&s2\&\u003E\&.\u002Fnode_modules\u002Freact\u002Flib\u002FreactProdInvariant.js\&\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E6\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F ............\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E接下来我们就可以快乐地打包业务代码啦,首先写好打包配置文件 \u003Cb\u003Ewebpack.config.js\u003C\u002Fb\u003E:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kr\&\u003Econst\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ewebpack\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'webpack'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Emodule\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eexports\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eoutput\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Epath\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'build'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Efilename\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'[name].js'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E},\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eentry\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eapp\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'.\u002Fsrc\u002Findex.js'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E},\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Eplugins\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Enew\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ewebpack\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003EDllReferencePlugin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E({\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Econtext\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003E__dirname\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\n
\u003Cspan class=\&nx\&\u003Emanifest\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E:\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Erequire\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'.\u002Fmanifest.json'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E),\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}),\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E};\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cb\u003Ewebpack.DllReferencePlugin\u003C\u002Fb\u003E 的选项中:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cb\u003Econtext \u003C\u002Fb\u003E需要跟之前保持一致,这个用来指导 Webpack 匹配 \u003Cb\u003Emanifest.json\u003C\u002Fb\u003E 中库的路径;\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cb\u003Emanifest \u003C\u002Fb\u003E用来引入刚才输出的 \u003Cb\u003Emanifest.json\u003C\u002Fb\u003E 文件。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cb\u003EDllPlugin\u003C\u002Fb\u003E 本质上的做法和我们手动分离这些第三方库是一样的,但是对于包极多的应用来说,自动化明显加快了生产效率。\u003C\u002Fp\u003E&,&updated&:new Date(&T06:51:58.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:60,&collapsedCount&:0,&likeCount&:339,&state&:&published&,&isLiked&:false,&slug&:&&,&lastestTipjarors&:[],&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002F897c2df2f21aa6b2f9f4a_r.png&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&reviewers&:[],&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&webpack&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&JavaScript&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&前端开发&}],&adminClosedComment&:false,&titleImageSize&:{&width&:1920,&height&:960},&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&column&:{&slug&:&starkwang&,&name&:&一只码农的技术日记&},&tipjarState&:&activated&,&tipjarTagLine&:&谢谢OvO&,&sourceUrl&:&&,&pageCommentsCount&:60,&tipjarorCount&:0,&annotationAction&:[],&hasPublishingDraft&:false,&snapshotUrl&:&&,&publishedTime&:&T14:51:58+08:00&,&url&:&\u002Fp\u002F&,&lastestLikers&:[{&bio&:&计算机网络在读、自学ui设计师&,&isFollowing&:false,&hash&:&f29e1b940b3cdcf9d770bc&,&uid&:332700,&isOrg&:false,&slug&:&sabarlily&,&isFollowed&:false,&description&:&&,&name&:&sabarlily&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fsabarlily&,&avatar&:{&id&:&v2-dbe33b25e1dd617c851fd49f&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&web前端开发&,&isFollowing&:false,&hash&:&188bc78a0f1e535d13f965b&,&uid&:08,&isOrg&:false,&slug&:&lemon-yezi&,&isFollowed&:false,&description&:&曾担任珍爱网web前端开发,热爱前端,热爱旅行&,&name&:&柠檬&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Flemon-yezi&,&avatar&:{&id&:&v2-2ab165ac2b&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&腾讯SNG前端,个人博客:https:\u002F\u002Fcpselvis.github.io\u002F&,&isFollowing&:false,&hash&:&0d41abbdb09&,&uid&:416500,&isOrg&:false,&slug&:&cpselvis&,&isFollowed&:false,&description&:&开源中国讲师,现腾讯IVWEB团队,Github: https:\\u002Fcpselvis&,&name&:&cpselvis&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fcpselvis&,&avatar&:{&id&:&v2-f4f893a395fdb2016eb3&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&饿了&,&isFollowing&:false,&hash&:&7de63a250f4b14ec69d129ef458a36ff&,&uid&:04,&isOrg&:false,&slug&:&zhang-xiang-di&,&isFollowed&:false,&description&:&&,&name&:&张翔迪&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fzhang-xiang-di&,&avatar&:{&id&:&80dfe654c&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&to be is to do&,&isFollowing&:false,&hash&:&d475aad0facf6f9a959f1&,&uid&:96,&isOrg&:false,&slug&:&qethan&,&isFollowed&:false,&description&:&&,&name&:&QETHAN&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fqethan&,&avatar&:{&id&:&7c85c2d21&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}],&summary&:&\u003Cimg src=\&https:\u002F\\u002Fd5aacfff08af1dca999e_200x112.png\& data-rawwidth=\&780\& data-rawheight=\&124\& class=\&origin_image inline-img zh-lightbox-thumb\& data-original=\&https:\u002F\\u002Fd5aacfff08af1dca999e_r.png\&\u003E这几天写腾讯实习生 Mini 项目的时候用上了 react 全家桶,当然同时引入了 Webpack 作为打包工具。但是开发过程中遇到一个很棘手的问题就是,react 加上 react-router、material-ui、superagent、eventproxy 这些第三方轮子一共有好几百个 module,Webpack …&,&reviewingCommentsCount&:0,&meta&:{&previous&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002F50\u002Fa48eedb38a417c57a3171aec1d10dd0b_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&函数式编程&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&JavaScript&}],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&企鹅培育与饲养&,&isFollowing&:false,&hash&:&d965f32ae58ad3a48a1585a4&,&uid&:68,&isOrg&:false,&slug&:&starkwei&,&isFollowed&:false,&description&:&\u002Fstarkwang&,&name&:&Stark伟&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fstarkwei&,&avatar&:{&id&:&v2-cfafbe3e362ecf37f1d5fcb7f488f13c&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&starkwang&,&name&:&一只码农的技术日记&},&content&:&\u003Cp\u003E一、引言\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E说到函数式编程,大家可能第一印象都是学院派的那些晦涩难懂的代码,充满了一大堆抽象的不知所云的符号,似乎只有大学里的计算机教授才会使用这些东西。在曾经的某个时代可能确实如此,但是近年来随着技术的发展,函数式编程已经在实际生产中发挥巨大的作用了,越来越多的语言开始加入闭包,匿名函数等非常典型的函数式编程的特性,从某种程度上来讲,函数式编程正在逐步“同化”命令式编程。\u003C\u002Fp\u003E\u003Cp\u003EJavaScript 作为一种典型的多范式编程语言,这两年随着React的火热,函数式编程的概念也开始流行起来,RxJS、cycleJS、lodashJS、underscoreJS等多种开源库都使用了函数式的特性。所以下面介绍一些函数式编程的知识和概念。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E二、纯函数\u003C\u002Fh2\u003E\u003Cp\u003E如果你还记得一些初中的数学知识的话,函数 \u003Cb\u003Ef\u003C\u002Fb\u003E 的概念就是,对于输入 \u003Cb\u003Ex\u003C\u002Fb\u003E 产生一个输出 \u003Cb\u003Ey = f(x)\u003C\u002Fb\u003E。这便是一种最简单的纯函数。\u003Cb\u003E纯函数的定义是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E下面来举个栗子,比如在Javascript中对于数组的操作,有些是纯的,有些就不是纯的:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Earr\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E2\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E4\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E5\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E];\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F Array.slice是纯函数,因为它没有副作用,对于固定的输入,输出总是固定的\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F 可以,这很函数式\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Exs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eslice\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F=& [1,2,3]\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Exs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Eslice\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F=& [1,2,3]\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F Array.splice是不纯的,它有副作用,对于固定的输入,输出不是固定的\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F 这不函数式\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Exs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Esplice\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F=& [1,2,3]\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Exs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Esplice\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F=& [4,5]\u003C\u002Fspan\u003E\n\u003Cspan class=\&nx\&\u003Exs\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Esplice\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E3\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&c1\&\u003E\u002F\u002F=& []\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E在函数式编程中,我们想要的是 \u003Cb\u003Eslice \u003C\u002Fb\u003E这样的纯函数,而不是 \u003Cb\u003Esplice\u003C\u002Fb\u003E这种每次调用后都会把数据弄得一团乱的函数。\u003C\u002Fp\u003E\u003Cp\u003E为什么函数式编程会排斥不纯的函数呢?下面再看一个例子:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F不纯的\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Emin\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E18\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Echeckage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=&\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Emin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F纯的,这很函数式\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Echeckage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=&\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eage\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E18\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E在不纯的版本中,\u003Cb\u003Echeckage \u003C\u002Fb\u003E这个函数的行为不仅取决于输入的参数 age,还取决于一个外部的变量 \u003Cb\u003Emin\u003C\u002Fb\u003E,换句话说,这个函数的行为需要由外部的系统环境决定。对于大型系统来说,这种对于外部状态的依赖是造成系统复杂性大大提高的主要原因。\u003C\u002Fp\u003E\u003Cp\u003E可以注意到,纯的 \u003Cb\u003Echeckage \u003C\u002Fb\u003E把关键数字 18 硬编码在函数内部,扩展性比较差,我们可以在后面的\u003Cb\u003E柯里化\u003C\u002Fb\u003E中看到如何用优雅的函数式解决这种问题。\u003C\u002Fp\u003E\u003Cp\u003E纯函数不仅可以有效降低系统的复杂度,还有很多很棒的特性,比如可缓存性:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kr\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003E_\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&s1\&\u003E'lodash'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E;\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Esin\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003E_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ememorize\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=&\u003C\u002Fspan\u003E \u003Cspan class=\&nb\&\u003EMath\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Esin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E));\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F第一次计算的时候会稍慢一点\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ea\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Esin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F第二次有了缓存,速度极快\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eb\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Esin\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cbr\u003E\u003Ch2\u003E三、函数的柯里化\u003C\u002Fh2\u003E\u003Cp\u003E函数柯里化(curry)的定义很简单:传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。\u003C\u002Fp\u003E\u003Cp\u003E比如对于加法函数 \u003Cb\u003Evar add = (x, y) =& x + y\u003C\u002Fb\u003E ,我们可以这样进行柯里化:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-js\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F比较容易读懂的ES5写法\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kd\&\u003Efunction\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E){\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&kd\&\u003Efunction\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ey\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E){\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ereturn\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E+\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ey\u003C\u002Fspan\u003E\n
\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n\u003Cspan class=\&p\&\u003E}\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002FES6写法,也是比较正统的函数式写法\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=&\u003C\u002Fspan\u003E \u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&nx\&\u003Ey\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=&\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E+\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Ey\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&c1\&\u003E\u002F\u002F试试看\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd2\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E2\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\u003Cspan class=\&kd\&\u003Evar\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd200\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&nx\&\u003Eadd\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E200\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E);\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&nx\&\u003Eadd2\u003C\u002Fspan\u003E\u003Cspan clas

我要回帖

更多关于 webpack 图片打包路径 的文章

 

随机推荐