文章目錄
  1. 1. 问题描述:
  2. 2. 问题分析和解决:
    1. 2.1. 1. react-router 按需加载
    2. 2.2. 2. jquery、moment等用cdn
    3. 2.3. 3. 删除react-bootsrtap、react-router-bootstrap等用处不大的依赖,需要的,比如react-router-bootstrap的NavItemLink,自己实现。
    4. 2.4. 4. 依赖的组件库,antd,从entry.js中抽出antd,放入common.js中
  3. 3. 结论
  4. 4. 参考

问题描述:

丁丁租房,在8月初,开发大版本的重构。我也是在7.30号,加人丁丁,也莫名其妙的成为了第一个丁丁的前端。因为没有历史包袱,所以,当时决定用react+webpack,虽然从来没有接触过react和webpack。
在经过大概3周的开发后,代理商系统(http://daili.zufangzi.com/#/),和400系统(http://400.zufangzi.com/#/)开发完成。因为经验的缺乏、人力太少、时间太短,两个系统存在很多不完美的地方。其中,最大的问题是:webpack打包后,形成两个主要的js文件——entry.js 和 common.js ,都比较大,网络不好的时候,加载很慢。在上线当天,老板,就提出了,优化的问题……
以代理商为例:
代理商系统,目前线上两个js文件的大小:
Alt text

问题分析和解决:

想要达到的结果:尽量减少两个js文件的大小、尽量按需加载

1. react-router 按需加载

项目用react-router进行路由的管理,如下:router.js

import React from 'react';
import ReactRouter from 'react-router';

// 主入口
import App from './page/App';


// 房源
import storageHouseInfo from './page/house/storageHouse/storageHouse';
import houseList from './page/house/houseList';
import houseShow from './page/house/houseShow/houseShow';
import houseModify from './page/house/houseModify/houseModify';
import picEdit from './page/house/editpic';

// 账户管理
import accountModify from './page/account/modify';

import noAuth from './page/noAuth/noAuth';
// 定义整个页面的路由结构
require.ensure([], function (require) {
    var Router = ReactRouter.Route;

    var routes = (
        <Router path="/" handler={App}>
            <Router path="house/storage" name="subMenuId=housePutInFeature" handler={storageHouseInfo}/>
            <Router path="house/list" name="subMenuId=houseManage" handler={houseList}/>
            <Router path="house/show" name="subMenuId=houseShow" handler={houseShow}/>
            <Router path="house/modify" name="subMenuId=houseModify" handler={houseModify}/>
            <Router path="house/editpic" name="subMenuId=editpic" handler={picEdit}/>

            <Router path="account/modify" name="subMenuId=accountManagement" handler={accountModify}/>
            <Router path="noauth" name="subMenuId=noAuth" handler={noAuth}/>
        </Router>
    );

    ReactRouter.run(routes, ReactRouter.HashLocation, (Root) => {
        React.render(<Root/>, document.body);
    });
});

这样,导致的问题,所有的业务代码,都会直接打到entry.js里。所有,要能够使handler异步加载。

asyncPage.js:

/**
*异步加载模块
*/
var React = require('react');
var handlers = {};
var AsyncRoute = function(req) {
    return React.createClass({
        getInitialState: function() {
            return {
                myComponent: handlers[req]
            };
         },
        statics: {
            // willTransitionTo,react-router生命周期: 当一个handler 将要被渲染的时候被调用
            // willTranstionFrom是当一个被激活路由将要跳出的时候给你提供了中断跳出的方法
            willTransitionTo: function (transition, params, query, callback) {
                var deffer = new Promise(function(resolve, reject) {
                    require.ensure([], function() {
                        var Comp = handlers[req] || require(req);
                        handlers[req] = Comp;
                        resolve();
                    });
                });
                deffer.then(function() {
                    callback();
                });
            }
        },
        render: function() {
            return (<this.state.myComponent />);
        }
    });
};

module.exports = AsyncRoute;

router.js里的更改:

import React from 'react';
import ReactRouter from 'react-router';

var AsyncRoute = require("./asyncPage");
var routerConf = require("./routerConf");

// 主入口
import App from './page/App';

// 房源
// import storageHouseInfo from './page/house/storageHouse/storageHouse';

//import houseList from './page/house/houseList';
//import houseShow from './page/house/houseShow/houseShow';
//import houseModify from './page/house/houseModify/houseModify';
//import picEdit from './page/house/editpic';

// 账户管理
//import accountModify from './page/account/modify';

//import noAuth from './page/noAuth/noAuth';

// 定义整个页面的路由结构
// 异步加载handler
require.ensure([], function (require) {
    var Router = ReactRouter.Route;
    var routes = (
        <Router path="/" handler={App}>
            <Router path={routerConf['housePutInFeature']} name="subMenuId=housePutInFeature" handler={AsyncRoute('./page/house/storageHouse/storageHouse.js')}/>
            <Router path={routerConf['houseManage']} name="subMenuId=houseManage" handler={AsyncRoute('./page/house/houseList/index.js')}/>
            <Router path={routerConf['houseShow']} name="subMenuId=houseShow" handler={AsyncRoute('./page/house/houseShow/houseShow.js')}/>
            <Router path={routerConf['houseModify']} name="subMenuId=houseModify" handler={AsyncRoute('./page/house/houseModify/houseModify.js')}/>
            <Router path={routerConf['editpic']} name="subMenuId=editpic" handler={AsyncRoute('./page/house/editpic/index.js')}/>
            <Router path={routerConf['accountManagement']} name="subMenuId=accountManagement" handler={AsyncRoute('./page/account/modify/index.js')}/>
            <Router path={routerConf['noAuth']} name="subMenuId=noAuth" handler={AsyncRoute('./page/noAuth/noAuth.js')}/>
        </Router>
        );

    ReactRouter.run(routes, ReactRouter.HashLocation, (Root) => {
        React.render(<Root/>, document.body);
    });
});

webpack.config.js中的修改:

output: {
    path: '/',
    // path: __dirname + "/release",
    publicPath: '/agent-asset/',
    // filename: '[name].[hash].js',
    filename: '[name].js',
    chunkFilename: 'entry.biz.[hash].js' //  加上这句!!嘻嘻……
}

通过上述的修改,webpack在打包时,会自动给我们分出一个entry.biz.hash.js,这个js文件,会在登录点菜单时,按需加载。

2. jquery、moment等用cdn
3. 删除react-bootsrtap、react-router-bootstrap等用处不大的依赖,需要的,比如react-router-bootstrap的NavItemLink,自己实现。
4. 依赖的组件库,antd,从entry.js中抽出antd,放入common.js中

在webpack.config.js中,如下更改。

entry: {
    common: ['react', 'antd'],
    entry: [
        'webpack-dev-server/client?http://localhost:8080',
        'webpack/hot/only-dev-server',
        './src/router'
    ]
},

结论

在经过上面四步后,

Alt text

登录时加载的entry.js,从917k减少到了141k,但是common.js因为加入了antd,从281k增加到了469k……entry.biz.js会在登录点击菜单后进行加载。

结果……虽然,比之前好点……但是还是不够完美……后面待续……

参考

http://segmentfault.com/a/1190000002801128
这个,是后来发现的,也不错~但是没有实验过。https://github.com/QianmiOpen/react-async-router

文章目錄
  1. 1. 问题描述:
  2. 2. 问题分析和解决:
    1. 2.1. 1. react-router 按需加载
    2. 2.2. 2. jquery、moment等用cdn
    3. 2.3. 3. 删除react-bootsrtap、react-router-bootstrap等用处不大的依赖,需要的,比如react-router-bootstrap的NavItemLink,自己实现。
    4. 2.4. 4. 依赖的组件库,antd,从entry.js中抽出antd,放入common.js中
  3. 3. 结论
  4. 4. 参考