antd 工程优化

Flying
2016-06-08 / 0 评论 / 139 阅读 / 正在检测是否收录...

上次预演之后,得到了领导的肯定。项目也如火如荼地开展起来。一切都很顺利。。截至目前为止完成90%以上开发工作。现在是时候考虑优化了。

webpack-antd.svg

按需加载

先前我们使用了 antd init 脚手架工具,它对 antd 没有进行深度优化。比如说我们的组件导入的时候不是按需加载的。然我们只是用了部分组件,但是由于使用全部导入,不得不加载所有组件。 导致单个 JavaScrip 包(bundel) 和 CSS 包都很大,页面首次加载比较慢。

好消息是 antd 出新版了,v1.0 已经支持按需加载了。有两种方式:

  1. 非 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

所以这种方式相对于全部导入代码改动比较大,而且要对组件库结构比较熟悉才行。

  1. babel 方式

如果你使用 babel,就容易多了。推荐使用 babel-plugin-antd 来进行按需加载。

npm i -D babel-plugin-import

安装好这个插件后,还需要在 .babelrcbabel-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 的公共模块。

  1. 指定公共入口
entry: {
  vendor: ['react', 'react-dom', 'react-router', 'redux'],
  app: './src/index',
}
Redux 本身很小,不加也可以,这里只是举例说明。
  1. 新建立一个独立文件
plugins: [
  ...
  new Webpack.optimize.CommonsChunkPlugin({
    // vendor 是包括公共的第三方代码,称为 initial chunk
    name: 'vendor'
  }),
]

运行 npm run build。可以看到当前模多出了一个独立文件 vendor.jsapp.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,所以可以动态路由实现组件懒加载。

  1. getComponent 异步方法

React router 中的 getComponent 用来异步获取组件。它接受两个参数 : locationcallback。当 React router 执行回调函数 callback(null, component)时,路由只渲染指定组件 component。

  1. 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.jsusers.jsfeedback.jsapp.jsapp.css比优化前小很多,这意味着节省首页加载的时间。

相关资源

6

评论 (0)

取消