内容简介:webpack 是一个优秀的打包工具,其本身为我们做了大量优化,同时也为我们提供了大量的配置项让我们可以自定义,从而有优化空间。在讲 webpack 优化篇之前,由于楼主主要以 vue 脚手架开始的,而且是已经升级为 webpack4 之后的优化,如果对 vue脚手架配置不太了解的同学。可以看我上一篇文章下面我先讲讲vue脚手架为我们做的一些优化,不喜欢看的请跳过,然后会讲如何在优化的基础上升华一下,内容从浅到深,但是所有的方法都经过楼主考证,内容较长,请自带板凳瓜子。
webpack 是一个优秀的打包工具,其本身为我们做了大量优化,同时也为我们提供了大量的配置项让我们可以自定义,从而有优化空间。
在讲 webpack 优化篇之前,由于楼主主要以 vue 脚手架开始的,而且是已经升级为 webpack4 之后的优化,如果对 vue脚手架配置不太了解的同学。可以看我上一篇文章 如何优雅的升级到webpack4 ,或者直接看 webpack3 vue脚手架注解
下面我先讲讲vue脚手架为我们做的一些优化,不喜欢看的请跳过,然后会讲如何在优化的基础上升华一下,内容从浅到深,但是所有的方法都经过楼主考证,内容较长,请自带板凳瓜子。
vue-cli 脚手架自带优化
babel
Babel 是一个 JavaScript 编译器,能将 ES6 代码转为 ES5 代码,让你使用最新的语言特性而不用担心兼容性问题,并且可以通过插件机制根据需求灵活的扩展。这里我不讲babel ,而是讲官方用的插件 transform-runtime,对应的插件全名叫做 babel-plugin-transform-runtime,其作用是减少冗余代码,到底是怎么减少的呢?
例如在转换 class extent 语法时会在转换后的 ES5 代码里注入 _extent 辅助函数用于实现继承:
function _extent(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
}
复制代码
这会导致每个使用了 class extent 语法的文件都被注入重复的_extent 辅助函数代码,babel-plugin-transform-runtime 的作用在于不把辅助函数内容注入到文件里,而是注入一条导入语句:
var _extent = require('babel-runtime/helpers/_extent');
复制代码
这样能减小 Babel 编译出来的代码的文件大小。 注意:babel-plugin-transform-runtime 必须和 babel-runtime 需要配套使用
说来惭愧,楼主试了一下,把这个插件去掉,生成文件的hash和大小并没有变化(汗,别砸,翻资料webpack 标准入门、 前端工程化-webpack篇之babel-polyfill与babel-runtime(三) 上有写,而且脚手架上有)。后来发现,楼主的代码中并没有es6。后来换了一个大项目,做了对比
可以发现,图右边是去掉插件的。体积明显大了一点。使用此插件可以减少重复代码,缩小项目体积。
缩小文件搜索范围
loader
使用 Loader 时可以通过 test 、 include 、 exclude 三个配置项来命中,对于我们的项目大部分都是 js,下面看看官方脚手架 js 的 babel-loader:
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
]
}
}
复制代码
由于通过 npm 安装的第三方的库,都是经过 webpack 打包 es5 化了,所以这里就可以只对 include 包括的文件使用 babel-loader 解析
注意了。由于 css、less 的引入是要插入到js中的,所以并不适用于这个(把 node_modules 排除在外)方法。说到这里,多说一句,也是曾经很困扰我的 css 的 loader 解析顺序,use 的 loader 解析顺序跟数组的位置是反着的,以 less 为例,具体来讲
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.less$/,
// less 文件的处理顺序为先 less-loader 再 css-loader 再 vue-style-loader
use: [
// style-loader 会把 CSS 代码转换成字符串后,注入到 JavaScript 代码中去,
'vue-style-loader',
// css-loader 会找出 CSS 代码中的 @import 和 url() 这样的导入语句,告诉 Webpack 依赖这些资源。同时还支持 CSS Modules、压缩 CSS 等功能。处理完后再把结果交给 vue-style-loader 去处理。
{
loader: 'css-loader',
options: {
sourceMap: config.dev.cssSourceMap
}
},
//通过 less-loader 把 less 源码转换为 CSS 代码,再把 CSS 代码交给 css-loader 去处理。
{
loader: 'less-loader'
}
]
},
]
}
}
复制代码
关于缩小范围增加命中这个思想,还可以做很多事情,这里只讲了vue脚手架优化做的事情,更多配置请往后看,看我如何自定义的
node 选项
webpack 的官方脚手架里面的node选项可以防止node包,还有 setImmediate 的 profill注入到代码中
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
复制代码
好不好,看疗效。那么具体的疗效怎么样呢,楼主同样的代码,做了对比,效果如下:
通过对比可以看到,两次打包css的hash值全部变了,js部分hash发生改变(这个打包没看出js变化,但是另一个项目的部分js的hash变了)。总体打出来的包的体积相差不大。去掉node选项打包时间差别不明显,所以用不用,见仁见智吧。我看create-react-app中也使用了,所以还是建议使用吧,知道更多的,可以留言区讨论。
js、css 压缩
css 压缩这个就不多说了,大家都懂,
值得一提的是由于 UglifyJsPlugin 插件升级到1.0之后有了 parallel选项,开启了多线程压缩
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true // 开启多线程压缩
})
复制代码
这两个插件都有配置项,合理配置可以优化项目。后面会讲。
代码分割
代码分割就是将动态引入的代码分割成一个一个的代码块(chunk),根据需求加载到html上。 注意:要使用代码分割功能,在项目中要配合使用组件、路由懒加载的方式(可以通过import实现)
webpack4 的 mode 为 production 时,默认会对代码进行分割。楼主看了 webpack3 的代码分割方式是使用 CommonsChunkPlugin 插件,目的就是分割出几类代码:
- vendor 也就是第三方库打包这里。
- manifest 当编译器开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 "Manifest"
- app 这个是代码中的公共部分
HashedModuleIdsPlugin
嗯 webpack 生成 js 的 hash 是如何计算我并不清楚,但是如果不用这个插件的话,所有生成 js 的 hash 是一样的,而且只要有一点点改动,所有文件的 hash 值都会变化。那造成什么样的结果呢?
比如你只改了 b 页面的 js 里的一行代码,如果不用此插件的话,所有页面的 js 的 hash 全部会变化,浏览器要重新请求全部的js。性能浪费到令人发指。而使用了 HashedModuleIdsPlugin 这个插件,只有你改动的那个 chunk 的 hash会发生变化,其他不变,由于浏览器的缓存机制,浏览器只重新请求改动的js。是不是很棒。而且上一小节对代码分割那里的分割方式,也是为了把不经常变动的文件单独打包,hash 可以保持不变。
使用方法也很简单
new webpack.HashedModuleIdsPlugin(), 复制代码
什么?为什么就算去掉 HashedModuleIdsPlugin 插件 用脚手架第一次打包项目生成的 js 的 hash 不全部一样,而且改动之后,也不是全部发生变化啊。这个也是楼主遇到的问题。楼主不用脚手架搭建的项目,js 的 hash 是一样的,知道为什么出现初始打包的 js hash 值为什么不全部一样的同学,欢迎评论区讨论。
作用域提升(scope hoisting)
过去 webpack 打包时的一个取舍是将 bundle 中各个模块单独打包成闭包。这些打包函数使你的 JavaScript 在浏览器中处理的更慢。相比之下,一些 工具 像 Closure Compiler 和 RollupJS 可以提升(hoist)或者预编译所有模块到一个闭包中,提升你的代码在浏览器中的执行速度。 个插件会在 webpack 中实现以上的预编译功能。
new webpack.optimize.ModuleConcatenationPlugin() 复制代码
这种连结行为被称为“作用域提升(scope hoisting)
记住,此插件仅适用于由 webpack 直接处理的 ES6 模块。在使用转译器(transpiler)时,你需要禁用对模块的处理(例如 Babel 中的 modules 选项)。
css 优化
由于css加载不会阻塞dom的解析,所以把css抽取出来。不占用js的大小是一个明智的选择 OptimizeCSSPlugin 插件做的就是这个,并且代码复用,会减小css体积
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
复制代码
以上所述就是小编给大家介绍的《关于webpack优化,你需要知道的事(上篇)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 消息推送异常重发需要注意的点(上篇)
- 威胁情报相关标准简介 (上篇)
- Tensorflow Rust实战上篇
- 【前端面试分享】- 寒冬求职上篇
- 认证授权方案之授权揭秘 (上篇)
- 流式处理框架storm浅析(上篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Powerful
Patty McCord / Missionday / 2018-1-25
Named by The Washington Post as one of the 11 Leadership Books to Read in 2018 When it comes to recruiting, motivating, and creating great teams, Patty McCord says most companies have it all wrong. Mc......一起来看看 《Powerful》 这本书的介绍吧!