详解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 TextArea动态显示剩余字符
Oct 22 Javascript
在JS中最常看到切最容易迷惑的语法(转)
Oct 29 Javascript
jquery live()调用不存在的解决方法
Feb 26 Javascript
javascript内置对象操作详解
Feb 04 Javascript
基于javascript实现图片预加载
Jan 05 Javascript
JS模拟简易滚动条效果代码(附demo源码)
Apr 05 Javascript
阿里云ecs服务器中安装部署node.js的步骤
Oct 08 Javascript
微信小程序 时间格式化(util.formatTime(new Date))详解
Nov 16 Javascript
Vue.2.0.5实现Class 与 Style 绑定的实例
Jun 20 Javascript
从源码看angular/material2 中 dialog模块的实现方法
Oct 18 Javascript
Bootstrap实现下拉菜单多级联动
Nov 23 Javascript
深入浅出webpack之externals的使用
Dec 04 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
兼容ie6浏览器的php下载文件代码分享
2014/07/14 PHP
Laravel框架在本地虚拟机快速安装的方法详解
2018/06/11 PHP
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
2015/03/14 Javascript
javascript基于prototype实现类似OOP继承的方法
2015/12/16 Javascript
JQuery 传送中文乱码问题的简单解决办法
2016/05/24 Javascript
再谈Javascript中的基本类型和引用类型(推荐)
2016/07/01 Javascript
浅谈JS中的三种字符串连接方式及其性能比较
2016/09/02 Javascript
jQuery插件easyUI实现通过JS显示Dialog的方法
2016/09/16 Javascript
通过JS获取Request.QueryString()参数的值实现方法
2016/09/27 Javascript
Input文本框随着输入内容多少自动延伸的实现
2017/02/15 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
2017/08/14 Javascript
EL表达式截取字符串的函数说明
2017/09/22 Javascript
angular4应用中输入的最小值和最大值的方法
2019/05/17 Javascript
通过js给网页加上水印背景实例
2019/06/17 Javascript
vue + typescript + 极验登录验证的实现方法
2019/06/27 Javascript
three.js利用gpu选取物体并计算交点位置的方法示例
2019/11/25 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
jQuery实现查看图片功能
2020/12/01 jQuery
Nodejs 数组的队列以及forEach的应用详解
2021/02/25 NodeJs
python控制台显示时钟的示例
2014/02/24 Python
Python 实现简单的shell sed替换功能(实例讲解)
2017/09/29 Python
Python多线程threading和multiprocessing模块实例解析
2018/01/29 Python
从0开始的Python学习016异常
2019/04/08 Python
Jacobi迭代算法的Python实现详解
2019/06/29 Python
python调试神器PySnooper的使用
2019/07/03 Python
python读取当前目录下的CSV文件数据
2020/03/11 Python
介绍一下sql server的安全性
2014/08/10 面试题
实习会计求职自荐信范文
2014/03/10 职场文书
运动会方队口号
2014/06/07 职场文书
收银员岗位职责范本
2015/04/07 职场文书
2015年小学数学教师工作总结
2015/05/20 职场文书
人民调解协议书
2016/03/21 职场文书
详解Html5项目适配系统深色模式方案总结
2021/04/14 HTML / CSS
微软Win11有哪些隐藏功能? windows11多个功能汇总
2021/11/21 数码科技
用Python可视化新冠疫情数据
2022/01/18 Python
正则表达式拆分url实例代码
2022/02/24 Java/Android