Jan 2018
I'm building an online booking system for barbers. 99% of the site's visitors are people wanting to book a haircut; they only need a few screens to do this. The final 1% are the barbers, who require many more screens/modules to manage their account, services, timetables etc.
Rather than declaring (and hence importing) all of our Routes
upfront, we instead only decalre what Routes
the user needs. We determine if the visitor needs the staff routes by using the alanning/roles
package, to see if they are staff.
If they are staff, then the extra Routes
are asynchronously loaded.
Below is a simplified version of my code-split app:
import _ from 'lodash'; | |
import React from 'react'; | |
import { Roles } from 'meteor/alanning:roles'; | |
import { Route, Switch } from 'react-router-dom'; | |
import Login from '../../screens/Login/Login'; | |
import Home from '../../screens/Home/Home'; | |
import Booking from '../../screens/Booking/Booking'; | |
const staffRoles = ['admin', 'super-admin', 'staff']; | |
class App extends React.PureComponent { | |
constructor(props) { | |
super(props); | |
this.state = { routes: this.clientRoutes() }; | |
this.buildRoutes = this.buildRoutes.bind(this); | |
} | |
componentDidMount() { | |
this.buildRoutes(this.props); | |
} | |
componentWillReceiveProps(nextProps) { | |
this.buildRoutes(nextProps); | |
} | |
clientRoutes() { | |
return [ | |
<Route exact path="/" component={Home} key="c1"/>, | |
<Route exact path="/booking" component={Booking} key="c2"/>, | |
<Route path="/admin" component={Login} key="c3" />, | |
]; | |
} | |
async buildRoutes(props) { | |
/* | |
// Here we dynamically import the staff routes | |
// This means that customers don't need to download any of the modules required for staff pages. | |
*/ | |
const { user } = props; | |
if (_.isEmpty(user) || !Roles.userIsInRole(user._id, staffRoles, props.organisation.securityGroup)) { | |
this.setState({ routes: this.clientRoutes() }); | |
} else { | |
const StaffRoutes = await import('./StaffRoutes'); | |
const staffRoutes = StaffRoutes.Generate(props); | |
this.setState({ routes: [...staffRoutes, ...this.clientRoutes()] }); | |
} | |
} | |
render() { | |
const { routes } = this.state; | |
return ( | |
<Switch> | |
{routes} | |
</Switch> | |
); | |
} | |
} | |
App.propTypes = ({ | |
user: PropTypes.object, | |
}); | |
App.defaultProps = ({ | |
user: null, | |
}); | |
export default App; |
import React from 'react'; | |
import { Route } from 'react-router-dom'; | |
import InitialSetup from '../../screens/InitialSetup/InitialSetup'; | |
import Staff from '../../screens/Staff/Staff'; | |
export const Generate = (props) => { | |
return [ | |
<Route path="/admin/initial-setup" component={InitialSetup} {...props} key="s1" />, | |
<Route path="/admin/staff" component={Staff} {...props} key="s2" />, | |
]; | |
}; |