[关闭]
@xiaoqq 2016-12-29T04:09:05.000000Z 字数 2931 阅读 1220

Webpack Lazy Loading

Webpack


一、引言

目前项目中存在的问题:

  1. 同一个组件会被多个页面反复打包;
  2. 组件不能实现按需加载。

需要实现的目标:

  1. 每个组件必须被打包成独立的分片;
  2. 从一个页面切换到另外一个页面时,已加载过的组件不会被重复加载;
  3. 组件只有需要时才会被加载。

二、解决方案

采用Webpack2.X的Lazy Loading

三、实现步骤

1、 升级Webpack至2.x

  1. npm i webpack@2.1.0-beta.25 --save-dev
  2. npm i webpack@2.1.0-beta.25 -g

参考文章:https://gold.xitu.io/entry/581d9fcc8ac247004ff3c70e

2、修改Webpack配置文件

在现有的项目上直接使用webpack2.x会报错,必须先修改配置文件
1)resolve.extensions去掉' '

  1. resolve: {
  2. extensions: ['.js', '.jsx']
  3. },

2)去掉new webpack.optimize.OccurenceOrderPlugin()插件
3) (可选)对module进行改造

  1. module: {
  2. - loaders: [
  3. + rules: [
  4. {
  5. test: /\.css$/,
  6. - loaders: [
  7. + use: [
  8. {
  9. loader: "style-loader"
  10. },
  11. {
  12. loader: "css-loader",
  13. - query: {
  14. + options: {
  15. modules: true
  16. }
  17. ]
  18. }
  19. ]
  20. }

参考:https://webpack.js.org/guides/migrating/

3、添加LazilyLoad组件

  1. import React from 'react';
  2. /**
  3. * @function 支持异步加载的封装组件
  4. */
  5. class LazilyLoad extends React.Component {
  6. constructor() {
  7. super(...arguments);
  8. this.state = {
  9. isLoaded: false,
  10. };
  11. }
  12. componentWillMount() {
  13. this.load(this.props);
  14. }
  15. componentDidMount() {
  16. this._isMounted = true;
  17. }
  18. componentWillReceiveProps(next) {
  19. if (next.modules === this.props.modules) return null;
  20. this.load(next);
  21. }
  22. componentWillUnmount() {
  23. this._isMounted = false;
  24. }
  25. load(props) {
  26. this.setState({
  27. isLoaded: false,
  28. });
  29. const {modules} = props;
  30. const keys = Object.keys(modules);
  31. Promise.all(keys.map((key) => modules[key]()))
  32. .then((values) => (keys.reduce((agg, key, index) => {
  33. agg[key] = values[index];
  34. return agg;
  35. }, {})))
  36. .then((result) => {
  37. if (!this._isMounted) return null;
  38. this.setState({modules: result, isLoaded: true});
  39. });
  40. }
  41. render() {
  42. if (!this.state.isLoaded) return null;
  43. return React.Children.only(this.props.children(this.state.modules));
  44. }
  45. }
  46. LazilyLoad.propTypes = {
  47. children: React.PropTypes.func.isRequired,
  48. };
  49. export const LazilyLoadFactory = (Component, modules) => {
  50. return (props) => (
  51. <LazilyLoad modules={modules}>
  52. {(mods) => <Component {...mods} {...props} />}
  53. </LazilyLoad>
  54. );
  55. };
  56. export const importLazy = (promise) => (
  57. promise.then((result) => result)
  58. );
  59. export default LazilyLoad;

4、引入LazilyLoad组件

  1. import LazilyLoad, { importLazy, LazilyLoadFactory } from './LazilyLoad'

异步加载组件有两种方式
1)使用高阶组件包裹现有的页面组件,当页面加载时,被引用的组件会同时被异步加载,并且通过props传递给页面组件。

  1. class PageTest extends React.Component {
  2. render() {
  3. const { Breadcrumb, Table, Pagination } = this.props;
  4. return (
  5. <div id="page-test">
  6. <Breadcrumb menuDataList={this.props.menuDataList} />
  7. ...
  8. </div>
  9. )
  10. }
  11. }
  12. PageTest = LazilyLoadFactory(PageTest, {
  13. Breadcrumb: () => System.import('../../components/breadcrumb'),
  14. Table: () => System.import('../../components/cTable'),
  15. Pagination: () => System.import('../../components/pagination'),
  16. })

2) 按需加载组件:比如某个组件在首屏时并不显示,只有等弹窗时才需要显示,那么这个组件就可以采用按需加载的方式进行异步加载。

  1. class PageTestEdit extends React.Component {
  2. ...
  3. //返回LazilyLoad包裹后的组件
  4. createLazilyModule(moduleFn) {
  5. return (
  6. <LazilyLoad modules={{
  7. Datepicker: () => System.import('../../components/datepicker')
  8. }}>
  9. {moduleFn}
  10. </LazilyLoad>
  11. )
  12. }
  13. renderModuleEdit() {
  14. return (
  15. <div className="padding-20" id="edit-module">
  16. {this.createLazilyModule(({Datepicker}) => {
  17. return <Datepicker type="datetime" placeholder="请选择"/>
  18. })}
  19. </div>
  20. )
  21. }
  22. ...
  23. }

四、参考文献

Webpack2.x Lazy Loading - React: https://webpack.js.org/guides/lazy-load-react/
基于Webpack 2的React组件懒加载: https://segmentfault.com/a/1190000007938737

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注