系统运维

基于Webpack 2的React组件懒加载

时间:2010-12-5 17:23:32  作者:人工智能   来源:系统运维  查看:  评论:0
内容摘要:Chunks是Webpack的基本概念之一,最直观的概念是在多入口配置中,诶个单独的入口会生成单独的Chunk。而在添加额外的插件配置之后,Webpack会输出譬如独立的CSS包体这样独立的块。Web

Chunks是基于件懒加载Webpack的基本概念之一,最直观的基于件懒加载概念是在多入口配置中,诶个单独的基于件懒加载入口会生成单独的Chunk。而在添加额外的基于件懒加载插件配置之后,Webpack会输出譬如独立的基于件懒加载CSS包体这样独立的块。Webpack内置有如三种类型的基于件懒加载Chunk:

Entry Chunks:Entry Chunks是我们最常见的Chunks类型,包含了应用所需要的基于件懒加载Webpack运行时与即刻加载的模块。 Normal Chunks:Normal Chunks并不会包含Webpack运行时,基于件懒加载主要指代那些应用运行时动态加载的基于件懒加载模块,Webpack会为我们创建类似于JSONP这样合适的香港云服务器基于件懒加载加载器来进行动态加载。 Initial Chunks:Initial Chunks本质上还是基于件懒加载Normal Chunks,不过其会在应用初始化时完成加载,基于件懒加载往往这个类型的基于件懒加载Chunks由CommonsChunkPlugin生成。

bundle-loader

bundle-loader是基于件懒加载Webpack官方出品的Loader之一,bundle-loader可以用来加载异步代码块,基于件懒加载基本的用法如下:

// 当请求某个Bundle时,Webpack会为我们自动加载 var waitForChunk = require("bundle-loader!./file.js"); //我们需要等待Chunk加载完成才能获取到文件详情 waitForChunk(function(file) {      // use file like is was required with     // var file = require("./file.js"); }); // wraps the require in a require.ensure block 

我们同样可以自定义Chunk名:

require("bundle-loader?lazy&name=my-chunk!./file.js"); 

我们可以很方便地利用bundle-loader实现React Router中模块的懒加载,譬如如果我们的路由设置如下:

import HomePage from "./pages/HomePage"; import AdminPage from "./pages/admin/AdminPage"; import AdminPageSettings from "./pages/admin/AdminPageSettings"; export default function routes(fromServer) {    return (     <Router history={ browserHistory}>       <Route path="/" component={ HomePage}/>       <Route path="/admin" component={ AdminPage}/>       <Route path="/admin/settings" component={ AdminSettingsPage}/>     <Router/>   ) } 

其中AdminPage可能非常笨重,我们希望只有当用户真实请求到/admin这个地址时才会加载相关组件,此时我们就可以在Webpack配置中添加bundle-loader的支持:

{  ... module: {    loaders: [{      // use `test` to split a single file     // or `include` to split a whole folder     test: /.*/,     include: [path.resolve(__dirname, pages/admin)],     loader: bundle?lazy&name=admin    }] } ... } 

该配置会自动帮我们从主文件中移除admin相关的组件代码,然后将其移动到1.admin.js文件中,然后在React Router中,我们同样需要冲定义组件加载函数:

import HomePage from "./pages/HomePage"; import AdminPage from "./pages/admin/AdminPage"; import AdminPageSettings from "./pages/admin/AdminPageSettings"; const isReactComponent = (obj) => Boolean(obj && obj.prototype && Boolean(obj.prototype.isReactComponent)); const component = (component) => {    return isReactComponent(component)     ? { component}     : { getComponent: (loc, cb)=> component(          comp=> cb(null, comp.default || comp))} }; export default function routes(fromServer) {    return (     <Router history={ browserHistory}>       <Route path="/" { ...component(HomePage)}/>       <Route path="/admin" { ...component(AdminPage)}/>       <Route path="/admin/settings"                         { ...component(AdminSettingsPage)}/>     <Router/>   ) } 

React 懒加载组件封装

Lazy Loading - React

有时候我们需要将某个厚重的组件设置为异步加载,云服务器这里我们将常见的懒加载操作封装为某个组件及其高阶组件接口,源代码参考LazilyLoad:

import React from react; /**  * @function 支持异步加载的封装组件  */ class LazilyLoad extends React.Component {    constructor() {      super(...arguments);     this.state = {        isLoaded: false,     };   }   componentWillMount() {      this.load(this.props);   }   componentDidMount() {      this._isMounted = true;   }   componentWillReceiveProps(next) {      if (next.modules === this.props.modules) return null;     this.load(next);   }   componentWillUnmount() {      this._isMounted = false;   }   load(props) {      this.setState({        isLoaded: false,     });     const { modules} = props;     const keys = Object.keys(modules);     Promise.all(keys.map((key) => modules[key]()))       .then((values) => (keys.reduce((agg, key, index) => {          agg[key] = values[index];         return agg;       }, { })))       .then((result) => {          if (!this._isMounted) return null;         this.setState({ modules: result, isLoaded: true});       });   }   render() {      if (!this.state.isLoaded) return null;     return React.Children.only(this.props.children(this.state.modules));   } } LazilyLoad.propTypes = {    children: React.PropTypes.func.isRequired, }; export const LazilyLoadFactory = (Component, modules) => {    return (props) => (     <LazilyLoad modules={ modules}>       { (mods) => <Component { ...mods} { ...props} />}     </LazilyLoad>   ); }; export const importLazy = (promise) => (   promise.then((result) => result.default) ); export default LazilyLoad; 

回调方式懒加载

这里我们使用类似于bundle-loader中的回调方式进行懒加载,不过将其封装为了组件形式。其中的importLazy主要是为了兼容Babel/ES2015,其只是单纯的返回默认属性值,实例代码参考这里。

render(){      return ...         <LazilyLoad modules={ {            LoadedLate: () => importLazy(System.import(../lazy/loaded_late.js))         }}>           {              ({ LoadedLate}) => {                return <LoadedLate />             }           }         </LazilyLoad>    ... } 

高阶组件方式懒加载

在入门介绍中我们讲过可以利用external属性来配置引入jQuery,而这里我们也可以使用高阶组件方式进行异步加载:

// @flow import React, {  Component, PropTypes } from react; import {  LazilyLoadFactory } from ../../../common/utils/load/lazily_load; /**  * 组件LoadedJquery  */ export default class LoadedJQuery extends Component {    /**    * @function 默认渲染函数    */   render() {      return (       <div         ref={ (ref) => this.props.$(ref).css(background-color, red)}>         jQuery加载完毕       </div>     );   } } export default LazilyLoadFactory(   LoadedJQuery,   {      $: () => System.import(jquery),   } ); 

这里我们将加载完毕的jQuery作为组件的Props参数传入到组件中使用,同样我们也可以使用这种方式加载我们自定义的函数或者组件。上述两种的效果如下所示:

【本文是专栏作者“张梓雄 ”的原创文章,如需转载请通过与作者联系】

戳这里,服务器托管看该作者更多好文

copyright © 2025 powered by 益强资讯全景  滇ICP备2023006006号-31sitemap