上次预演之后,得到了领导的肯定。项目也如火如荼地开展起来。一切都很顺利。。截至目前为止完成90%以上开发工作。现在是时候考虑优化了。
按需加载
先前我们使用了 antd init
脚手架工具,它对 antd 没有进行深度优化。比如说我们的组件导入的时候不是按需加载的。然我们只是用了部分组件,但是由于使用全部导入,不得不加载所有组件。 导致单个 JavaScrip 包(bundel) 和 CSS 包都很大,页面首次加载比较慢。
好消息是 antd 出新版了,v1.0 已经支持按需加载了。有两种方式:
- 非 babel 方式
import 'antd/lib/form/style/index.css';
import Form from 'antd/lib/form';
不仅组件的 JavaScript 代码 如此,CSS 也是如此。
非 babel 方式必须导入该组件所需的所有 CSS,其中 antd/lib/style/index.css
是所有组件都要导入的样式。
特别要注意有些依赖的样式也要导入,比如 DatePicker
需要导入以下样式:
- antd/lib/style/index.css
- antd/lib/date-picker/style/index.css
- antd/lib/input/style/index.css
- antd/lib/button/style/index.css
所以这种方式相对于全部导入代码改动比较大,而且要对组件库结构比较熟悉才行。
- babel 方式
如果你使用 babel,就容易多了。推荐使用 babel-plugin-antd
来进行按需加载。
npm i -D babel-plugin-import
安装好这个插件后,还需要在 .babelrc
或 babel-loader
配置:
{
"plugins": [["import", options]]
}
options
可以是对象或数组,常见的配置有以下几种:
- ["import", { "libraryName": "antd" }]:模块化地导入 JavaScript
- ["import", { "libraryName": "antd", "style": true }]: 模块化地导入 JavaScript 和 CSS (less 源文件)
- ["import", { "libraryName": "antd", "style": "css" }]:模块化地导入 JavaScript 和 CSS (css 生成文件)
加入这个插件后。你可以仍然使用先前的写法:
import { Form, Input, Button } from 'antd';
babel-plugin-import
插件会帮你转换成上面的写法。另外此插件配合 style 属性可以做到模块样式的按需自动加载。看到没有,不用单独或另外导入组件的 CSS 文件。
实现按需加载比较容易,照文档操作一遍就行。运行 npm run build
,可以看到当前模块对应的独立文件小多了,这是组件按需加载的功劳。
Asset Size Chunks Chunk Names
static/js/app.js 573 kB 0 [emitted] app
static/css/app.css 132 kB 0 [emitted] app
index.html 206 bytes [emitted]
Webpack 分包
不仅 antd 组件使用不当会冗余。我们的其他公共基础库也会冗余。比如说像 React、React DOM、React router 和 Redux 这些公共基础库在每个模块可能都会使用这些它们。如果打包后每个模块都包含这些库的备份。会导致每个 JavaScript 包都很大,这就存在严重的数据冗余——理想状态下我们需要把这些公共基础库单独打成一个独立文件,其他引用公共基础库的模块分别打包。
对于 HTTP/1.1,由 Webpack 打包比较大,这样可以减少浏览器请求,从而减少应用程序必须等待的时间。对于 HTTP/2,可以使用代码分离,打包比较小,重分利用 HTTP/2 多并发请求的优势实现最佳构建结果。
目前,默认配置下 Webpack 还不能自动处理公共基础库。我们需要解决这个问题。
我们可以为公包指定一个入口(entry),再使用 CommonsChunkPlugin
插件来新建一个独立文件(又称作 chunk)的功能,这个文件包括多个入口 chunk 的公共模块。
- 指定公共入口
entry: {
vendor: ['react', 'react-dom', 'react-router', 'redux'],
app: './src/index',
}
Redux 本身很小,不加也可以,这里只是举例说明。
- 新建立一个独立文件
plugins: [
...
new Webpack.optimize.CommonsChunkPlugin({
// vendor 是包括公共的第三方代码,称为 initial chunk
name: 'vendor'
}),
]
运行 npm run build
。可以看到当前模多出了一个独立文件 vendor.js
,app.js
又小不少。
Asset Size Chunks Chunk Names
static/js/app.js 363 kB 0 [emitted] app
static/js/vendor.js 212 kB 1 [emitted] vendor
static/css/app.css 132 kB 0 [emitted] app
index.html 270 bytes [emitted]
好了,基本上我们已经通过分包达到优化的目的。最后可以考虑组件懒加载。
懒加载组件
我们的项目使用了 React router,所以可以动态路由实现组件懒加载。
getComponent
异步方法
React router 中的 getComponent
用来异步获取组件。它接受两个参数 : location
和 callback
。当 React router 执行回调函数 callback(null, component)时,路由只渲染指定组件 component。
require.ensure
方法
语法:require.ensure(dependencies, callback, chunkName)
使用该方法需要注意 :
- require 函数在这里只能接受字符串,不能接受变量
- 如果你的组件是使用 ES6 的
export.default
导出的话,那么需要加上default
- 需要按需加载的路由级组件必须在路由页面进行加载
Webpack 中的 require.ensure
可以定义分割点来打包独立文件,再配合getComponent
方法就可以实现 React 组件的按需加载。
{
path: 'feedback',
getComponent(location, callback) {
require.ensure([], (require) => {
callback(null, require('./FeedBack').default)
}, 'feedback')
}
}
该实例中,只有访问 /feedback
时,才会加载 FeedBack
组件。
设置好路由后,运行 npm run build
。
Asset Size Chunks Chunk Names
static/js/app.js 6.54 kB 0 [emitted] app
static/js/home.js 28.3 kB 1 [emitted] home
static/js/users.js 227 kB 2 [emitted] users
static/js/feedback.js 183 kB 3 [emitted] feedback
static/js/vendor.js 212 kB 4 [emitted] vendor
static/css/app.css 95.7 kB 0 [emitted] app
index.html 270 bytes [emitted]
可以看到 app.js
按路由另外拆分出几个独立文件 home.js
、users.js
、feedback.js
。app.js
和 app.css
比优化前小很多,这意味着节省首页加载的时间。
评论 (0)