详解webpack + react + react-router 如何实现懒加载


Posted in Javascript onNovember 20, 2017

在 Webpack 1 中主要是由bundle-loader进行懒加载,而 Webpack 2 中引入了类似于 SystemJS 的System.import语法,首先我们对于System.import的执行流程进行简单阐述:

  1. Webpack 会在编译过程中扫描代码库时将发现的System.import调用引入的文件及其相关依赖进行单独打包,注意,Webpack 会保证这些独立模块及其依赖不会与主应用的包体相冲突。
  2. 当我们访问到这些独立打包的组件模块时,Webpack 会发起 JSONP 请求来抓取相关的包体。
  3. System.import 同样也是 Promise,在请求完成之后System.import会将抓取到的模块作为参数传入then中的回调函数。
  4. 如果我们重复访问已经加载完毕的模块,Webpack 不会重复执行抓取与解析的过程。

而 React Router 路由的懒加载实际上分为动态路由与与懒加载两步,典型的所谓动态路由配置如下:

/**
 * <Route path="/" component={Core}>
 *  <IndexRoute component={Home}/>
 *  <Route path="about" component={About}/>
 *  <Route path="users" component={Users}>
 *  <Route path="*" component={Home}/>
 * </Route>
 */
export default {
 path: '/', 
 component: Core,
 indexRoute: { 
  getComponent(location, cb) {
    ...
  },
 },
 childRoutes: [
  {
   path: 'about', 
   getComponent(location, cb) {
    ...
   },
  },
  {
   path: 'users', 
   getComponent(location, cb) {
    ...
   },
  },
  {
   path: '*', 
   getComponent(location, cb) {
    ...
   },
  },
 ],
};

正常打包

import IndexPage from './views/app.jsx'
import AboutPage from './views/about.jsx'
export default function({history}) {
  return (
    <Router history={history}>
      <Route path="/" component={IndexPage} />
      <Route path="/about" component={AboutPage} />
    </Router>
  )
}

这是一个正常打包的路由写法, 如果需要分割代码, 我们需要改造下路由, 借助getComponent和require.ensure

webpack 代码分割

export default function({history}) {
  return (
    <Router history={history}>
      <Route path="/" getComponent={(location, callback) => {
        require.ensure([], function(require) {
          callback(null, require('./HomePage.jsx'))
        })
      }} />
      <Route path="/about" getComponent={(location, callback) => {
        require.ensure([], function(require) {
          callback(null, require('./AboutPage.jsx'))
        })
      }} />
    </Router>
  )
}

这样看来代码有点累, 我们稍微改造下

const home = (location, callback) => {
 require.ensure([], require => {
  callback(null, require('./HomePage.jsx'))
 }, 'home')
}

const about = (location, callback) => {
 require.ensure([], require => {
  callback(null, require('./AboutPage.jsx'))
 }, 'about')
}
export default function({history}) {
  return (
    <Router history={history}>
      <Route path="/" getComponent={home}></Route>
      <Route path="/about" getComponent={about}></Route>
    </Router>
  )
}

这样看起来是不是简洁了很多

注意: 由于webpack的原因, 如果直接require('./AboutPage.jsx')不能正常加载, 请尝试require('./AboutPage.jsx').default

webpack2 代码分割

上面的代码看起来好像都是webpack1的写法, 那么webpack2呢?

webpac2就需要借助System.import了

export default function({history}) {
  return (
    <Router history={history}>
      <Route path="/" getComponent={(location, callback) => {
        System.import('./HomePage.jsx').then(component => {
          callback(null, component.default || component)
        })
      }} />
      <Route path="/about" getComponent={(location, callback) => {
        System.import('./AboutPage.jsx').then(component => {
          callback(null, component.default || component)
        })
      }} />
    </Router>
  )
}

我们一样可以把上面的代码优化一下

const home = (location, callback) => {
  System.import('./HomePage.jsx').then(component => {
    callback(null, component.default || component)
  })
}
const about = (location, callback) => {
  System.import('./AboutPage.jsx').then(component => {
    callback(null, component.default || component)
  })
}

export default ({ history }) => {
  return (
    <Router history={history}>
      <Route name="home" path="/" getComponent={home} />
      <Route name="about" path="/about" getComponent={about} />
    </Router>
  )
}

webpack2 + dva 实现路由和 models 懒加载

const routerThen = (app, callback, [component, model]) => {
  app.model(model.default || model)
  callback(null, component.default || component)
}

export default ({ history, app }) => {
  return (
    <Router history={history}>
      <Route name="home" path="/" getComponent={(location, callback) => {
        Promise.all([
          System.import('./views/app.jsx'),
          System.import('./models/topics')
        ]).then(routerThen.bind(null, app, callback))
      }} />
      <Route name="article" path="/article/:id" getComponent={(location, callback) => {
        Promise.all([
          System.import('./views/article.jsx'),
          System.import('./models/topic')
        ]).then(routerThen.bind(null, app, callback))
      }} />
    </Router>
  )
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
extjs form textfield的隐藏方法
Dec 29 Javascript
jQuery实现平滑滚动的标签分栏切换效果
Aug 28 Javascript
jquery判断当前浏览器的实现代码
Nov 07 Javascript
Javascript基础知识盲点总结之函数
May 15 Javascript
AngularJS实现按钮提示与点击变色效果
Sep 07 Javascript
Boostrap实现的登录界面实例代码
Oct 09 Javascript
javascript 实现文本使用省略号替代(超出固定高度的情况)
Feb 21 Javascript
js鼠标经过tab选项卡时实现切换延迟
Mar 24 Javascript
JS使用插件cryptojs进行加密解密数据实例
May 11 Javascript
JavaScript闭包与作用域链实例分析
Jan 21 Javascript
Vue 实现手动刷新组件的方法
Feb 19 Javascript
react同构实践之实现自己的同构模板
Mar 13 Javascript
详细分析jsonp的原理和实现方式
Nov 20 #Javascript
three.js中文文档学习之通过模块导入
Nov 20 #Javascript
JS写XSS cookie stealer来窃取密码的步骤详解
Nov 20 #Javascript
浅谈Vue SSR 的 Cookies 问题
Nov 20 #Javascript
three.js中文文档学习之创建场景
Nov 20 #Javascript
Vue 中批量下载文件并打包的示例代码
Nov 20 #Javascript
VueJs 搭建Axios接口请求工具
Nov 20 #Javascript
You might like
PHP新手上路(二)
2006/10/09 PHP
第二章 PHP入门基础之php代码写法
2011/12/30 PHP
PHP获取youku视频真实flv文件地址的方法
2014/12/23 PHP
ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解
2019/04/02 PHP
JQuery在页面中添加和除移DOM示例代码
2013/06/24 Javascript
JQEasy-ui在IE9以下版本中二次加载的问题分析及处理方法
2014/06/23 Javascript
JavaScript返回0-1之间随机数的方法
2015/04/06 Javascript
跟我学习javascript解决异步编程异常方案
2015/11/23 Javascript
JavaScript文本框脚本编写的注意事项
2016/01/25 Javascript
JS实现页面载入时随机显示图片效果
2016/09/07 Javascript
详解Node.js 命令行程序开发教程
2017/06/07 Javascript
JavaScript实现图片切换效果
2017/08/12 Javascript
小程序获取周围IBeacon设备的方法
2018/10/31 Javascript
Element图表初始大小及窗口自适应实现
2020/07/10 Javascript
vue2和vue3的v-if与v-for优先级对比学习
2020/10/10 Javascript
Python的Flask框架中实现登录用户的个人资料和头像的教程
2015/04/20 Python
分享一下Python 开发者节省时间的10个方法
2015/10/02 Python
pandas把dataframe转成Series,改变列中值的类型方法
2018/04/10 Python
使用pandas的DataFrame的plot方法绘制图像的实例
2018/05/24 Python
在PyCharm中实现关闭一个死循环程序的方法
2018/11/29 Python
详解python中递归函数
2019/04/16 Python
python3读取图片并灰度化图片的四种方法(OpenCV、PIL.Image、TensorFlow方法)总结
2019/07/04 Python
python打印直角三角形与等腰三角形实例代码
2019/10/20 Python
如何通过python计算圆周率PI
2020/11/11 Python
施华洛世奇美国官网:SWAROVSKI美国
2018/02/08 全球购物
美丽的现代设计家具:2Modern
2018/07/26 全球购物
C语言基础笔试题
2013/04/27 面试题
平面设计自荐信
2013/10/07 职场文书
应届生财务管理求职信
2013/11/06 职场文书
学生会干部自荐信
2014/02/04 职场文书
情人节寄语大全
2014/04/11 职场文书
旅行社优秀创业计划书
2014/08/16 职场文书
科技活动总结范文
2015/05/11 职场文书
2016毕业实习单位评语大全
2015/12/01 职场文书
《彼得与狼》教学反思
2016/02/20 职场文书
Vue ECharts实现机舱座位选择展示功能
2022/05/15 Vue.js