美文网首页React Native
使用react-router做延迟加载路由配置

使用react-router做延迟加载路由配置

作者: 张培_ | 来源:发表于2017-12-16 20:43 被阅读415次

    情景描述

    • 客户要求我们首次打开页面的时候必须在1s之内
    • 可是项目很大,首页加载模块体积大首屏加载时间长
    • 为了解决这个问题项目中使用按需加载路由配置这种方式
    • 将router写成了如下的样子
    import {AppContainer} from 'containers'
    
    export const routes = {
    const errorLoading = _ => _ // console.error('Dynamic loading failed' + err)
    
    const loadRoute = cb =>
      module => cb(null, module.default)
    
    
    export const routes = {
      component: AppContainer,
      path: '/',
      indexRoute: {
        getComponent(location, callback) {
          import('./containers/User/LandingPageContainer')
            .then((module) => {
              callback(null, module.default)
            })
            .catch(err => errorLoading(err))
        }
      },
      childRoutes: [
        {
          path: '/admin',
          getChildRoutes(partialNextState, callback) {
            import('./containers/Admin/routes')
              .then(loadRoute(callback))
              .catch(err => errorLoading(err))
          },
          onEnter: checkInvalidRoleAndRedirect
        },
        {
          path: '/wms/create',
          getComponent(nextState, callback) {
            import('./containers/WMS/CreateOrderContainer')
              .then(loadRoute(callback))
              .catch(err => errorLoading(err))
          }
        }
      ]
    }
    
    • 导致我完全不能明白。。。。

    解释

    • Q1:这种写法和以前的使用标签区别是啥呢?
    <BrowserRouter>
          <Route path="/tacos" component={Tacos}/>
        </div>
    </BrowserRouter>
    
    • A1:区别:

      • 使用标签的写法webpack会把所有的文件全部打包在一个main.*****.js文件,也就是说这时候庞大的项目中所有js代码全部都被打包到一个js文件中。会造成的问题
        • 当用户请求首页,首页的代码以及项目中所有的代码全部都在main.****.js文件中。
        • 为了将首页render出来,必须将这个非常大的js文件请求回来
        • 因此非常耗时
      • 使用项目中的写法
        • webpack会通过import()这个方法作为code spliting的分割点,然后将庞大的项目根据分割点分成若干的chunk.js文件。
        • 然后当你访问首页的时候
        • 我们只需要请求首页的chunk.js文件即可
        • 这时候每次请求的内容大大减少,时间就会减小
    • Q2: 按需加载又是什么样的概念呢?

    • A2: 按需加载很好理解,需要什么加载什么,问题在于如何保证你需要的都能加载进来,你不需要的都不加载进来呢?重点在于我们通过webpack将文件打包成静态文件,部署到服务器,要做到按需加载(按需请求),就必须要求webpack做到合适的分隔项目并且将他们打包到不同的文件(chunk文件中)所以要实现好的按需加载必须要要求webpack能够做好将不同的代码打包到不同的文件。


    • Q3:那么webpack又是如何分割项目并打包到不同的文件中呢?
    • A3:webpack提供了code splitting特性,此特性能够把代码分离到不同的bundle文件实现按需加载。在webpack的官网介绍了三种实现code splitting,采用动态导入的方式,结合es6提出的import(和promise)作为code splitting分割点,将不同本部分分别打包在不同的chunk文件中。
      • ps:webpack主要有两种代码分割的分割点选择方式:
        • 1.import
        • 2.require.ensure

    • Q4:import是什么和我们之前的模块引入使用import不是一个东西吗?
    • A4:两种import分别是同步和异步加载模块(也可以看做静态和动态的引入模块),两种引入方式的最大区别在:
      • import App from './component/app':编译时加载模块,因此必须写在每个模块的最上方,写在编译时候不会执行的地方就会失效(比如写在if里面),只能做静态引入不能做动态引入
      • import('./component/app').then((module)=>{console.log('this is dynamic import module',module.default)}).catch(err=> 'dynamic import failed'):是运行时加载模块(和require一样),所以只有import()和require能够做到动态引入
        • require和import之间的区别又是什么呢?
          • require:是同步的
          • import:返回的是promise是异步的

    • Q5:那么使用webpack做按需加载需要配置什么吗? 代码中又要做什么样的改变呢?
    • A5:改变需要分成两个部分:
      • webpack配置上的改变:配置需要做的改变基本没有,顶多就是配置一下chunk文件的名字
      ```js
      entry: {
          chunkFilename: '[name].[chunkhash:5].chunk.js',
          //给生成的chunk文件确定命名规范,name在没有设置的时候默认使用id
          //chunkhash:5 5位hash码
      
      }
      - 代码上的改变:这里主要针对react实现按需加载,如果想要对react实现按需加载,那么就需要webpack和react-router之间的配合。so react-router实现按需加载该怎么配置(主要分成两个部分):
      - 实现组件的按需引入:react-router提供了方法代替相应属性实现对相应路由组件的异步挂载
        - getComponent: 代替Route标签的component实现当访问到当前路径的时候再执行该方法加载组件
          - 参数有两个
            - location:是一个对象包含当前的所有路由中能获取的信息
            - callback:回调函数,用于异步引入组件成功后调用
              - 参数有两个: 
                - error(如果没有error这个参数在调用的时候写成null,如果不写成null,那么在当前路由下就会报出Require.ensure error的错误)
                - 组件:请注意如果你是用的是import引入组件那么promise返回的数据应该是整个module对象,而不是你的组件
                  - 如果在module使用default暴露:那么callback的第二参数必须是module.default
                  - 如果在module中使用export const a、export const那么第二个参数必须是module.a或者module.b
        - getChildRoutes:代替某个Route的子组件实现异步加载child组件(大有作用!! 下一篇简书介绍)
        - getIndexRoute: 但是实践过后发现使用失败不知道为什么,所以换成了`indexRoute: { getComponent()}`
      - 写明code splitting的分割点:之前提到过有两种分割方式
        - 使用webpack 提供的require.ensure实现:用这个方法定义分割点独立打包chunk
        - 使用es6的动态import实现:参数是引入module的地址   方法返回promise 回调函数的参数中包含module
      ```js
        import AppContainer from './components/AppContainer'
        import LandingPageContainer from './containers/User/LandingPageContainer'
        import CreateOrderContainer from './containers/WMS/CreateOrderContainer'
        <Router>
           <Route path='/' component={AppContainer}>
             <IndexRoute component={LandingPageContainer} />
             <Route path='/wms/creat' component={CreateOrderContainer} />
           </Route>
        </Router>
        //原来的写法  所有的组件都是静态引入,也就意味这在编译的时候就必须将所有引入的文件(也就是项目中所有的组件)打包在一个js文件中,当浏览器没有缓存的时候,第一次请求就要把一个很大的js文件请求回来
        
      

    • Q6:那么对于第三方模块如何实现性能的提升呢?
    • A6: 采用将所有的第三方库的全部都打包到一个js文件,原因:
      - 由于这一部分内容不怎么需要变化,所以打包好之后就放在一个js文件中不动了
      - 这样既有利于缓存而且不需要重复打包。
      - 但是剥离第三方库主要对于开发的时候会加快打包速度
      - 可以使用commonChunkPlugin来实现

    相关文章

      网友评论

        本文标题:使用react-router做延迟加载路由配置

        本文链接:https://www.haomeiwen.com/subject/okdewxtx.html