-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Simplify and modularize app/router initialization #10256
Changes from 4 commits
585a935
0320b5a
788580f
0941344
9c2b8d4
434e9cc
cf55da2
73d3ee0
496dfe7
a16adec
e929b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -253,6 +253,8 @@ var Application = Namespace.extend(DeferredMixin, { | |
customEvents: null, | ||
|
||
init: function() { | ||
this._super(); | ||
|
||
// Start off the number of deferrals at 1. This will be | ||
// decremented by the Application's own `initialize` method. | ||
this._readinessDeferrals = 1; | ||
|
@@ -261,42 +263,19 @@ var Application = Namespace.extend(DeferredMixin, { | |
this.$ = jQuery; | ||
} | ||
|
||
// Create subclass of Ember.Router for this Application instance. | ||
// This is to ensure that someone reopening `App.Router` does not | ||
// tamper with the default `Ember.Router`. | ||
this.Router = Router.extend(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we comment this as for global mode only, something we can shed in the future? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there, in general, a way for us to note code that likely can be removed in 2.0? /cc @rwjblue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe just |
||
this.buildRegistry(); | ||
this.buildContainer(); | ||
|
||
this.Router = this.defaultRouter(); | ||
// TODO:(tomdale+wycats) Move to session creation phase | ||
this.buildInstance(); | ||
|
||
this._super(); | ||
registerLibraries(); | ||
logLibraryVersions(); | ||
|
||
this.scheduleInitialize(); | ||
|
||
if (!librariesRegistered) { | ||
librariesRegistered = true; | ||
|
||
if (environment.hasDOM) { | ||
Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); | ||
} | ||
} | ||
|
||
if (Ember.LOG_VERSION) { | ||
// we only need to see this once per Application#init | ||
Ember.LOG_VERSION = false; | ||
var libs = Ember.libraries._registry; | ||
|
||
var nameLengths = EnumerableUtils.map(libs, function(item) { | ||
return get(item, 'name.length'); | ||
}); | ||
|
||
var maxNameLength = Math.max.apply(this, nameLengths); | ||
|
||
Ember.debug('-------------------------------'); | ||
for (var i = 0, l = libs.length; i < l; i++) { | ||
var lib = libs[i]; | ||
var spaces = new Array(maxNameLength - lib.name.length + 1).join(' '); | ||
Ember.debug([lib.name, spaces, ' : ', lib.version].join('')); | ||
} | ||
Ember.debug('-------------------------------'); | ||
} | ||
}, | ||
|
||
/** | ||
|
@@ -316,46 +295,19 @@ var Application = Namespace.extend(DeferredMixin, { | |
Create a container for the current application's registry. | ||
|
||
@private | ||
@method buildContainer | ||
@method buildInstance | ||
@return {Ember.Container} the configured container | ||
*/ | ||
buildContainer: function() { | ||
buildInstance: function() { | ||
var container = this.__container__ = this.__registry__.container(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we maintain There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dgeb - There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, @wycats and I discussed this a bit and felt that, as much as this fact might pain us, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@rwjblue I wasn't suggesting this, but I'd recommend doing so IF
@tomdale Those are my thoughts as well. Perhaps tag it with the |
||
|
||
return container; | ||
}, | ||
|
||
/** | ||
If the application has not opted out of routing and has not explicitly | ||
defined a router, supply a default router for the application author | ||
to configure. | ||
|
||
This allows application developers to do: | ||
|
||
```javascript | ||
var App = Ember.Application.create(); | ||
|
||
App.Router.map(function() { | ||
this.resource('posts'); | ||
var instance = this.__instance__ = ApplicationInstance.create({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you say more what you mean? The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the container is created immediately before the application instance. The container is even passed to the application instance on create. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the bootstrap process should be to instantiate via the container. |
||
customEvents: get(this, 'customEvents'), | ||
rootElement: get(this, 'rootElement'), | ||
container: container | ||
}); | ||
``` | ||
|
||
@private | ||
@method defaultRouter | ||
@return {Ember.Router} the default router | ||
*/ | ||
|
||
defaultRouter: function() { | ||
if (this.Router === false) { return; } | ||
var container = this.__container__; | ||
var registry = this.__registry__; | ||
|
||
if (this.Router) { | ||
registry.unregister('router:main'); | ||
registry.register('router:main', this.Router); | ||
} | ||
|
||
return container.lookupFactory('router:main'); | ||
return instance; | ||
}, | ||
|
||
/** | ||
|
@@ -573,17 +525,6 @@ var Application = Namespace.extend(DeferredMixin, { | |
_initialize: function() { | ||
if (this.isDestroyed) { return; } | ||
|
||
// At this point, the App.Router must already be assigned | ||
if (this.Router) { | ||
var registry = this.__registry__; | ||
var container = this.__container__; | ||
|
||
registry.unregister('router:main'); | ||
registry.register('router:main', this.Router); | ||
|
||
container.reset('router:main'); | ||
} | ||
|
||
this.runInitializers(); | ||
runLoadHooks('application', this); | ||
|
||
|
@@ -664,15 +605,14 @@ var Application = Namespace.extend(DeferredMixin, { | |
@method reset | ||
**/ | ||
reset: function() { | ||
var instance = this.__instance__; | ||
|
||
this._readinessDeferrals = 1; | ||
|
||
function handleReset() { | ||
var router = this.__container__.lookup('router:main'); | ||
router.reset(); | ||
|
||
run(this.__container__, 'destroy'); | ||
run(instance, 'destroy'); | ||
|
||
this.buildContainer(); | ||
this.buildInstance(); | ||
|
||
run.schedule('actions', this, '_initialize'); | ||
} | ||
|
@@ -716,7 +656,7 @@ var Application = Namespace.extend(DeferredMixin, { | |
*/ | ||
didBecomeReady: function() { | ||
if (environment.hasDOM) { | ||
this.setupEventDispatcher(); | ||
this.__instance__.setupEventDispatcher(); | ||
} | ||
|
||
this.ready(); // user hook | ||
|
@@ -731,23 +671,6 @@ var Application = Namespace.extend(DeferredMixin, { | |
this.resolve(this); | ||
}, | ||
|
||
/** | ||
Setup up the event dispatcher to receive events on the | ||
application's `rootElement` with any registered | ||
`customEvents`. | ||
|
||
@private | ||
@method setupEventDispatcher | ||
*/ | ||
setupEventDispatcher: function() { | ||
var customEvents = get(this, 'customEvents'); | ||
var rootElement = get(this, 'rootElement'); | ||
var dispatcher = this.__container__.lookup('event_dispatcher:main'); | ||
|
||
set(this, 'eventDispatcher', dispatcher); | ||
dispatcher.setup(customEvents, rootElement); | ||
}, | ||
|
||
/** | ||
If the application has a router, use it to route to the current URL, and | ||
trigger a new call to `route` whenever the URL changes. | ||
|
@@ -757,18 +680,12 @@ var Application = Namespace.extend(DeferredMixin, { | |
@property router {Ember.Router} | ||
*/ | ||
startRouting: function() { | ||
var router = this.__container__.lookup('router:main'); | ||
if (!router) { return; } | ||
|
||
var moduleBasedResolver = this.Resolver && this.Resolver.moduleBasedResolver; | ||
|
||
router.startRouting(moduleBasedResolver); | ||
var isModuleBasedResolver = this.Resolver && this.Resolver.moduleBasedResolver; | ||
this.__instance__.startRouting(isModuleBasedResolver); | ||
}, | ||
|
||
handleURL: function(url) { | ||
var router = this.__container__.lookup('router:main'); | ||
|
||
router.handleURL(url); | ||
return this.__instance__.handleURL(url); | ||
}, | ||
|
||
/** | ||
|
@@ -795,12 +712,10 @@ var Application = Namespace.extend(DeferredMixin, { | |
*/ | ||
Resolver: null, | ||
|
||
// This method must be moved to the application instance object | ||
willDestroy: function() { | ||
Ember.BOOTED = false; | ||
// Ensure deactivation of routes before objects are destroyed | ||
this.__container__.lookup('router:main').reset(); | ||
|
||
this.__container__.destroy(); | ||
this.__instance__.destroy(); | ||
}, | ||
|
||
initializer: function(options) { | ||
|
@@ -1016,7 +931,6 @@ Application.reopenClass({ | |
registry.register('route:basic', Route, { instantiate: false }); | ||
registry.register('event_dispatcher:main', EventDispatcher); | ||
|
||
registry.register('router:main', Router); | ||
registry.injection('router:main', 'namespace', 'application:main'); | ||
|
||
registry.register('location:auto', AutoLocation); | ||
|
@@ -1097,4 +1011,67 @@ function resolverFor(namespace) { | |
return resolve; | ||
} | ||
|
||
function registerLibraries() { | ||
if (!librariesRegistered) { | ||
librariesRegistered = true; | ||
|
||
if (environment.hasDOM) { | ||
Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); | ||
} | ||
} | ||
} | ||
|
||
function logLibraryVersions() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we are refactoring, it might be better to declare these as var logLibraryVersions;
// later
Ember.runInDebug(function(){
logLibraryVersions = function(){
};
});
// init Function
Ember.runInDebug(function(){
logLibraryVersions();
}); and use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fivetanley - I agree in principle, but having There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am happy to do whatever here, we just extracted these as-is to make the |
||
if (Ember.LOG_VERSION) { | ||
// we only need to see this once per Application#init | ||
Ember.LOG_VERSION = false; | ||
var libs = Ember.libraries._registry; | ||
|
||
var nameLengths = EnumerableUtils.map(libs, function(item) { | ||
return get(item, 'name.length'); | ||
}); | ||
|
||
var maxNameLength = Math.max.apply(this, nameLengths); | ||
|
||
Ember.debug('-------------------------------'); | ||
for (var i = 0, l = libs.length; i < l; i++) { | ||
var lib = libs[i]; | ||
var spaces = new Array(maxNameLength - lib.name.length + 1).join(' '); | ||
Ember.debug([lib.name, spaces, ' : ', lib.version].join('')); | ||
} | ||
Ember.debug('-------------------------------'); | ||
} | ||
} | ||
|
||
var ApplicationInstance = Ember.Object.extend({ | ||
container: null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason why these 3 properties exist? Or are they for future documentation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean? They are used in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. they are provided to the constructor, why do we need to specify them on the prototype? |
||
customEvents: null, | ||
rootElement: null, | ||
|
||
startRouting: function(isModuleBasedResolver) { | ||
var router = this.container.lookup('router:main'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It shouldn't be possible to get to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the intent is only to guard against the calling if (container.has('router:main')) {
this.startRouting();
} |
||
if (!router) { return; } | ||
|
||
router.startRouting(isModuleBasedResolver); | ||
}, | ||
|
||
handleURL: function(url) { | ||
var router = this.container.lookup('router:main'); | ||
|
||
return router.handleURL(url); | ||
}, | ||
|
||
setupEventDispatcher: function() { | ||
var dispatcher = this.container.lookup('event_dispatcher:main'); | ||
|
||
dispatcher.setup(this.customEvents, this.rootElement); | ||
|
||
return dispatcher; | ||
}, | ||
|
||
willDestroy: function() { | ||
run(this.container, 'destroy'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just preserving semantics you introduced in 9c83112. We specifically were trying to hew to existing behavior as much as possible without doing a more in-depth refactoring. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tomdale and that used join. The above will nest a run loop. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, if memory serves we did want a nested loop here. SG |
||
} | ||
}); | ||
|
||
export default Application; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -169,16 +169,15 @@ export default EmberObject.extend({ | |
resolved = this[resolveMethodName](parsedName); | ||
} | ||
|
||
if (!resolved) { | ||
resolved = this.resolveOther(parsedName); | ||
} | ||
resolved = resolved || this.resolveOther(parsedName); | ||
|
||
if (parsedName.root && parsedName.root.LOG_RESOLVER) { | ||
this._logLookup(resolved, parsedName); | ||
} | ||
|
||
return resolved; | ||
}, | ||
|
||
/** | ||
Convert the string name of the form 'type:name' to | ||
a Javascript object with the parsed aspects of the name | ||
|
@@ -214,13 +213,15 @@ export default EmberObject.extend({ | |
' namespace, but the namespace could not be found', root); | ||
} | ||
|
||
var resolveMethodName = fullNameWithoutType === 'main' ? 'Main' : classify(type); | ||
|
||
return { | ||
fullName: fullName, | ||
type: type, | ||
fullNameWithoutType: fullNameWithoutType, | ||
name: name, | ||
root: root, | ||
resolveMethodName: 'resolve' + classify(type) | ||
resolveMethodName: 'resolve' + resolveMethodName | ||
}; | ||
}, | ||
|
||
|
@@ -253,6 +254,7 @@ export default EmberObject.extend({ | |
makeToString: function(factory, fullName) { | ||
return factory.toString(); | ||
}, | ||
|
||
/** | ||
Given a parseName object (output from `parseName`), apply | ||
the conventions expected by `Ember.Router` | ||
|
@@ -368,6 +370,11 @@ export default EmberObject.extend({ | |
if (factory) { return factory; } | ||
}, | ||
|
||
resolveMain: function(parsedName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add doc to this new method and annotate it public/private |
||
var className = classify(parsedName.type); | ||
return get(parsedName.root, className); | ||
}, | ||
|
||
/** | ||
@method _logLookup | ||
@param {Boolean} found | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -297,6 +297,10 @@ var EmberRouter = EmberObject.extend(Evented, { | |
} | ||
}, | ||
|
||
willDestroy: function() { | ||
this.reset(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
|
||
_lookupActiveView: function(templateName) { | ||
var active = this._activeViews[templateName]; | ||
return active && active[0]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this._super.apply(this, arguments);