@@ -42,6 +42,8 @@ function Choo (opts) {
4242 this . _hasWindow = typeof window !== 'undefined'
4343 this . _createLocation = nanolocation
4444 this . _cache = opts . cache
45+ this . _asyncProxy = null // proxy for async routes
46+ this . _asyncRoutes = { }
4547 this . _loaded = false
4648 this . _stores = [ ]
4749 this . _tree = null
@@ -76,10 +78,66 @@ function Choo (opts) {
7678
7779Choo . prototype . route = function ( route , handler ) {
7880 assert . equal ( typeof route , 'string' , 'choo.route: route should be type string' )
79- assert . equal ( typeof handler , 'function' , 'choo.handler: route should be type function' )
81+ assert . equal ( typeof handler , 'function' , 'choo.route: handler should be type function' )
8082 this . router . on ( route , handler )
8183}
8284
85+ // Register a route to be loaded asynchronously.
86+ Choo . prototype . asyncRoute = function ( route , load ) {
87+ assert . equal ( typeof route , 'string' , 'choo.asyncRoute: asyncRoute should be type string' )
88+ assert . equal ( typeof handler , 'function' , 'choo.asyncRoute: route should be type function' )
89+
90+ var IDLE = 0
91+ var LOADING = 1
92+ var LOADED = 2
93+
94+ var loadingState = IDLE
95+ var renderRoute = null
96+ var view = null
97+ var self = this
98+
99+ this . route ( route , function ( state , emit ) {
100+ if ( ! self . _asyncProxy ) self . _initAsyncProxy ( )
101+ // Begin loading the bundle on the first call
102+ if ( loadingState === IDLE ) {
103+ emit ( 'choo:async-route-start' , state . route )
104+ renderRoute = state . route
105+ loadingState = LOADING
106+
107+ var p = load ( onload )
108+ assert ( p && p . then , 'choo.asyncRoute: async route should return a Promise' )
109+ p . then ( onload . bind ( null , null ) , onload )
110+ return self . _asyncProxy
111+ } else if ( loadingState === LOADING ) {
112+ return self . _asyncProxy
113+ } else {
114+ // loadingState === LOADED
115+ return view ( state , emit )
116+ }
117+
118+ function onload ( err , _view ) {
119+ if ( err ) {
120+ emit ( 'error' , err )
121+ loadingState = IDLE
122+ return
123+ }
124+
125+ emit ( 'choo:async-route-end' , renderRoute , _view )
126+ loadingState = LOADED
127+ view = _view
128+
129+ // Only rerender if we are still on the same route
130+ if ( state . route === renderRoute ) emit ( 'render' )
131+ }
132+ } )
133+ }
134+
135+ Choo . prototype . _initAsyncProxy = function ( ) {
136+ var tagName = this . _tree ? this . _tree . nodeName : 'body'
137+ this . _asyncProxy = document . createElement ( tagName )
138+ this . _asyncProxy . isSameNode = function ( ) { return true }
139+ }
140+
83141Choo . prototype . use = function ( cb ) {
84142 assert . equal ( typeof cb , 'function' , 'choo.use: cb should be type function' )
85143 var self = this
0 commit comments