详解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 相关文章推荐
js 跨域和ajax 跨域问题小结
Jul 01 Javascript
某页码显示的helper 少量调整,另附js版
Sep 12 Javascript
javascript:history.go()和History.back()的区别及应用
Nov 25 Javascript
jQuery自定义添加&quot;$&quot;与解决&quot;$&quot;冲突的方法
Jan 19 Javascript
跟我学习javascript的最新标准ES6
Nov 20 Javascript
javascript中json对象json数组json字符串互转及取值方法
Apr 19 Javascript
Bootstrap 表单验证formValidation 实现远程验证功能
May 17 Javascript
Vue v2.5 调整和更新不完全问题
Oct 24 Javascript
使用 vue.js 构建大型单页应用
Feb 10 Javascript
webpack4.x下babel的安装、配置及使用详解
Mar 07 Javascript
vue双向绑定及观察者模式详解
Mar 19 Javascript
Vue组件间通信 Vuex的用法解析
Aug 05 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
echo, print, printf 和 sprintf 区别
2006/12/06 PHP
PHP实现对文件锁进行加锁、解锁操作的方法
2017/07/04 PHP
php使用redis的几种常见操作方式和用法示例
2020/02/20 PHP
一段利用WSH修改和查看IP配置的代码
2008/05/11 Javascript
Javascript读取cookie函数代码
2010/10/16 Javascript
Wordpress ThickBox 点击图片显示下一张图的修改方法
2010/12/11 Javascript
jquery插件制作 自增长输入框实现代码
2012/08/17 jQuery
JavaScript四种调用模式和this示例介绍
2014/01/02 Javascript
30个经典的jQuery代码开发技巧
2014/12/15 Javascript
Jquery中Event对象属性小结
2015/02/27 Javascript
jQuery简单实现禁用右键菜单
2015/03/10 Javascript
JavaScript转换二进制编码为ASCII码的方法
2015/04/16 Javascript
AngularJS Ajax详解及示例代码
2016/08/17 Javascript
JS实用的带停顿的逐行文本循环滚动效果实例
2016/11/23 Javascript
JQuery Dialog对话框 不能通过Esc关闭的原因分析及解决办法
2017/01/18 Javascript
使用Vue如何写一个双向数据绑定(面试常见)
2018/04/20 Javascript
基于Vue 服务端Cookies删除的问题
2018/09/21 Javascript
layui 数据表格复选框实现单选功能的例子
2019/09/19 Javascript
Python 对输入的数字进行排序的方法
2018/06/23 Python
Python切片操作深入详解
2018/07/27 Python
Django用户认证系统 组与权限解析
2019/08/02 Python
numpy:np.newaxis 实现将行向量转换成列向量
2019/11/30 Python
使用tensorflow显示pb模型的所有网络结点方式
2020/01/23 Python
Python通过2种方法输出带颜色字体
2020/03/02 Python
移动端rem布局的两种实现方法
2018/01/03 HTML / CSS
html5教程制作简单画板代码分享
2013/12/04 HTML / CSS
美国优质宠物用品购买网站:Muttropolis
2020/02/17 全球购物
周年庆典邀请函范文
2014/01/23 职场文书
小学庆六一活动方案
2014/02/28 职场文书
水电站项目建议书
2014/05/12 职场文书
专题组织生活会方案
2014/06/15 职场文书
党的群众路线教育实践活动个人自我剖析材料
2014/10/07 职场文书
2015年世界水日活动总结
2015/02/09 职场文书
工伤调解协议书
2016/03/21 职场文书
Django程序的优化技巧
2021/04/29 Python
pytest实现多进程与多线程运行超好用的插件
2022/07/15 Python