博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于webpack优化,你需要知道的事(上篇)
阅读量:7010 次
发布时间:2019-06-28

本文共 5563 字,大约阅读时间需要 18 分钟。

前言

webpack 是一个优秀的打包工具,其本身为我们做了大量优化,同时也为我们提供了大量的配置项让我们可以自定义,从而有优化空间。

在讲 webpack 优化篇之前,由于楼主主要以 vue 脚手架开始的,而且是已经升级为 webpack4 之后的优化,如果对 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和大小并没有变化(汗,别砸,翻资料、上有写,而且脚手架上有)。后来发现,楼主的代码中并没有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 插件,目的就是分割出几类代码:

  1. vendor 也就是第三方库打包这里。
  2. manifest 当编译器开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 "Manifest"
  3. 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 为我们做的优化有

  1. babel-plugin-transform-runtime 插件去除重复垫片代码
  2. module.rules 的 js 解析,使用 include 提高命中
  3. node 选项,防止 node 的自带包(dgram、fs、net、tls、child_process)注入到我们的代码中
  4. js、css 压缩,代码分割,公共部分抽离
  5. 维持打包后不变chunk的hash值不变
  6. 作用域提升(scope hoisting)
  7. css 抽离。公共部分抽离

大致就这样了,有没有讲到的也请评论区提出,那么如何在此基础上做优化呢,这个也许是大家都很关心的问题。接下来我会在 《关于webpack优化,你需要知道的事(下篇)》讲到。

转载地址:http://ufntl.baihongyu.com/

你可能感兴趣的文章
Oracle truncate table 与 delete tabel的区别
查看>>
Oracle 11g回收站recyclebin的使用详解
查看>>
写时拷贝(方案三)
查看>>
超导突触处理信息能力超人脑
查看>>
人民日报三问人工智能 给法律制度带来哪些挑战?
查看>>
使用winpe安装系统后不能进入滚动条的方法
查看>>
Centos系统搭建ror平台搭建
查看>>
gitlab多线程备份脚本
查看>>
netsh切换IP地址
查看>>
初始化Linux数据盘(fdisk)
查看>>
JS闭包
查看>>
bootstrap多层model关闭后的滚动问题
查看>>
excel 的 vlookup 函数 根据对应关系进行单元格数据批量替换
查看>>
SQL2008R2标准版(学生身份验证)
查看>>
【入门教程】SequoiaDB+Postgresql数据实时检索最佳实践
查看>>
在CentOS/RHEL 6.5上安装Chromium
查看>>
十个你可能没用过的Linux命令
查看>>
为extjs的TabPanel 添加右键关闭效果(修改一个bug)
查看>>
java中传递基础数据类型值与传递数组引用变量给方法的不同之处
查看>>
监控io性能,free命令,ps网络命令,查看网络状态,Linux下抓包
查看>>