更新时间:2022-09-16 10:51:34
Webpack 是 OneAPM 前端技术栈中非常重要的一部分。它非常好用,假设你还不了解它,建议你阅读这篇 Webpack 入门指迷 ,在 OneAPM 我们用它完毕静态资源打包。ES6 代码的转换 ,React 组件的组织等,在接下来的日子里,我们将通过一系列文章和业界分享我们在使用 Webpack 过程中关于性能方面的经验。
作为系列文章的第一篇。我们会重点介绍 Webpack 中的 resolve.alias
,也就是请求重定向。
只是请注意 Webpack 里的请求是对模块的依赖,也就是一个 require
语句,而不是一个 HTTP 请求。
要实现的功能非常easy。就是在页面上用中文显示当前时间,须要用到 moment 这个库,这个库封装了非常多和日期相关的函数,并且自带了国际化的支持。
使用 npm init
初始化你的项目,然后通过npm install moment -D
加上 moment
的开发人员依赖。
新建一个entry.js
作为入口文件,当然你也能够用 app.js
这种名字,仅仅是大部分的 Webpack 演示样例都是用的是 entry.js
。
var moment = require('moment');
document.write(moment().locale('zh-cn').format('LLLL'));
新建一个页面index.html
, 引用 bundle.js
:
<body>
<h5>当前时间:</h5>
<script src="dist/bundle.js"></script>
</body>
此时的文件文件夹看起来是这种:
index.html
package.json
entry.js
node_modules/moment
到眼下为止 bundle.js
这个文件还不存在,只是别着急,接下来的工作就交给 Webpack 来完毕。
index.html ------------------------+
package.json |
+--> <Clock App>
entry.js --------+ |
+-->bundle.js+--+
node_modules/moment-+
如图,Webpack 会把 entry.js
和 moment
模块一起打包成一个 bundle.js
文件,和 index.html
一起构成了我们的 Clock App。怎么样,是不是已经听到 Clock App 滴答作响了?
在命令行执行:
webpack --entry ./entry.js --output-path dist --output-file bundle.js
你会看到相似以下的输出结果:
Hash: bf9007fb1e0cb30e3ef7
Version: webpack 1.10.0
Time: 650ms
Asset Size Chunks Chunk Names
bundle.js 378 kB 0 [emitted] null
[0] ./entry.js 125 bytes {0} [built]
+ 86 hidden modules
能够看到,耗时 650ms,这么慢着实让人意外,一定要想办法提高“新一代神器”速度;还有一方面,最后一行的 + 86 hidden modules 非常让人怀疑:明明是一个简单的 Clock App,怎么会有这么多的依赖。
再一次。在命令行输入:
webpack --entry ./entry.js --output-path dist --output-file bundle.js \
--colors \
--profile \
--display-modules
只是这次新添加了三个參数,这三个參数的含义各自是:
--colors
输出结果带彩色,比方:会用红色显示耗时较长的步骤--profile
输出性能数据,能够看到每一步的耗时--display-modules
默认情况下 node_modules
下的模块会被隐藏,加上这个參数能够显示这些被隐藏的模块 Hash: bf9007fb1e0cb30e3ef7
Version: webpack 1.10.0
Time: 650ms
Asset Size Chunks Chunk Names
bundle.js 378 kB 0 [emitted] null
[0] ./entry.js 125 bytes {0} [built]
factory:11ms building:8ms = 19ms
[1] ../~/moment/moment.js 102 kB {0} [built]
[0] 19ms -> factory:7ms building:141ms = 167ms
[2] (webpack)/buildin/module.js 251 bytes {0} [built]
[0] 19ms -> [1] 148ms -> factory:132ms building:159ms = 458ms
[3] ../~/moment/locale ^\.\/.*$ 2.01 kB {0} [optional] [built]
[0] 19ms -> [1] 148ms -> factory:6ms building:10ms dependencies:113ms = 296ms
[4] ../~/moment/locale/af.js 2.57 kB {0} [optional] [built]
[0] 19ms -> [1] 148ms -> [3] 16ms -> factory:52ms building:65ms dependencies:138ms = 438ms
..... 广告切割线,Node.js project师简历请发 nodejs@oneapm.com ......
[85] ../~/moment/locale/zh-cn.js 4.31 kB {0} [optional] [built]
[0] 22ms -> [1] 162ms -> [3] 18ms -> factory:125ms building:145ms dependencies:22ms = 494ms
[86] ../~/moment/locale/zh-tw.js 3.07 kB {0} [optional] [built]
[0] 22ms -> [1] 162ms -> [3] 18ms -> factory:126ms building:146ms dependencies:21ms = 495ms
从命令行的结果里能够看到从 Request[4] 到 Request[86] 都是在解析 moment.js
附带的大量本地化文件。所以我们遇到的速度慢的问题事实上是由 moment
引起的。
假设你想知道为什么 Webpack 会载入这么多的模块。能够參考这篇文章 Why Enormous Locales During Webpack MomentJS
我们再来看看 entry.js
代码的第一行,标准的 CommonJS
写法:
var moment = require('moment');
也就是说。请求的是 moment
的源代码。实际上。通过 NPM 安装moment
的时候会同一时候安装 moment
的源代码和压缩后的代码,试验证明以下这种写法也是可行的:
var moment = require('moment/min/moment-with-locales.min.js');
仅仅只是这样改,可读性会有所下降,并且每个用到moment
的地方都得这么写。另外,假设相同的问题出如今第三方模块中,改动别人代码就不那么方便了。
以下来看看用 Webpack 怎么解决问题。
别名(resolve.alias
) 是 Webpack 的一个配置项,它的作用是把用户的一个请求重定向到还有一个路径,比如通过改动 webpack.config.js
配置文件,添加:
resolve: {
alias: {
moment: "moment/min/moment-with-locales.min.js"
}
}
这样待打包的脚本中的 require('moment')
; 事实上就等价于 require('moment/min/moment-with-locales.min.js');
。通过别名的使用在本例中能够降低差点儿一半的时间。
Hash: cdea65709b783ee0741a
Version: webpack 1.10.0
Time: 320ms
Asset Size Chunks Chunk Names
bundle.js 148 kB 0 [emitted] main
[0] ./entry.js 125 bytes {0} [built]
factory:11ms building:9ms = 20ms
[1] ../~/moment/min/moment-with-locales.min.js 146 kB {0} [built] [1 warning]
[0] 20ms -> factory:8ms building:263ms = 291ms
[2] (webpack)/buildin/module.js 251 bytes {0} [built]
[0] 20ms -> [1] 271ms -> factory:3ms building:1ms = 295ms
WARNING in ../~/moment/min/moment-with-locales.min.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./locale in */webpack_performance/node_modules/moment/min
@ ../~/moment/min/moment-with-locales.min.js 1:2731-2753
Webpack
中忽略对已知文件的解析module.noParse
是 webpack
的还有一个非常实用的配置项,假设你 确定一个模块中没有其他新的依赖 就能够配置这项,webpack
将不再扫描这个文件里的依赖。
module: {
noParse: [/moment-with-locales/]
}
这样改动。再结合前面重命名的样例,更新后的流程是:
webpack
检查到 entry.js
文件对 moment
的请求;alias
重定向,转而请求 moment/min/moment-with-locales.min.js;
noParse
规则中的 /moment-with-locales/
一条生效,所以 webpack
就直接把依赖打包进了 bundle.js
。
Hash: 907880ed7638b4ed70b9
Version: webpack 1.10.0
Time: 76ms
Asset Size Chunks Chunk Names
bundle.js 147 kB 0 [emitted] main
[0] ./entry.js 125 bytes {0} [built]
factory:13ms building:13ms = 26ms
[1] ../~/moment/min/moment-with-locales.min.js 146 kB {0} [built]
[0] 26ms -> factory:13ms building:5ms = 44ms
时间进一步被压缩,仅仅须要 76ms,比前一步还降低了 75%。
Webpack 是如此的强大。用其打包的脚本能够执行在多种环境下。Web 环境仅仅是其默认的一种,也是最经常使用的一种。考虑到 Web 上有非常多的公用 CDN 服务。那么 怎么将 Webpack 和公用的 CDN 结合使用呢?方法是使用 externals
声明一个外部依赖。
externals: {
moment: true
}
当然了 HTML 代码里须要加上一行
<script src="//apps.bdimg.com/libs/moment/2.8.3/moment-with-locales.min.js"></script>
这次打包。结果仅仅用了 49 ms。差点儿达到了极限。
本文结合本地时钟的样例,展示了定位 Webpack 性能问题的步骤,以及所须要的两个參数 :--display-modules
和 --profile
。然后,重点介绍了 resolve.alias
即利用别名做重定向的方法和场景。在此基础上,配合module.noParse
忽略某些模块的解析能够进一步加高速度。最后介绍了用 externals
定义外部依赖方法来使用公用 CDN。
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5416045.html,如需转载请自行联系原作者