Skip to content

Instantly share code, notes, and snippets.

@faceyspacey
Last active March 13, 2019 05:13
Show Gist options
  • Save faceyspacey/be2ea05eb69de705f9da61c6b236f08a to your computer and use it in GitHub Desktop.
Save faceyspacey/be2ea05eb69de705f9da61c6b236f08a to your computer and use it in GitHub Desktop.
Rudy custom code-splitting middleware (split reducers, components, routes, libs)
// implementation 1
const load = (api) => async (req, next) => {
const { route, action } = req
const hasLoad = route && route.load
if (!hasLoad) return next()
const { components, reducers, chunks, ...res } = await route.load(req) || {}
if (hasChunks(req.ctx, chunks)) return next()
if (reducers) {
req.options.replaceReducer(reducers)
if (req.tmp.committed) {
req.commitDispatch(req.action) // double commit so reducer is up to date
// but what about reducer receiving potential _COMPLETE action?? -- autoDispatch middleware only does it after both complete
}
}
if (components) {
if (!req.tmp.committed) {
const currentComponents = req.getLocation().components
req.action.components = { ...currentComponents, ...components }
}
else {
req.commitDispatch({ type 'LOAD', payload: { components } })
}
}
if (isServer()) {
req.ctx.chunks.push(...chunks)
}
Object.assign(route, res)
return next()
}
}
// implementation 2
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
export default (name = 'load') => (api) => async (req, next) => {
const load = req.route && req.route[name]
if (load) { // if `route.load` does not exist short-circuit
const parts = await load(req)
addPartsToRuntime(req, parts)
}
return next()
}
const addPartsToRuntime = (req, parts) => {
const { route, action, options, tmp, ctx, commitDispatch } = req
const { components, reducers, chunk, ...rest } = parts
if (ctx.chunks.includes(chunk)) return // chunk was already added to runtime, so short-circuit
if (reducers) {
// options.replaceReducer(reducers)
}
if (components) {
req.location.components = components
action.components = components // we need to modify `createReducer` to store `state.location.components` so after load they can be dynamically rendered within existing components!
}
if (tmp.committed && (components || reducers)) { // if the route change action has already been dispatched, we need to re-dispatch it again, so the new goodies are received
action.force = true // we need a flag to force this action through, so component are added to state or new reducers receive action -- the `force` flag doesn't already exist, it's a placeholder for something we can already use to force the action passed the `isDoubleDispatch` check; we may have some other piece of infrastructure that precludes needing to create a new custom flag
commitDispatch(action)
}
Object.assign(route, rest) // rest allows you to tack on additional thunks, sagas, etc, to your route object (optionally) -- i.e. you can build the "plane" (aka route) while flying
ctx.chunks.push(chunk)
}
// usage
const routes = {
CODESPLIT: {
path: '/split/:page',
load: ({ params }) => (typeof window === 'undefined') ? require.resolveWeak(`./components/${params.page}`) : import(`./components/${params.page}`)
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment