We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在一系列测试网络应用质量的工具中,Lighthouse 脱颖而出。并且它集成进了 chrome 中,便利性也很高。
在 Lighthouse6 中,FCP 是六个主要指标中第一个指标,它测量的是用户第一次访问网页时浏览器需要多长时间呈现第一块 DOM 内容。图片,非空白的<canvas>,SVG 被认为是 DOM 内容(不包括 iframe 内的)。也不会考虑浏览器缓存的情况。FCP 在 v6 版本比重占 15%(v5 占 20%),是其他指标Speed Index、Largest Contentful Paint、Time to Interactive的基础,合计占总评分的70%,是开始优化的第一步。
我自己写了一个 demo,其中总结了自己的优化经验,记录一个典型的 webpack + antd 的项目中怎么进行优化。下面的文章也是基于这个demo。
webpack + antd
这是一个典型的网站,总共分为四个页面,包含了一些常见的组件,分别为主页,表单,表格和图表。样式和 Network 瀑布流如下:
这里使用的 Chrome 版本是86.0.4240.111,Lighthouse 版本是6.2.0。
等demo启动好,打开开发者工具 Lighthouse 面板,设置好需要评估的选项,这里以Performance和Desktop为例,表示测试桌面端浏览器的性能。点击 Generate report 开始生成报告。第一次启动可能时间会久一些,Lighthouse 需要预热。稍作等候,这样就得到了我们的报告。
可以看到这里的瓶颈就是 FCP 2.5s。
Lighthouse 模拟了环境带宽和 CPU 性能,是为了统一标准和计算结果,并不代表目标用户的实际体验。
我们知道同步 js 的加载和执行是会阻碍 DOM 渲染的, css 资源的优先级也是最高的,所以我们要把不需要的资源移除,减少打包的大小。下面我们借助 webpack-bundle-analyzer 分析打包结果。
鼠标悬浮在模块上会显示详情:stat size 是引用源码的大小,parsed size 是经过压缩后的大小,gzipped size 是 gzip 后的大小。面积越大在文件中的比例就越大。
可以看到所占比例最大的是 echarts,其次是 moment。我们查找相关文档,echarts 可以按需引入,moment 不需要的 locale 文件也可以移除。
// src/components/chart.tsx // 完整引入 import echarts from 'echarts'; // 按需引入 import echarts from 'echarts/lib/echarts' import 'echarts/lib/chart/line' import 'echarts/lib/chart/pie' import 'echarts/lib/component/tooltip' import 'echarts/lib/component/legend'
完整引入大小: 按需引入大小:
可以看到改成按需引入后结果是让人惊喜的。除了 echarts,现在很多开源组件都支持了按需引入,有的是通过 ES modules 支持来 tree shaking。其他依赖也可以找到对应的文档,查看是否提供了按需引入的方法。
antd 本身支持 ES modules的 tree shaking 的,样式也可以只引入需要的部分。
// 完整引入 // src/app.tsx // 入口处完整引入样式 import 'antd/dist/antd.css' // 按需引入 // src/app.tsx // 入口处移除全部样式 - import 'antd/dist/antd.css' // src/components/home.tsx import { Carousel } from 'antd' // 引入需要的样式 import 'antd/es/carousel/style/index.css'
但是这样太繁琐了,我们可以交给 babel-plugin-import 处理。只需按需引入 js 的部分,它会自动帮我们引入组件对应的 css。
// .babelrc { // ... "plugins": [ // ... [ "import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" } ] ] }
css完整引入: css按需引入:
antd 部分组件依赖了moment.js,使用 webpack 打包时会把 moment.js 和所有的 locales 都引入。我们可以使用 moment-locales-webpack-plugin 来移除不需要的 locales。
// webpack-config.js const MomentLocalesPlugin = require('moment-locales-webpack-plugin') module.exports = { // ... plugins: [new MomentLocalesPlugin({ localesToKeep: ['zh-cn'], // 保留需要的语言 })], };
引入了所有的locales:只引入需要的locales:
如果想进一步优化,可以用 day.js 替换 moment.js。
webpack 在 production模式 下默认启用 TerserPlugin 来精简 js,但是 css 还没压缩。下面我们用 css-minimizer-webpack-plugin 来压缩 css。
// webpack-config.js const TerserPlugin = require('terser-webpack-plugin') const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') module.exports = { // ... optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: true, }), new CssMinimizerPlugin(), ], }, };
css压缩前: css压缩后:
FCP成绩的提高,其他指标也随之提高。
打开首页的时候,其他三个页面的组件也一并打包进了 main.js 和 main.css,从而会占用带宽和 CPU 资源,拖慢首页的加载。我们可以使用 webpack 的动态加载组件 import() 和 React.lazy 来实现代码拆分和懒加载。
以Form组件为例:
Form
// 同步加载 import Form from './components/form' <Route path="/form"> <Form /> </Route> // 懒加载 import { Suspense, lazy } from 'react' import { Spin } from 'antd' const Form = lazy( () => import( /* webpackChunkName: "form" */ './components/form' ) ) <Route path="/form"> <Suspense fallback={<Spin />}> <Form /> </Suspense> </Route>
这时候 FCP 从 1.6s 降到了 1.3s。点击 View Original Trace 查看 perfermence:
可以看到浏览器只请求了首页的 main.js 和 main.css,而 Form 的资源要等到 url 变成 /form 才会去请求。
/form
此时 main.css 和 main.js 优化减少到了,而 Form 和其他组件对应的 js 和 css 都从 main 里面拆分了出来。
vue 框架也支持 AsyncComponent来实现懒加载
在 demo 里我们给静态服务加上 gzip,把 koa-static 替换成 koa-static-cache,默认以 level=6 压缩。
level=6
由于 koa-static-cache 不支持 index.html,所以我们需要加上 index.html,即通过 http://localhost:8080/index.html 访问。
compression-webpack-plugin 可以在打包的时候就生成 gzip 后的资源,可以根据实际情况选择对应的压缩方式。
实际上用户的体验可能会因为网络通畅,资源缓存而更好,也可能因为网络拥堵,服务器压力大等情况更差。 但我们经过了下面的几个方向的尝试,确实提高了web应用的质量:
当然这只是茫茫多优化中的一小部分而已,再好的程序总是会有优化的空间的。良好的用户体验不仅仅需要速度快,还要浅显易懂的设计,友善的引导,清晰的出错提示等等。
CDN 服务商一般都能提供更快的网络和更低的延迟,让用户就近获取资源,缩短资源下载时间,减少自身服务器的压力。而且CDN 可以避免和 api 共用同一个域名,浏览器请求时不会携带 cookie 等 http 头,减少请求时间。
一般现代浏览器在同一个 origin 同时最大链接数是 6。打开多个标签也共享这6个限制。html,css,font,js,图片,ajax,下载文件等 http 请求等都受到限制( websocket 除外)。
有些应用依赖项过多的,想使用 DllPlugin 和 splitChunks.cacheGroups 等功能拆分 js 文件的需要注意,同步的 js 拆出来加载时依然是同步的,如果超过最大链接数反而会成为瓶颈。可以考虑转换成动态引入 import()。
服务端渲染是个值得尝试的技术,配合 css 的按需加载,可以让浏览器在 js 加载和执行前就渲染出页面。使用时要注意做好缓存和用户隔离。
HTTP/2其中的特性比如 HTTP 头压缩, 服务端推送, 多路复用等,可以减少资源传输的时间。HTTP/2 的支持率达到了 96% 以上 。
除了网站可能没有遵循最佳实践,也可能是 Lighthouse 版本小于 v6,在 v5 中 CPU 是4x slowdown并且模拟了更高的延迟和更低的吞吐量。
可能你使用了 webpack5,笔者自测 webpack-bundle-analyzer@3.9.0 版本还没有完全适配 wepack5。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
在一系列测试网络应用质量的工具中,Lighthouse 脱颖而出。并且它集成进了 chrome 中,便利性也很高。
在 Lighthouse6 中,FCP 是六个主要指标中第一个指标,它测量的是用户第一次访问网页时浏览器需要多长时间呈现第一块 DOM 内容。图片,非空白的<canvas>,SVG 被认为是 DOM 内容(不包括 iframe 内的)。也不会考虑浏览器缓存的情况。FCP 在 v6 版本比重占 15%(v5 占 20%),是其他指标Speed Index、Largest Contentful Paint、Time to Interactive的基础,合计占总评分的70%,是开始优化的第一步。
我自己写了一个 demo,其中总结了自己的优化经验,记录一个典型的
webpack + antd
的项目中怎么进行优化。下面的文章也是基于这个demo。介绍demo
这是一个典型的网站,总共分为四个页面,包含了一些常见的组件,分别为主页,表单,表格和图表。样式和 Network 瀑布流如下:
使用Lighthouse
等demo启动好,打开开发者工具 Lighthouse 面板,设置好需要评估的选项,这里以Performance和Desktop为例,表示测试桌面端浏览器的性能。点击 Generate report 开始生成报告。第一次启动可能时间会久一些,Lighthouse 需要预热。稍作等候,这样就得到了我们的报告。
可以看到这里的瓶颈就是 FCP 2.5s。
优化打包大小
我们知道同步 js 的加载和执行是会阻碍 DOM 渲染的, css 资源的优先级也是最高的,所以我们要把不需要的资源移除,减少打包的大小。下面我们借助 webpack-bundle-analyzer 分析打包结果。
鼠标悬浮在模块上会显示详情:stat size 是引用源码的大小,parsed size 是经过压缩后的大小,gzipped size 是 gzip 后的大小。面积越大在文件中的比例就越大。
可以看到所占比例最大的是 echarts,其次是 moment。我们查找相关文档,echarts 可以按需引入,moment 不需要的 locale 文件也可以移除。
按需引入
完整引入大小:
按需引入大小:
可以看到改成按需引入后结果是让人惊喜的。除了 echarts,现在很多开源组件都支持了按需引入,有的是通过 ES modules 支持来 tree shaking。其他依赖也可以找到对应的文档,查看是否提供了按需引入的方法。
antd 的样式按需引入
antd 本身支持 ES modules的 tree shaking 的,样式也可以只引入需要的部分。
但是这样太繁琐了,我们可以交给 babel-plugin-import 处理。只需按需引入 js 的部分,它会自动帮我们引入组件对应的 css。
css完整引入:

css按需引入:
只引入需要的 moment.js locales
antd 部分组件依赖了moment.js,使用 webpack 打包时会把 moment.js 和所有的 locales 都引入。我们可以使用 moment-locales-webpack-plugin 来移除不需要的 locales。
引入了所有的locales:
只引入需要的locales:
代码压缩
webpack 在 production模式 下默认启用 TerserPlugin 来精简 js,但是 css 还没压缩。下面我们用 css-minimizer-webpack-plugin 来压缩 css。
css压缩前:

css压缩后:
阶段性成果
FCP成绩的提高,其他指标也随之提高。
组件懒加载
打开首页的时候,其他三个页面的组件也一并打包进了 main.js 和 main.css,从而会占用带宽和 CPU 资源,拖慢首页的加载。我们可以使用 webpack 的动态加载组件 import() 和 React.lazy 来实现代码拆分和懒加载。
以
Form
组件为例:可以看到浏览器只请求了首页的 main.js 和 main.css,而
Form
的资源要等到 url 变成/form
才会去请求。此时 main.css 和 main.js 优化减少到了
,而
Form
和其他组件对应的 js 和 css 都从 main 里面拆分了出来。gzip 进一步优化资源下载速度
在 demo 里我们给静态服务加上 gzip,把 koa-static 替换成 koa-static-cache,默认以
level=6
压缩。总结
实际上用户的体验可能会因为网络通畅,资源缓存而更好,也可能因为网络拥堵,服务器压力大等情况更差。
但我们经过了下面的几个方向的尝试,确实提高了web应用的质量:
当然这只是茫茫多优化中的一小部分而已,再好的程序总是会有优化的空间的。良好的用户体验不仅仅需要速度快,还要浅显易懂的设计,友善的引导,清晰的出错提示等等。
其他可以优化或需要注意的地方
CDN
CDN 服务商一般都能提供更快的网络和更低的延迟,让用户就近获取资源,缩短资源下载时间,减少自身服务器的压力。而且CDN 可以避免和 api 共用同一个域名,浏览器请求时不会携带 cookie 等 http 头,减少请求时间。
浏览器并发请求链接数
一般现代浏览器在同一个 origin 同时最大链接数是 6。打开多个标签也共享这6个限制。html,css,font,js,图片,ajax,下载文件等 http 请求等都受到限制( websocket 除外)。
有些应用依赖项过多的,想使用 DllPlugin 和 splitChunks.cacheGroups 等功能拆分 js 文件的需要注意,同步的 js 拆出来加载时依然是同步的,如果超过最大链接数反而会成为瓶颈。可以考虑转换成动态引入 import()。
Server Side Rendering(SSR)
服务端渲染是个值得尝试的技术,配合 css 的按需加载,可以让浏览器在 js 加载和执行前就渲染出页面。使用时要注意做好缓存和用户隔离。
HTTP/2
HTTP/2其中的特性比如 HTTP 头压缩, 服务端推送, 多路复用等,可以减少资源传输的时间。HTTP/2 的支持率达到了 96% 以上 。
可能会遇到的问题
为什么 Lighthouse 评分极低?
除了网站可能没有遵循最佳实践,也可能是 Lighthouse 版本小于 v6,在 v5 中 CPU 是4x slowdown并且模拟了更高的延迟和更低的吞吐量。
为什么 webpack-bundle-analyzer 结果没有 parsed size 和 gziped size?
可能你使用了 webpack5,笔者自测 webpack-bundle-analyzer@3.9.0 版本还没有完全适配 wepack5。
The text was updated successfully, but these errors were encountered: