QubitProducts / cherrytree

A flexible nested router.
MIT License
108 stars 20 forks source link

Add routes dinamically. Is it possible? #134

Closed blikblum closed 8 years ago

blikblum commented 8 years ago

React Router allows to create routes dinamically, i.e., it allows a route to configure and load the child routes only when its first matched

Is it possible with cherrytree?. Looked at the docs and do not found how to do that.

KidkArolis commented 8 years ago

It's not currently possible to extend route configuration itself dynamically. But in practise it might not be a problem. As long as you define the route map upfront, you can then still dynamically load parts of your app. We do this in production. For example:

// app.js
let cherrytree = require('cherrytree')
let resolvers = require('./routing/resolvers')
let loadCode = require('./routing/loadCode')

let router = cherrytree()
router.use(loadCode)
router.map(function (route) {
  route('application', { resolver: resolvers.application }, function () {
    route('logout')
    route('list', { resolver: resolvers.list }, function () {
      route('list.tab')
    })
    route('item', { resolver: resolvers.item }, function () {
      route('item.details')
    })
  })
})
// routing/resolvers.js
let resolvers = {}

resolvers.application = function (name, cb) {
  require.ensure([], function (require) {
    cb(require('app/modules/application/routes')[name])
  }, 'list-routes')
}

resolvers.list = function (name, cb) {
  require.ensure([], function (require) {
    cb(require('app/modules/list/routes')[name])
  }, 'list-routes')
}

resolvers.item = function (name, cb) {
  require.ensure([], function (require) {
    cb(require('app/modules/item/routes')[name])
  }, 'item-routes')
}
// app/modules/item/routes.js
module.exports = {
  'item': require('./itemComponent'),
  'item.details': require('./itemDetailsComponent')
}
// routing/loadCode.js
let when = require('when')

module.exports = function loadCode (transition) {
  return when.map(transition.routes, function (memo, route) {
    return resolve(route, transition.routes).then(function (Component) {
      route.component = Component
    })
  })
}

function resolve (route, routes) {
  let r = route
  while (r) {
    if (r.options.resolver) {
      // this route has a resolver configured
      return when.promise(resolve => r.options.resolver(name, resolve))
    } else {
      // walk up to the parent routes to find a resolver
      r = routes[routes.indexOf(r) - 1]
    }
  }
  throw new Error('Couldn\'t find a route resolver for ' + route.name)
}

And now webpack would build list page routes and item page routes into separate bundles and cherrytree would load those bundles dynamically as part of transitioning to those pages.

I'll have to take a closer look at react-router's API for this as they seem to have less boilerplate.

blikblum commented 8 years ago

Many thanks for your work. I think this library has a right balance between functionality, flexibility and size. Just wanted to know if the feature is already available but is not a deal breaker. Closing the issue