基于vue和react的spa进行按需加载的实现方法
基于vue和react的spa进行按需加载
由于最近打算将所有的管理系统采用同一套登陆方法,然后在登陆后进行系统的切换选择,不需要每个系统都去重新登陆一次,所以前端这边思考将所有的系统用一套spa的应用进行构建,但是各个系统的合并之后,打包后的代码应该是相当大的,单页需要一次性加载所有系统的资源,显得不合实际,所以打算将不同系统的资源进行分离,再选择后在加载该系统的相应资源。自己发现这个业务和每个系统的路由比较类似,因此将系统的配置基于vue-router或者react-router的基础进行按需加载处理。因此自己了解了一下按需加载的应用和配置方案。
基于该业务大家有其他解决方案欢迎交流( _O_ )
按需加载
随着单页应用的发展,整个系统的所有功能都集合在一个页面,该页面一次性加载所有的资源,随着系统的不断扩展,因此所加载的资源会不断的增大,虽然经过压缩处理,大大的减小了资源的内容量,但是不能从本质上减小资源内容的增多。
其实我们的模块对应不同的资源,就类似之前所做的多页系统,不同的页面加载对应的资源文件,所以可以参考之前的的多页系统的做法,在单页系统中根据不同的模块加载其对应的资源文件。就是用户当前需要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载。
如何按需加载
在单页应用做按需加载,一般采用以下原则
- 把整个系统划分成一个个小功能,再按照功能的相关程度划分为几类。
- 把每一类合并为一个Chunk,按需加载对应的Chunk
- 对于首屏看到的内容直接放到入口Chunk中,以降低网页首次加载资源的个数
- 对于其他的模块可以做按需加载。
被分割出去的代码的加载需要一定的机制去触发,也就是当用户即将操作到对应的功能时再去加载。被分割出去的代码的加载时机需要开发者根据自己系统的需求去衡量确定。
因为被分割出去的代码加载也需要一定的时间,所以可以提前做预加载处理。
import()
在开始下面的案例之前先了解一下import(),这里的import()不同于引入模块的import xxx from 'xxx',这里的import是指一个动态加载模块的函数,传入的参数就是相应的模块,但是import()会返回一个Promise对象,因此可以在import()完成后根据其状态进行处理。
//eg import('/component/details').then(mod=>{ console.log(mod) },error=>{ console.log(error) })
vue按需加载的应用
1.模块分割
根据自己系统的情况,个人根据vue-router的模块来进行分割,
//roter配置的分割代码 import Vue from 'vue' import Router from 'vue-router' const listnav=()=> import('@/components/listnav') const adminav=()=> import('@/components/adminav') Vue.use(Router) const router = new Router({ routes:[{ path:'/listnav', name:'listnav', component:listnav }, { path:'/adminav', name:'adminav', component:adminav } ] }) export default router
2.webpack输出文件配置
//webpack.base.conf.js moudle.exports = { entry:{ app:'./src/main.js' }, output:{ path:"../dist", filename:'js/[name].js', chunkFilename:'js/[name].js' } }
react按需加载应用
1,模块分割
同样模块分割可采用react-router进行划分
//router配置分割代码 import React, {PureComponent, Component ,createElement} from 'react'; import {HashRouter as Router, Route,Link,withRouter} from 'react-router-dom'; import Home from "../component/home" function getAsyncComponent(load) { return class AsyncComponent extends PureComponent { constructor(props) { super(props); } componentDidMount() { // 在高阶组件 DidMount 时才去执行网络加载步骤 load().then(({default: component}) => { // 代码加载成功,获取到了代码导出的值,调用 setState 通知高阶组件重新渲染子组件 this.setState({ component, }) }); } render() { const {component} = this.state || {}; // component 是 React.Component 类型,需要通过 React.createElement 生产一个组件实例 return component ? createElement(component) : null; } } } const Routes = () =>( <HashRouter> <Route path="/home/:test" exact component={Home}/> <Route path='/details/:id' component={getAsyncComponent( // 异步加载函数,异步地加载 details组件 () => import('../component/details') )}/> </HashRouter> ) export default Routers;
2.webpack输出文件配置
//webpack.base.config.js module.exports = { entry:{ main: "../src/index.js", //入口文件 }, output:{ path:"../dist",//出口文件 filename:"js/[name].js", chunkFilename:"js/[name].js", publicPath: '' } }
3.按需加载组件中的props传递
在按需加载划分后,按需加载的组件不能接收到传递来的props,因此不能通过this.props.match.params来获取router配置时所带入的参数。
解决方法利用react-router中的withRouter
可以在按需加载的组件中进行配置处理
//component/details.js import React, { Component } from 'react'; import {withRouter} from 'react-router-dom'; class Details extends Component { constructor(props) { super(props); } render() { console.log(this.props) return ( <div></div> ) } } export default withRouter(Details);
参考链接
vue-router路由懒加载 [ https://router.vuejs.org/zh/guide/advanced/lazy-loading.html]
React按需加载[ http://webpack.wuhaolin.cn/4%E4%BC%98%E5%8C%96/4-12%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD.html]
总结