Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate route matching from rendering #613

Merged

Conversation

marcbachmann
Copy link
Contributor

@marcbachmann marcbachmann commented Dec 27, 2017

This PR

Additionally to the changes I did in here I think we should

  • Define what's the responsiblity of nanorouter & wayfarer and how we could modularize it better
    (I guess this is done by now as nanorouter contains some electron-, and browser specific logic)
  • Deprecate curry support in nanorouter. People could just wrap their method by themselves

Please let me know what you think

  • Before merging this PR, we have to cleanup the nanorouter dependency.
  • We'll also need to rename some methods and expose the _handler differently on the state if we decide to go down this path. In case we want to be able to cancel a navigate event in the future, we could also make it more stateless and pass the new route as object to the navigate events instead of modifying the state.

index.js Outdated
this.state.query = nanoquery(location)
var html = this.router(location)
var href = location.replace(/\?.+$/, '')
this._matchRoute(href, location)
Copy link
Contributor Author

@marcbachmann marcbachmann Dec 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move this into the pushState/popState/replaceState methods.
But there might be other side effects if we do that.

e.g.

var route = this._matchRoute(href)
self.emitter.emit(self._events.NAVIGATE, route)

or this (if we keep the mutation of state)

this._matchRoute(href)
self.emitter.emit(self._events.NAVIGATE)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should leave this the way it is for this PR, and consider the changes in a seperate PR? That might keep the changes nicely contained, and easier to follow along.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I completely agree here. This definitely needs more elaboration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question here was whether we should prevent _matchRoute from mutating the state. It should only return the new params and mutate the state after the NAVIGATE event got triggered.
This would allow us to keep the current state but already pass route params to some function to preload something.

This could end up in something similar to the angular resolve object where it's possible to preload some resources based on route params. In there we could also cancel the route change if a resolve gets rejected.
Maybe this would make everything more complicated. I'll think about it and will create a new issue if I think it's a good idea in the longer term. Here's a link to the resolve reference documentation in case you don't know it:
https://angular.io/api/router/Resolve

And a few more readable examples:
https://www.codementor.io/max_diachenko/angular-2-route-resolves--typescript-du1089pdm
https://medium.com/@dazcyril/resolving-data-in-angular-2-4-and-5-refactoring-components-and-moving-to-ngrx-store-15e15d8be3dd#9968

Copy link
Member

@yoshuawuyts yoshuawuyts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! Yeah, also all for deprecating the curry statement in nanorouter.

@marcbachmann
Copy link
Contributor Author

btw. Don't merge just yet 😉

index.js Outdated

Choo.prototype._prerender = function (state) {
var routeTiming = nanotiming("choo.prerender('" + state.route + "')")
var res = state._handler(state, this.emitter.emit.bind(this.emitter))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we cache that this.emitter.emit.bind(this.emitter) variable somewhere? e.g. in the Choo constructor?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that'd be great!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly as choo.emit? Then we would have choo.emitter and choo.emit.

@marcbachmann marcbachmann force-pushed the separate-route-matching-from-rendering branch 2 times, most recently from 993867a to 049d57e Compare January 2, 2018 16:26
@marcbachmann
Copy link
Contributor Author

marcbachmann commented Jan 2, 2018

This is ready now for another review. We could wait for some hours until choojs/nanorouter#13 is merged. With that we would have a simplified nanorouter module by removing the curry option.

I'd also consider renaming the new methods to make the code more readable. Better names for the prerender method might be generateDomTree or toDomTree but that might be confusing if the server side function calls that and returns a string instead. So maybe generateView suits our use-case better.

Let me also know if you want to make the _prerender and _matchroute methods private.
Other modules like nanolocation are also exposed but I don't know for what reason ... maybe it's just a preference to keep the code simple. 🤷‍♂️

For the _prerender case we could use something like that:

@@ -189,7 +189,7 @@ Choo.prototype.toString = function (location, state) {

   var href = location.replace(/\?.+$/, '')
   this._matchRoute(href, location)
-  var html = this._prerender(this.state)
+  var html = prerender(this.state, this.emit)
   assert.ok(html, 'choo.toString: no valid value returned for the route ' + location)
   return html.toString()
 }
@@ -206,9 +206,9 @@ Choo.prototype._matchRoute = function (location, queryString) {
   return this.state
 }

-Choo.prototype._prerender = function (state, emit) {
+function prerender (choo, state) {
   var routeTiming = nanotiming("choo.prerender('" + state.route + "')")
-  var res = state._handler(state, this.emit)
+  var res = state._handler(state, emit)
   routeTiming()
   return res
 }

index.js Outdated

Choo.prototype._matchRoute = function (location, queryString) {
if (location === undefined) location = this._createLocation()
if (queryString === undefined) queryString = window.location.search
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to myself: I shoud add a comment about that queryString is only used in the browser.
Or even move it up to the function call... depending how we'd like to handle it in #609

@johanalkstal
Copy link

I'm really eager to get this released! :D
Without this it's hard to redirect to other routes based on where the user is trying to go (prevent user from going to routes they should not have access to).

@marcbachmann
Copy link
Contributor Author

Nanorouter just got published. So this could land soon in master
...after updating to nanorouter@3.0.0

- This fixes choojs#530
- Adds support for wayfarer/nanorouter subrouters
@marcbachmann marcbachmann force-pushed the separate-route-matching-from-rendering branch from 049d57e to 9aa1015 Compare January 15, 2018 18:42
@marcbachmann
Copy link
Contributor Author

marcbachmann commented Jan 15, 2018

@yoshuawuyts this is ready to merge.
We should also tackle some tests soon.

Copy link
Member

@yoshuawuyts yoshuawuyts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rad!

@yoshuawuyts
Copy link
Member

How should we publish this? Semver... minor, right?

@bates64
Copy link
Contributor

bates64 commented Jan 16, 2018

@yoshuawuyts I'd argue major - this fixes #530, which is definitely not a backwards-compatible patch, as it changes behaviour that some apps may rely on...

Although, choo 7 has it's own goals and releasing that early won't be fun, so minor could work.

@marcbachmann
Copy link
Contributor Author

It could be a patch as it fixes only the state of the navigate event. The sub-route support is just a nice add-on.
Now because the state change happens earlier, this could break something in case somebody accesses some old state value in within the navigate event... just as @heyitsmeuralex mentioned.
But because most consumers saw that as bug, I'd do a patch or minor version.

So to sum up, there are the following changes in this PR:

@espy
Copy link

espy commented Jan 17, 2018

Sounds like it would also fix #463 😸

@yoshuawuyts yoshuawuyts merged commit cf8c316 into choojs:master Jan 17, 2018
@yoshuawuyts
Copy link
Member

yoshuawuyts commented Jan 17, 2018

Cool, going to release as minor then! - Seems reasonable given the conversation. It's always this weird situation where one person's bug is another person's feature.

@marcbachmann
Copy link
Contributor Author

❤️ Thanks 🎉

@marcbachmann marcbachmann deleted the separate-route-matching-from-rendering branch January 17, 2018 23:00
@yoshuawuyts
Copy link
Member

choo@6.7.0 🎉

@marcbachmann
Copy link
Contributor Author

For future reference and people who still want to access the old state within the navigate method,
please use choo.emitter.prependListener('navigate', func) instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

State out of date when switching routes
5 participants