前言
如果我们不进行按需加载, 把所有js加载到一个文件里面,会造成首屏加载慢的问题,毕竟把当前页面不需要的js也加载进来,因此我们要进行按需加载操作。
在react-router4之前,按需加载使用的是require.ensure的方法,异步加载组件。
在react-router4,官方推荐使用webpack的bundle-loader进行按需加载。
bundle-loader原理
npm i --save bundle-loader
使用require("bundle-loader!./file.js")
来进行相应chunk的加载。该方法会返回一个function
,这个function
接受一个回调函数作为参数。
let chatChunk = require("bundle-loader?lazy!./components/chat");
chatChunk(function(file) {
someOperate(file);
});
和其他loader类似,Bundle Loader也需要在webpack的配置文件中进行相应配置。Bundle-Loader的代码也很简短,如果阅读一下可以发现,其实际上也是使用require.ensure()
来实现的,通过给Bundle-Loader返回的函数中传入相应的模块处理回调函数即可在require.ensure()
的中处理,代码最后也列出了相应的输出格式:
/*
Output format:
var cbs = [],
data;
module.exports = function(cb) {
if(cbs) cbs.push(cb);
else cb(data);
}
require.ensure([], function(require) {
data = require("xxx");
var callbacks = cbs;
cbs = null;
for(var i = 0, l = callbacks.length; i < l; i++) {
callbacks[i](data);
}
});
*/
react-router v4 中的代码拆分
首先需要一个异步加载的包装组件Bundle。Bundle的主要功能就是接收一个组件异步加载的方法,并返回相应的react组件:
export default class Bundle extends Component {
constructor(props) {
super(props);
this.state = {
mod: null
};
}
componentWillMount() {
this.load(this.props)
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps)
}
}
load(props) {
this.setState({
mod: null
});
props.load((mod) => {
this.setState({
mod: mod.default ? mod.default : mod
});
});
}
render() {
return this.state.mod ? this.props.children(this.state.mod) : null;
}
}
通过Bundle Loader来引入模块:
import loadSomething from 'bundle-loader?lazy!./About'
const About = (props) => (
<Bundle load={loadAbout}>
{(About) => <About {...props}/>}
</Bundle>
)