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

Public Router service MVP #14805

Merged
merged 1 commit into from
Jan 20, 2017
Merged

Public Router service MVP #14805

merged 1 commit into from
Jan 20, 2017

Conversation

scalvert
Copy link
Contributor

@scalvert scalvert commented Jan 9, 2017

This PR represents the MVP of the public router service described in this RFC. It incorporates work done by @locks in this PR.

It includes a minimal API:

  • currentRouteName
  • currentURL
  • location
  • rootURL
  • transitionTo

Status: Work in progress

Reviewers: @locks @rwjblue @ef4

Changes:

  • Added ember-routing-router-service feature flag
  • Added new router service and minimal API as described above
  • Added deprecation warning for use of private router service when feature enabled
  • Tests in progress

How to test drive this PR:

  • yarn start
  • Open up 2 tabs pointing to http://localhost:4200/tests/index.html, one with Enable Opt Features checked, ensure tests pass

TODO:
Write tests for

  • currentRouteName
  • currentURL
  • location
  • rootURL
  • transitionTo

RFC Implementation Phases

  1. MVP for public router service with minimal API
  2. Extended API, building on the work in phase 1
  3. Implementation of urlFor, ensuring correct performance profile
  4. Implementation of RouteInfo and associated API

urlFor() {
let router = get(this, 'router');

return router.generate(...arguments);
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this still take the slow path with the QPs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question. Will verify.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing until we verify the implementation details.

Copy link
Contributor

@krisselden krisselden left a comment

Choose a reason for hiding this comment

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

Any API that doesn't meet the RFC here https://github.com/emberjs/rfcs/blob/master/text/0095-router-service.md#query-parameter-semantics shouldn't be included until it does.

@homu
Copy link
Contributor

homu commented Jan 9, 2017

☔ The latest upstream changes (presumably #14806) made this pull request unmergeable. Please resolve the merge conflicts.

@locks locks requested review from rwjblue and ef4 January 9, 2017 22:59
@locks locks mentioned this pull request Jan 9, 2017
@scalvert
Copy link
Contributor Author

Added tests for currentRouteName.

@scalvert
Copy link
Contributor Author

@krisselden I've stripped the urlFor implementation out of this review. We can work out how to proceed in a subsequent review.

@@ -34,6 +34,8 @@ import ApplicationInstance from './application-instance';
import { privatize as P } from 'container';
import Engine from './engine';
import { setupApplicationRegistry } from 'ember-glimmer';
import RouterService from 'ember-routing/services/router';
import isEnabled from 'ember-metal/features';
Copy link
Member

Choose a reason for hiding this comment

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

import { isFeatureEnabled } from 'ember-metal';

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -34,6 +34,8 @@ import ApplicationInstance from './application-instance';
import { privatize as P } from 'container';
import Engine from './engine';
import { setupApplicationRegistry } from 'ember-glimmer';
import RouterService from 'ember-routing/services/router';
Copy link
Member

Choose a reason for hiding this comment

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

import { RouterService } from 'ember-routing';

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@submodule ember-routing
*/

import Service from 'ember-runtime/system/service';
Copy link
Member

Choose a reason for hiding this comment

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

Imports should be from the entry points (e.g. from 'ember-runtime'; instead of from 'ember-runtime/somethign';)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

containing a mapping of query parameters
@return {Transition} the transition object associated with this
attempted transition
@public
Copy link
Member

Choose a reason for hiding this comment

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

We should add @category ember-routing-router-service so that the YUIDoc will be able to remove these until the feature is enabled

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@public
*/
transitionTo() {
let router = get(this, 'router');
Copy link
Member

Choose a reason for hiding this comment

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

Since this is injected we should be able to swap this to just this.router here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

get
} from 'ember-metal';
import { jQuery } from 'ember-views';
import { inject } from 'ember-runtime';
Copy link
Member

Choose a reason for hiding this comment

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

Group with the ember-runtime import above...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

import { inject } from 'ember-runtime';
import { ApplicationTestCase, moduleFor } from 'internal-test-helpers';

import isEnabled from 'ember-metal/features';
Copy link
Member

Choose a reason for hiding this comment

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

import { isFeatureEnabled } from 'ember-metal';

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

this.registerRoute('parent', Route.extend({
router: inject.service(),
init() {
routerService = get(this, 'router');
Copy link
Member

Choose a reason for hiding this comment

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

we should call _super before this here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done for all inits.

return this.visit('/child').then(() => {
assert.equal(routerService.get('currentRouteName'), 'parent.child');

return this.visit('/sister').then(() => {
Copy link
Member

Choose a reason for hiding this comment

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

return this.visit('/child').then(() => {
  return this.visit('/sister');
}).then(() => {
  assert.equal(routerService.get('currentRouteName'), 'parent.sister');

  return this.visit('/brother');
}).then(() => {
  assert.equal(routerService.get('currentRouteName'), 'parent.brother');
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

currentRouteName: readOnly('router.currentRouteName'),
currentURL: readOnly('router.location.path'),
location: readOnly('router.location'),
rootUrL: readOnly('router.rootURL'),
Copy link
Member

Choose a reason for hiding this comment

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

Correct the casing here (I think it should be rootURL)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

import { get } from 'ember-metal';
import RouterDSL from '../system/dsl';

/*
Copy link
Contributor

Choose a reason for hiding this comment

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

The docstrings don't seem to match out usual style, see Router for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll update.

@krisselden
Copy link
Contributor

I'd love @ef4 review to see if there is any concern about the timing of when these properties update as compared to the RFC, I know that the RFC was a chance to improve the router not just give it a prettier API.

Copy link
Member

@rwjblue rwjblue left a comment

Choose a reason for hiding this comment

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

This is looking really good! I'm glad you got to the bottom of that currentURL async issue we chatted about. 👏

I think the only real thing missing here at this point are some tests for .transitionTo, .rootURL, and .location properties.

Service,
readOnly
} from 'ember-runtime';
import { get, descriptor } from 'ember-metal';
Copy link
Member

Choose a reason for hiding this comment

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

Descriptor seems unused

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll remove it. Thanks!

@@ -629,6 +633,7 @@ const EmberRouter = EmberObject.extend(Evented, {

let doUpdateURL = function() {
location.setURL(lastURL);
set(emberRouter, 'currentURL', lastURL);
Copy link
Member

Choose a reason for hiding this comment

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

I think we should actually do this in the router.updateURL and router.replaceURL methods directly above the run.once(doUpdateURL) bit...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can do that. My thought was I wanted to keep both set calls in the same place, but these methods are so closely related that it's find either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, so it turns out that setting this after a scheduled call is what's fixing this issue. So, it looks like I have to leave it where it is.


set(router, 'currentPath', path);
set(router, 'currentRouteName', currentRouteName);
set(router, 'currentURL', currentURL);
Copy link
Member

Choose a reason for hiding this comment

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

I would think this change is not needed since we are setting router.currentURL above in the changes to _setupRouter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought this too, initially. It turns out that there's a different codepath whether you're visiting vs. transitioning, and we need this update to occur in both places. I think this surfaces part of @krisselden's concerns, where we want to take advantage, while we have the engine out on the floor, to refactor this to make it cleaner and more consistent.

access to the router.

@public
@class RouterService
Copy link
Member

Choose a reason for hiding this comment

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

Should add the @category ember-routing-router-service flag here too (so that while the feature is pending it isn't listed in emberjs.com/api).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@scalvert
Copy link
Contributor Author

@rwjblue thanks for the additional comments. I'm adding tests for the outstanding properties/method now - mainly taking it slow so I make sure I cover high value test cases.

@scalvert
Copy link
Contributor Author

@krisselden I appreciate you wanting to make sure we're focussing on the right things with this PR, in terms of the opportunity to improve the router in general. This intent of this particular PR is to get a useful public API for the router in the hands of devs sooner rather than later. This will help provide immediate value, but does not preclude us circling back and refactoring parts of the internals later. In fact, that's our direct intention. We wanted to try to restrict these changes to simple, surface level changes before we get into the more meaty implementation, specifically the refactoring to use RouteInfo. Does this make sense to you?

I'll update the PR's description above to indicate the 4 phases, as discussed by @rwjblue and I.

@workmanw
Copy link

This is super exciting. Thank you for taking this on and helping driving it home.

One additional thing I'd really like to see fall into one of the later phases is some mechanism for components to subscribe to willTransition and didTransition. We use that kind of thing so often in our app to prevent transitioning when data is dirty. I know the RFC talks about providing new hooks to do that and that might mean willTransition and didTransition have to wait until that part is flushed out. I just don't want to see these guys forgotten about.

return this.visit('/').then(() => {
let location = routerService.get('location');
assert.ok(location);
assert.ok(location instanceof Ember.NoneLocation);
Copy link
Member

Choose a reason for hiding this comment

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

This should be imported from ember-routing/locations/none (using global Ember within Ember or the test suite isn't allowed). This is currently causing the linting tests to fail...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh weird. I didn't see that failure. Will fix right now!

routerService: inject.service('router'),
init() {
this._super();
set(this.router, 'rootURL', '/test');
Copy link
Member

Choose a reason for hiding this comment

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

I have a slight preference to use something other than /test here (since when tests are running we are already in /tests path). It definitely doesn't matter for this test as written, but it would just make this a tad bit easier for my brain to parse 😝

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change to /brainparse immediately! :)


return this.visit('/').then(() => {
this.assertText('/');
});
Copy link
Member

Choose a reason for hiding this comment

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

Can you add an update and reset phase to this (kinda like the INUR stuff for the glimmer tests)?

I'm thinking something like:

.then(() => routerService.transitionTo('child'))
.then(() => this.assertText('/child'))
.then(() => routerService.transitionTo('/'))
.then(() => this.assertText('/'))

})
.then(() => {
this.assertText('/child');
});
Copy link
Member

Choose a reason for hiding this comment

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

Can you add the update and reset steps (similar to comment for test above)?

@scalvert scalvert changed the title [WIP] - Public Router service MVP Public Router service MVP Jan 20, 2017
@rwjblue rwjblue merged commit 9cbf9f3 into emberjs:master Jan 20, 2017
@nickiaconis
Copy link
Contributor

nickiaconis commented Jun 29, 2017

@workmanw The RFC introduces the routeWillChange and routeDidChange events in place of the willTransition and didTransition hooks/events, but I agree. I too would like to ensure they're on the roadmap.

@janmisek
Copy link

What about rest of features covered by RFC (RouteInfo, transition events ...) ? is there any subsequent issue to track it ?

@locks
Copy link
Contributor

locks commented May 14, 2018

@janmisek There is not.

@janmisek
Copy link

And are these features still planned for implementation ?

@ef4
Copy link
Contributor

ef4 commented May 16, 2018

Yes, the RFC is merged which means anyone can PR the features. I started on several of them but had to back off to clear some other blockers first.

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.

10 participants