Defining routes nested more than two levels deep or even just providing a callback does not work MU applications and triggers the error below.
requirejs.js:74 Uncaught TypeError: Cannot read property 'defaultType' of undefined
at RequireJSRegistry._checkDefaultType (requirejs.js:74)
at RequireJSRegistry._detectModule (requirejs.js:63)
at RequireJSRegistry.has (requirejs.js:85)
at Resolver._serializeAndVerify (resolver.js:118)
at Resolver.identify (resolver.js:94)
at Resolver.resolve (resolver.js:104)
at Class.resolve (index.js:149)
at Class.resolve (index.js:15)
at Class.superWrapper [as resolve] (utils.js:308)
at _resolve (container.js:807)
Exemplary failing router:
Router.map(function() {
// this fails
this.route('foo', function() {
this.route('bar', function() {
// You don't even need to register a third-level route. Just providing the
// callback triggers the error, likely because of the implicit `index` route.
// this.route('qux');
});
});
// this works just fine
this.route('one', function() {
this.route('two');
});
});
Reproduction repo: https://github.com/buschtoens/mu-nested-routes
The problem seems to be somewhere in glimmer-resolver/resolver.ts#identify. Routes generate non-sensical specifiers with an IMO incorrect rootName property:
{
type: "route",
name: "index",
namespace: undefined,
collection: "routes",
rootName: "foo/bar"
}
I _think_ it should rather look like this:
{
type: "route",
name: "foo/bar/index",
collection: "routes",
rootName: "mu-nested-routes"
}
Or maybe?
{
type: "route",
name: "index",
namespace: "foo/bar",
collection: "routes",
rootName: "mu-nested-routes"
}
I assume the glimmer-wrapper in ember-resolver is the correct place to submit a failing test case to.
@buschtoens have you tried the fallback resolver?
the fallback resolver is currently what https://emberclear.io uses
@NullVoxPopuli I am already using the fallback resolver, as can be seen here. But that is actually a very good point to make. I'll give the glimmer-wrapper a try instead. Thanks a lot!
@NullVoxPopuli No luck here. Apparently fallback and glimmer-wrapper use the same buggy code paths.
fallback first tries the glimmer-wrapper resolver, and if that one cannot find a result, will fall back to the classic resolver:
excellent! (one less thing to fix)
Ha! I just found out that this only happens, if the third-level Route or Controller are auto-generated. If the app actually provides a route.js and controller.js, there's no error. I've updated the reproduction repo to show this as well.
I think I've pinned down the issue. So in L90 s looks like this:
{
type: "controller",
name: "index",
namespace: "foo/bar",
collection: "routes",
rootName: "dummy"
}
The resolver cannot find the Controller, as it is not explicitly defined and thus should be auto-generated. But before resorting to auto-generation, the resolver tries as to find a fitting addon first in L92-L100.
s then looks like this:
{
type: "controller",
name: "index",
namespace: undefined,
collection: "routes",
rootName: "foo/bar"
}
This is then serialized as controller:/foo/bar/routes/index in _serializeAndVerify by serializeSpecifier. It is then deserialized in has as:
{
type: "controller",
name: "index",
namespace: "routes",
collection: "bar",
rootName: "foo"
}
Notice how this differs from the prior specifier:
{
type: "controller",
name: "index",
- namespace: undefined,
+ namespace: "routes",
- collection: "routes",
+ collection: "bar",
- rootName: "foo/bar"
+ rootName: "foo"
}
What ultimately causes the TypeError then is that that _checkDefaultType expects the specified collection to always exist:
_checkDefaultType(specifier) {
let {defaultType} = this._config.collections[specifier.collection];
return defaultType && defaultType === specifier.type;
}
A simple fix to make this safer would be:
_checkDefaultType(specifier) {
let { defaultType } = this._config.collections[specifier.collection] || {};
return defaultType && defaultType === specifier.type;
}
However this does not fix the inconsistent de-/serialization. But is this actually a problem we need to worry about? The input specifier already looks off to me.
In any case, I'll prep a PR for the above fix and test it.
This can be marked as closed 馃槂 Maybe cut a release for ember-resolver that contains the fix (it's already on master)
Closing, thanks!
Most helpful comment
I think I've pinned down the issue. So in L90
slooks like this:The resolver cannot find the
Controller, as it is not explicitly defined and thus should be auto-generated. But before resorting to auto-generation, the resolver tries as to find a fitting addon first inL92-L100.sthen looks like this:This is then serialized as
controller:/foo/bar/routes/indexin_serializeAndVerifybyserializeSpecifier. It is then deserialized inhasas:Notice how this differs from the prior specifier:
What ultimately causes the
TypeErrorthen is that that_checkDefaultTypeexpects the specified collection to always exist:A simple fix to make this safer would be:
However this does not fix the inconsistent de-/serialization. But is this actually a problem we need to worry about? The input specifier already looks off to me.
In any case, I'll prep a PR for the above fix and test it.