使用react-router做延迟加载路由配置
2017-12-16 本文已影响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文件即可
- 这时候每次请求的内容大大减少,时间就会减小
- webpack会通过
- 使用标签的写法webpack会把所有的文件全部打包在一个main.*****.js文件,也就是说这时候庞大的项目中所有js代码全部都被打包到一个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
- ps:webpack主要有两种代码分割的分割点选择方式:
- 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是异步的
- require和import之间的区别又是什么呢?
-
- 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来实现