作者 | 居玉皓

对大多数 Web 应用来说,页面性能直接影响着流量。这是一个经常为我们所忽视的事实。

用户长时间的等待流失的不仅仅是跳出率、转化率,还有对产品的耐心和信赖。很多时候我们没有意识到性能问题,那是因为平常开发使用的都是高效的设备和网络。

而到了真实世界中却会发现,实际用户的网络环境会更加复杂,而如果使用的是移动设备的话,有限的计算能力也会拖慢代码的解析执行,这些都会影响页面的渲染效率。

Web 应用的加载速度很大程度上取决于资源的大小,下面是 Youtube 桌面端页面通过 PageSpeed Insights 检测得到的数据,整个页面渲染加载了 2861 KB 的资源,其中 JavaScript 占了大头。

下面我总结了一些借助 Webapck 进行构建的工程可以采用的一些优化输出资源体积的方法,使打包出的 JavaScript、CSS 文件更小,页面加载更快。

代码分片

首先让我们从代码分片(code splitting)说起。

代码分片就是通过把原本的代码进行“提取”和“分离”使客户端尽可能地只加载当前需要的资源。

曾经遇到过一个这样一个工程,它有十几个页面,每个页面都引用了其所使用的框架以及 UI 库,导致产出的资源体积非常大,有时在打包过程中直接就内存溢出崩掉了。

后来通过代码分片把公共模块提取到了单独的文件中,再让各个页面分别引用它,整个打包结果的体积只有原先的几分之一,并且也不再有内存溢出的问题了。

上面说的“提取”指的是找到代码中重复的部分或者是不经常变动的部分,并将其作为一个独立的资源打包出来。

在 Webpack4 之前通常使用 CommonsChunkPlugin,但它在设计上存在一些问题,并且在某些场景下难以使用,在 Webpack4 时就被官方替换为了 SplitChunksPlugin。

对 CommonsChunkPlugin 熟悉的人应该清楚,使用这个插件时要通过各种配置项对指定入口的指定模块进行提取,让人感觉像是命令式的;相比之下 SplitChunksPlugin 则更像是声明式的——由使用者来定义提取规则,比如新的 Chunk 必须可以被共享以及体积要大于 30KB 等等,当模块满足了这些规则就会被提取出来。

这样灵活性更强,对使用者也更加友好。

下面是一个使用 SplitChunksPlugin 的例子:

JavaScript

module.exports = {

entry: {

pageA:'./pageA.js',

pageB:'./pageB.js',

},

output: {

filename:[name].js,

},

mode:'development',

optimization: {

splitChunks: {

chunks:'all',

},

},

};

在该配置下,如果 pageA 和 pageB 包含了一些体积比较大的公共模块,那么它们就会自动地被提取出来,结果如下图。

说完了“提取”再说一下“分离”。它是指将部分代码延迟加载或者说动态加载,在 Webpack 中通过`import()` 语法来实现。请看下面这个例子:

JavaScript

// util.js

export function add(a, b) {

return a + b;

}

// index.js

import('./util').then(({ add }) => {

console.log(add(2,3));

});

使用`import()`加载的模块及其依赖模块会构建出一个async chunk,并在页面上延迟加载。比如上面的例子中的 util.js 将不会被打包到 index.js 的 bundle 中,而是在浏览器加载完 index.js 后再去请求 util.js,等 util.js 加载完成后后再去执行回调函数里面的逻辑。

这种方法适合于处理第三方库以及用户不会立即使用的功能,或者配合 SPA 路由,将页面级别的代码全部使用动态加载。

比如在 Vue 中,我们可以这样实现:

JavaScript

const Home = () => import('./Home.vue');

const router = new VueRouter({

routes: [

{ path: '/',component: Home }

]

});

类似的 React 的例子,结合 `React.lazy` 与 `Suspense` 也可以有相同的效果:

JavaScript

const Home = lazy(() => import('./routes/Home'));

const App = () => (

<Router>

<Suspensefallback={<div>Loading...</div>}>

<Switch>

<Routeexact path="/" component={Home}/>

</Switch>

</Suspense>

</Router>

);

排除非必要资源

有些时候在加载了一个库、框架或者工具之后,也会连带地加载一些不必要的资源,使打包结果体积无故增大了许多。

这个问题最常见的就是对 Moment.js 的使用。Moment.js是一个用于处理时间和日期的库,它支持非常多的语言。

这是一个非常方便的特性,比如我们可以用中文显示一个日期离现在有多久,会得到“一小时前”或者“两天前”等等。

但同时这个特性也有一个问题,即默认情况下它会加载进所有语言包。比如下面这个例子。

JavaScript

import moment from 'moment';

console.log(moment());

当加载了 moment 模块之后,我们在打包结果中会看到非常多类似`./node_modules/moment/locale/zh-cn.js`的语言包,所有这些由引入 Moment.js 带来的模块最后产生的 bundle.js 有 600KB。

为了解决这个问题,我们可以借助 `IgnorePlugin` 将语言包模块进行忽略:

JavaScript

new Webpack.IgnorePlugin(/^\.\/locale$/,/moment$/)

重新打包后产出的 bundle.js 仅有 233KB。

如果需要保留一些特定的语言,只要直接在代码中加载特定的语言包模块就可以了。请看这个例子。

JavaScript

// index.js

import moment from 'moment';

import 'moment/locale/zh-cn';

上面由于直接采用了模块路径的形式来加载,它并不会被我们配置的 `IgnorePlugin` 匹配到,因此依旧会打包到最后的 bundle 中。

减小 CSS 体积

相比于 JavaScript 和图片来说,CSS 的体积通常没有那么大,但对整个页面的渲染性能来说 CSS 仍然是十分重要的一环。

因为页面的初始渲染一定是要等 CSS 加载完成后再进行页面内容排布的,CSS 的体积将直接影响到用户从开始请求页面到看到有意义内容的时间,这个时间是评估页面性能的一项关键指标。

减小 CSS 体积要做的第一件事是压缩代码,下面是一个提取 CSS代码到文件并进行压缩的示例。

JavaScript

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const OptimizeCSSAssetsPlugin =require('optimize-css-assets-webpack-plugin');

module.exports = {

optimization: {

minimizer: [newOptimizeCSSAssetsPlugin({})],

},

plugins: [

newMiniCssExtractPlugin({

filename:'[name].css',

chunkFilename: '[id].css',

})

],

module: {

rules: [

{

test: /\.css$/,

use:[MiniCssExtractPlugin.loader, 'css-loader'],

}

],

},

};

导致 CSS 文件体积较大的情况通常是由于代码中包含了过多没用的样式。通过 Chrome dev tools 可以获取到当前页面中所使用到的 CSS 的占比,帮助检查出冗余的样式代码。

另一个容易使 CSS 文件体积过大的是 url-loader。如果在 Webpack 配置中使用了 url-loader 的话要注意 CSS 的内容中是不是包含了过多图片的 base64 URI。

url-loader 的 limit 如果设置的比较大,同时页面又有很多小的图片,并且由于 base64 URI 的 gzip 效果很差,很容易就会使 CSS 的体积变得很大。

下面的示例将 url-loader 的 limit 设为 2 KB,具体的数值设置要根据项目实际情况。

JavaScript

rules: [

{

test: /\.(png|jpg|gif)$/i,

use: [

{

loader:'url-loader',

options: {

limit:2048,

},

}

],

}

]

使用 Brotli 进行资源压缩

Brotli 是由 Google 开发的无损压缩算法,可以在几乎相同的速度下比 gzip 得到更好的压缩效果,并且它已经被绝大多数现代浏览器所支持:

有人通过大量网络上的资源对 Brotli 和 gzip 进行了一个对比:

  • - 对于 JavaScript 文件,Brotli 产出的压缩结果比 Gzip 小了 14%;

  • - HTML 文件缩小了 21%;

  • - CSS 文件缩小了 17%。

有很多工具可以让我们在构建流程中使用 Brotli 进行资源压缩,对于 Webpack 工程的话可以直接使用`brotli-webpack-plugin`。请看下面的例子。

JavaScript

var BrotliPlugin = require('brotli-webpack-plugin');

module.exports = {

plugins: [

newBrotliPlugin({

asset:'[path].br',

test:/\.(js|css|svg)$/

})

],

};

通过上面的配置,Webpack 在打包后会在原有资源的基础上生成一个`.br`文件,也就是经过 Brotli 压缩后的版本。我们可以将它与原有的资源文件一同上传到 CDN,这样如果浏览器不支持 Brotli,也可以使其回退来使用 gzip。

Brotli 生效的话,返回头中content-encoding 的值应该为 `br`。

资源打包分析和监控

最后也是最重要的一点,是对项目资源进行持续的监控和分析。下面介绍几个比较常用的工具。

webpack-bundle-analyzer

webpack-bundle-analyzer 借助可视化的方式直观地展示输出资源的构成,比如下面的例子。

const  BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {

plugins: [

newBundleAnalyzerPlugin(),

],

};

以上面提到过的 moment.js 为例,会得到下面这样一个分析图:

从图中可以发现 moment.js 中 locale 文件过多的问题。实际工程的情况会比这个更复杂,但仍然可以帮助我们排查冗余模块的存在。

size-plugin

size-plugin 是一个 Webpack 插件,可以在每次执行打包命令后打印出本次构建的资源体积并和上次构建结果进行对比。

JavaScript

const SizePlugin = require('size-plugin');

module.exports = {

plugins: [newSizePlugin()],

};

Import Cost

Import Cost 是一个 VSCode 的一个扩展,可以在模块加载语句旁边展示出所加载模块的大小。

总结

上面介绍了几种给 Webpack 应用“瘦身”的方法,更多的关于 Webpack 优化方面的介绍可以参考我写的《Webpack实战》。

这本书从头梳理了关于 Webpack 的概念,覆盖了常见的使用场景、问题和解决方法,也有关于最新打包工具前沿趋势的思考。

这本书的初衷是尽量区别于官方文档,更多地加入我个人的经验与思考。把我曾经遇到过的问题写出来,让后面的人少走一些弯路。

同时,也欢迎大家购买我的图书,下面二维码可以进行直接购买。

本文完~

PS:这个是资深前端工程师、Webpack技术专家、知名开源项目YKit发起者,居玉皓的经验之作,作者从功能、原理、实践、优化4个维度全面讲解Webpack,指导读者快速并轻松进阶。

最后,为了感谢大家的一路支持,在这里,免费送大家5本《Webpack实战》图书,获取图书的方式非常简单。

只要在此文章留言处分享一下你的编程故事以及为啥想要学习Webpack,点赞最高的前5名小伙伴,就有机会获得这本图书。

截止时间:2019-07-16 早上9点

因为免费送的图书有限,没有获得的小伙伴,也可以通过上面的二位进行直接购买,这本图书,还是非常实用的,如果你也是一名前端学习者或者编程爱好者或者也正在使用Webpack的话,我这边也推荐大家可以去购买这本图书来阅读一下。

【免费送书】小白也能学会的Webpack 应用瘦身技巧相关推荐

  1. python3自动化测试书籍推荐_免费送书 | 《Selenium 3+Python 3自动化测试项目实战:从菜鸟到高手》...

    点击上方蓝色字体,关注我们 免费送书 2019年就剩「2个月」了,你的读书计划进行得如何? 莫踌躇,光荣之路马上送你本书! 读完它,请为你的2019年画上个美丽的圈圈! <Selenium 3+ ...

  2. 免费送书啦!火遍全网的AI给老照片上色,这里有一份详细教程!

    0深度学习最令人兴奋的应用之一是智能照片美化,例如为黑白图像着色.破损图片修复以及去模糊等. 以黑白图像着色为例,通过将 AI 与照片着色相结合,即使不会使用Photoshop 等图片编辑工具,为黑白 ...

  3. 免费送书啦!《3D计算机视觉:原理、算法及应用》一本全搞定

    1966年,人工智能学家Minsky在给学生布置的作业中,要求学生通过编写一个程序让计算机告诉我们它通过摄像头看到了什么,这也被认为是计算机视觉(Computer Vision,CV)最早的任务描述. ...

  4. 【第2期免费送书】 10本机器学习与Python相关书籍等你来领!经典之作,绝对领你心动......

    微信公众号 关键字全网搜索最新排名 [机器学习算法]:排名第一 [机器学习]:排名第一 [Python]:排名第三 [算法]:排名第四 AI系列公开课,限时免费 [强烈推荐] AI 系列免费公开课.. ...

  5. 我的书出版了,本周限时优惠,免费送书30本!

    随着互联网和传统行业的深度融合,产生了新的生态,面向企业的产品和服务也蓬勃发展,催生了新的岗位 --B 端产品和运营等,我也是其中的一分子.  01 B 端产品的服务对象是公司,通常行业特征相对明显, ...

  6. 愚人节老板发话了,免费送书 + 免费入驻Java知识星球!!

    愚人节快乐,今天的活动很重磅! 1.免费送5本重量级技术书籍,不骗人,小程序随机抽奖送出哦! 2.免费进星球,哈哈不可能,愚人节快乐!不过今天有重大优惠,见下文! 活动一:免费送出5本重量级书籍 赠书 ...

  7. ClickHouse免费送书福利

    预计阅读时间: 13分钟 导读:一次机缘巧合,在研究BI产品技术选型的时候,我接触到了ClickHouse,瞬间就被其惊人的性能所折服.这款非Hadoop生态.简单.自成一体的技术组件引起了我极大的好 ...

  8. 免费送书 | 《自动化测试实战宝典:Robot Framework + Python从小工到专家》

    测试行业正在进入一个全新的阶段,表现出全新的特点. 1. 纯功能测试人员正在退出舞台 2. 对测试人员的能力要求越来越综合 一名优秀的测试工程师具备的核心关键能力总的来讲概括为:三项基本功+七大关键能 ...

  9. 荐书与免费送书:《编写高质量代码改善 Python 程序的 91 个建议》

    为了学习如何打理好微信公众号,Python猫我关注了好几个python技术公众号.然后发现这些同行们都在免费送资源,或者抽奖送书耶.于是,我也去参与抽奖,竟然侥幸抽中啦一本<Python数据科学 ...

最新文章

  1. 动态代理机制之查看一个类或接口中有哪些方法
  2. CSS------当内容超出div宽度后自动换行和限制文字不超出div宽度和高度
  3. Python输入输出练习,运算练习,turtle初步练习
  4. 2021-9-下旬 数据结构-线性表-链表-java代码实现(复习用)
  5. 为什么awt_为AWT的机器人创建DSL
  6. javascript !-- //-- 与老的浏览器打交道
  7. curl php 禁用ip6,CentOS 6禁用IPv6解决curl Couldn’t resolve host或dns解析慢
  8. jedis的源码理解-基础篇
  9. 第三十八篇、给UITabBar按钮的动画效果
  10. 2021 年 Web 开发的 7 大趋势,我只能说牛逼!
  11. 如何通过事件可视化分析?
  12. 如何删除绿盾加密软件
  13. 通俗易懂的Python入门基础详细教程
  14. 一篇关于微信防撤回(文本、图片、语音、视频、名片等...)的Python学习教程
  15. python中梅花数_梅花易数中的“数字”
  16. 百度AI 开放平台API调用
  17. 基于JavaScript实现拼图游戏
  18. java精品入门-0基础第一篇
  19. 夜天之书 #49 开源软件的技术写作
  20. 恭喜EDG 夺得冠军

热门文章

  1. 巧用企业微信机器人:客服信息预警中心
  2. 关于AMS(艾迈斯)的VOC传感器iAQ-Core的使用笔记
  3. 2020年磺化工艺考试题库及磺化工艺考试APP
  4. 云主机Windows Server 2012 R2 的 VMware 和HYPER-V不兼容怎么删除HYPER-V
  5. smartdraw, visio的一个替代品
  6. PHP中文网免费视频教程
  7. CSS 三大特性(层叠性,继承性,优先级)
  8. 中国青年女科学家奖公布:付巧妹等20人、风云卫星高精度定标与定位技术等5个团队获奖 | 美通社头条...
  9. QQ群单个私聊给每个群成员发消息 第2版使用属性页 按键精灵源码
  10. php跳转外链,分享两种外链跳转方法,可避免权重流失。