用 Webpack 解决应用性能问题
1. 影响页面加载时长的 Top3 因素
- 页面初载时,加载大量 JavaScript 脚本;
- 页面初载时,加载大量 CSS 文件;
- 页面初载时,加载大量网络资源;
页面加载的越久,页面不可交互的时间就越长,用户的体验就越差。
2. 页面优化的目标
- 页面初载时,未压缩的 JavaScript 脚本大小: <=200KB ;
- 页面初载时,未压缩的 CSS 资源大小: <=100KB ;
- HTTP 协议下,请求资源数: <=6 个 ;
- HTTP/2 协议下,请求资源数: <=20 个 ;
- 90% 的代码覆盖率(仅允许 10% 的未使用代码);
只有 Chrome 能够查看你的代码覆盖率。
遵从这个目标,应用将能在任何平台(PC,Mobile Phone...)都拥有良好的性能:
- 未来的网络世界在移动端;
- 平均每个移动端网站需要花费 14 秒时间达到可交互状态;
- 加载的代码越少,页面达到可交互的时间越短;
3. 查看代码覆盖率
- 打开 Chrome Dev Tool;
- 按下
Cmd + Shift + PorCtrl + Shift + P; - 输入
Coverage,选择第一个出现的选项:

- 点击面板上的
reload按钮,查看整个应用 JavaScript 的代码覆盖率:

4. 如何做到?
(1)代码分割(code splitting)
什么是 code splitting?
将部分代码在构建时转变为异步加载的过程。
(1.1)代码分割原理
代码分割的核心是异步加载资源,而异步加载功能使用到 stage 3 规范:whatwg/loader。import() 允许你在浏览器端运行时动态获取资源,虽然它存在以下一些问题:
- 安全问题;
- 浏览器支持问题;
(1.2)代码分割的两种类型
- 静态的;
- “动态的”(在 webpack 中,并不是真的动态):“动态”是指你能够在代码运行时决定应该引入什么 JavaScript 模块;
(1.3)静态代码分割
何时使用静态的代码分割?
- **你正在使用一个非常大的库或框架 **:如果在页面初始化时你不需要使用它,就不要在页面初载时加载它;
- **任何临时的资源 **:指不在页面初始化时被使用,被使用后又会立即被销毁的资源,例如模态框,对话框,tooltip等(任何一开始不显示在页面上的东西都可以有条件的加载);
- 路由 :既然用户不会一下子看到所有页面,那么只把当前页面相关资源给用户就是个明智的做法;
代码示例
import Listener from './listeners.js'
const getModal = () => import('./src/modal.js')
Listener.on('didSomethingToWarrentModalBeingLoaded', () => {
// Async fetching modal code from a separate chunk
getModal().then((module) => {
const modalTarget = document.getElementById('Modal')
module.initModal(modalTarget)
})
})
注意:
- 在 Vue 中,可以直接使用
import()关键字,在 React 中,使用react-loadable完成同样的事; - 每当你使用动态代码分割时,函数将返回一个 Promise 对象;
(1.4)“动态”代码分割
何时使用“动态”代码分割?
- **A/B Test **:你不需要在代码中引入不需要的 UI 代码;
- **主题 **:动态加载相应的主题;
- 为了方便 :本质上,你可以用静态代码分割代替“动态”代码分割,但是后者比前者拥有更少的代码量;
代码示例
const getTheme = (themeName) => import(`./src/themes/${themeName}`)
// using `import()` 'dynamically'
if (window.feeling.stylish) {
getTheme('stylish').then((module) => {
module.applyTheme()
})
} else if (window.feeling.trendy) {
getTheme('trendy').then((module) => {
module.applyTheme()
})
}
这背后的原理是,webpack 将目录中所有可以分离的 JavaScript 文件都生成了被称为 contextModule 的模块,所以本质上仍然是静态的。
(2)魔术注释
魔术注释技术是为代码分割技术服务的,它表现为在 import 关键字前使用指定注释来控制 webpack 生成的分割后代码片段。
代码示例
import (
/* webpackChunkName: "my-chunk-name" */
'./footer'
)
同时,你需要在 webapck.config.js 中添加配置:
{
output: {
filename: "bundle.js",
chunkFilename: "[name].lazy-chunk.js"
}
}
(2.1)webpack Modes
webpack 提供了一些注释让我们能够选择异步加载的模块应该被怎样组织:
import (
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: lazy */
'./someModule'
)
webpackMode 的默认值为 lazy ,指所有异步模块都会被单独抽离成单一的 chunk,通过使用 lazy-once 值,可以将所有的异步加载模块放在同一个 chunk 中。
(2.2)Prefetch & Preload
通过开启 prefetch ,我们可以通过使用 <link rel="prefetch>" 的特性,让浏览器在空闲时帮我们预先加载我们的异步资源,这有助于提升应用性能。
import(
/* webpackPrefetch: true */
'./someModule'
)
注意 :当你确保你的异步代码在未来一定会用到时,再开启该功能。
5. 参考链接
- https://developers.google.com/web/fundamentals/performance/optimizing-javascript/code-splitting/?hl=zh-cn
- https://webpack.js.org/guides/code-splitting/
- https://webpack.js.org/api/module-methods/#magic-comments
- https://medium.com/webpack/link-rel-prefetch-preload-in-webpack-51a52358f84c
用 Webpack 解决应用性能问题的更多相关文章
- 第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题
一. 开篇说明 EF的性能问题一直以来经常被人所吐槽,究其原因在于“复杂的操作在生成SQL阶段耗时长,且执行效率不高”,但并不是没有办法解决,从EF本身举几个简单的优化例子: ①:如果仅是查询数据,并 ...
- Webpack——解决疑惑,让你明白
Webpack——解决疑惑,让你明白 极客教程 作者 关注 2016.09.29 17:46* 字数 2868 阅读 22204评论 22喜欢 80 Webpack是目前基于React和Redux开发 ...
- 【译文】使用webpack提高网页性能优化
这篇文章原文来自https://developers.google.com/web/fundamentals/performance/webpack/. 说是译文其实更像是笔者做的笔记,如有错误之处请 ...
- 解决Linux性能问题的前60秒
为了解决性能问题,你登入了一台Linux服务器,在最开始的一分钟内需要查看什么? 在Netflix我们有一个庞大的EC2 Linux集群,还有非常多的性能分析工具来监控和调查它的性能.其中包括用于云监 ...
- webpack之前端性能优化(史上最全,不断更新中。。。)
最近在用webpack优化首屏加载性能,通过几种插件之后我们上线前后的速度快了一倍,在此就简单的分享下吧,先上个优化前后首屏渲染的对比图. 可以看到总下载时间从3800ms缩短到1600ms. 我们在 ...
- webpack 解决 semantic ui 中 google fonts 引用的问题
semantic ui css 的第一行引用了 google web font api,由于不可告人而又众所周知的原因,这条链接在国内无法访问: @import url('https://fonts. ...
- [转] webpack之前端性能优化(史上最全,不断更新中。。。)
最近在用webpack优化首屏加载性能,通过几种插件之后我们上线前后的速度快了一倍,在此就简单的分享下吧,先上个优化前后首屏渲染的对比图. 可以看到总下载时间从3800ms缩短到1600ms. 我们在 ...
- webpack 解决跨域问题
一.webpack 内置了 http-proxy-middleware 可以解决 请求的 URL 代理的问题 安装:npm install --save http-proxy-middleware 二 ...
- webpack解决单页面路由问题
index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
随机推荐
- React 事件对象、键盘事件、表单事件、ref获取dom节点、react实现类似Vue双向数据绑定
1.案例实现代码 import React, { Component } from 'react'; /** * 事件对象.键盘事件.表单事件.ref获取dom节点.react实现类似Vue双向数据绑 ...
- JavaWeb实现文件上传下载功能实例解析 (好用)
转: JavaWeb实现文件上传下载功能实例解析 转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web ...
- IPython4_Notebook
目录 目录 前言 系统软件 Setup IPython Setup IPython Setup Notebook 临时指定镜像源 Install pyreadline Install pyzmq In ...
- arguments对象的callee属性详解
在函数内部,有两个特殊的对象:arguments和this. argument对象有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数.请看下面这个非常经典的阶乘函 ...
- java:struts框架2(方法的动态和静态调用,获取Servlet API三种方式(推荐IOC(控制反转)),拦截器,静态代理和动态代理(Spring AOP))
1.方法的静态和动态调用: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...
- ffi模块——node调用动态链接库(.so/.dll文件)
参考资料1:[https://www.npmjs.com/package/ffi] 参考资料2:[http://imweb.io/topic/57732fbef0a5487b05f325bf] 参考资 ...
- 关于token的理解
什么是token token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识. 当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个 ...
- C++ 简介 基本语法 注释
一.第一个 C++ 程序 #include <iostream> using namespace std; int main() { cout << "Hello, ...
- Layer 弹出层抖动问题
layer.open({ type: 2, anim: 5,//加上anim,渐显 title: '品牌列表', shadeClose: fal ...
- centoss7下将命令加开机服务
https://www.cnblogs.com/hxun/p/11075755.html