详解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 相关文章推荐
Javascript下的keyCode键码值表
Apr 10 Javascript
jQuery创建自己的插件(自定义插件)的方法
Jun 10 Javascript
jquery 操作iframe的几种方法总结
Dec 13 Javascript
textarea不能通过maxlength属性来限制字数的解决方法
Sep 01 Javascript
JS控制弹出新页面窗口位置和大小的方法
Mar 02 Javascript
JavaScript DSL 流畅接口(使用链式调用)实例
Mar 15 Javascript
JavaScript中的函数声明和函数表达式区别浅析
Mar 27 Javascript
深入理解基于vue-cli的vuex配置
Jul 24 Javascript
使用travis-ci如何持续部署node.js应用详解
Jul 30 Javascript
详解vue移动端项目代码拆分记录
Mar 15 Javascript
vue动态绘制四分之三圆环图效果
Sep 03 Javascript
JavaScript实现简单图片切换
Apr 29 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
咖啡知识大全
2021/03/03 新手入门
php上传图片存入数据库示例分享
2014/03/11 PHP
thinkPHP中配置的读取与C方法详解
2016/12/05 PHP
php表单处理操作
2017/11/16 PHP
laravel5.6实现数值转换
2019/10/23 PHP
JavaScript脚本语言在网页中的简单应用
2007/05/13 Javascript
通过js动态操作table(新增,删除相关列信息)
2012/05/23 Javascript
JQuery实现鼠标滚轮滑动到页面节点
2015/07/28 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之主动触发事件和模拟冒泡处理
2015/11/24 Javascript
JavaScript代码性能优化总结(推荐)
2016/05/16 Javascript
BootStrap Datepicker 插件修改为默认中文的实现方法
2017/02/10 Javascript
深入理解Vue 单向数据流的原理
2017/11/09 Javascript
JavaScript引用类型RegExp基本用法详解
2018/08/09 Javascript
Javascript 之封装(Package)
2018/09/14 Javascript
vue滚动固定顶部及修改样式的实例代码
2019/05/30 Javascript
Vue 列表上下过渡效果的实例代码
2019/06/25 Javascript
python测试驱动开发实例
2014/10/08 Python
bpython 功能强大的Python shell
2016/02/16 Python
Python的requests网络编程包使用教程
2016/07/11 Python
python中子类调用父类函数的方法示例
2017/08/18 Python
使用pandas将numpy中的数组数据保存到csv文件的方法
2018/06/14 Python
Python3 JSON编码解码方法详解
2019/09/06 Python
python打印异常信息的两种实现方式
2019/12/24 Python
Matplotlib绘制雷达图和三维图的示例代码
2020/01/07 Python
Python requests模块cookie实例解析
2020/04/14 Python
Python实现敏感词过滤的4种方法
2020/09/12 Python
PyCharm最新激活码(2020/10/27全网最新)
2020/10/27 Python
面向对象概念面试题(.NET)
2016/11/04 面试题
怀念母亲教学反思
2014/04/28 职场文书
大学生就业自我推荐信
2014/05/10 职场文书
2014年秋季开学典礼致辞
2014/08/02 职场文书
党员个人对照检查材料范文
2014/09/24 职场文书
党的群众路线教育实践活动教师自我剖析材料
2014/10/09 职场文书
单位病假条范文
2015/08/17 职场文书
2016年教师节贺卡寄语
2015/12/04 职场文书
Python find()、rfind()方法及作用
2022/12/24 Python