Using require breaks router...?


#1

Hi, first sorry for my bad english :confused:

I had an aurelia app that worked fine but after a “npm update”, it has a strange problem:
If I do this on my app.html, it shows the list with the configured routes correctly:

<ul repeat.for="nav of router.navigation">
    <li>
        <a href.bind="nav.href">${nav.title}</a>
    </li>
</ul>

but if I move this html to a nav.html and use it like this (with the bindable atribute, etc), it stops working

<require from="nav.html"></require>
...
<nav router.bind="router"></nav>

Any html I have inside the nav.html gets printed on screen but not the routes.

Now, even stranger is that If I just write on my app.html this:

<template>
  <require from="nav.html"></require>

  <ul repeat.for="nav of router.navigation">
    <li class="${nav.isActive ? 'active' : ''}">
      <a href.bind="nav.href">${nav.title}</a>
    </li>
  </ul>

</template>

It does not show the routes anymore (but show any HTML inside the nav.html). If I remove the “require”, it works again.
The same problem happen if I use @viewResources instead of require on the template.

If I configure nav.html to be a global resource, it works fine but if I require a css file, it stops working again.

So basically, this works (without css)

<template>
  <ul repeat.for="route of router.navigation">
    <li>
      <a href.bind="route.href">${route.title}</a>
    </li>
  </ul>
</template>

but this, although applies the css, does not render the UL:

<template>
  <require from="app.css"></require>

  <ul repeat.for="route of router.navigation">
    <li>
      <a href.bind="route.href">${route.title}</a>
    </li>
  </ul>
</template>

Did something changed around this?


#2

See your browser console, I guess it says something (module or file) could not be found.

Try relative path.

<require from="./nav.html"></require>

<require from="./app.css"></require>

#3

Saddly, this is not the case, if I put some random HTML inside nav.html, it appears correctly on screen :frowning:


#4

Another thing might matter, nav is a defined HTML tag.

You can try my-nav.html to avoid overwriting a known HTML tag.


#5

I would be interested in any solution here, I have the same problem you have described at the end of your post when trying to require a css style sheet in my app.html before the navigation.

I recreated it in a clean app with just a couple pages and a style sheet added. Without the stylesheet it works fine, when I add it the styles are applied but there are no li elements in the ul.

I should have mentioned I have tried the relative paths mentioned above.

According to my package.json I am using “aurelia-cli”: “^0.33.0”, I just upgraded to 0.33.1


#6

Even If I globally have 0.33.1, au new project gets generated with 0.33.0 on the package.json.
So I generate a new app, and add only the minimum to reproduce this problem. If someone with more knowledge can help us, just unzip the folder, run npm install and au run - it will show a page with a css but without the routes list - removing the require from the app.html will lose the css but the routes list will show. I have 3 aurelia projects that have this problem now and I tried everything I can think of with no success… probably it is a version mismatch or something stupid on my part but I really do not know how to proceed :frowning:


#7

I did some investigation. It was not because nav is a known html tag name.
I can repeat all the issues mentioned.

Somehow in latest Aurelia version, it looks like the require tag (either require css or another component) altered some timing of lifecycle callbacks (or timing of router initialisation).

To test

<template>
  <require from="app.css"></require>

  <ul repeat.for="route of router.navigation">
    <li>
      <a href.bind="route.href">${route.title}</a>
    </li>
  </ul>
</template>

Put this in app.js

  bind() {
    console.log('router.navigation size ' + this.router.navigation.length);
  }

It prints

router.navigation size 0

Comment out <require from="app.css"></require>, it prints

router.navigation size 3

It looks like with require tag, the app bind() callback is called before the router is initialised. This can be approved by delayed render which renders correct nav bar.

<template>
  <require from="app.css"></require>

  <ul if.bind="ready" repeat.for="route of router.navigation">
    <li>
      <a href.bind="route.href">${route.title}</a>
    </li>
  </ul>
</template>
export class App {
  ready = false;

  constructor() {
    setTimeout(() => {
      this.ready = true;
    }, 2000);
  }
  //...
  1. it’s not latest aurelia-router 1.6.1, I can repeat the issue with aurelia-router 1.5.0
  2. not aurelia-binding 2.x.x, I can repeat the issue with aurelia-binding 1.7.1
  3. somewhere in latest aurelia-templating/templating-resources. I cannot debug individual old version because of dependency requirement.

@bigopon, this looks like rather serious. Definitely a regression, because I cannot reproduce this issue on gistrun with current https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js (I guess it’s not updated to latest version).

I can confirm with old version, it always prints

router.navigation size 3

So the timing regression is introduced somewhere in latest version of Aurelia.

@bigopon, another thing surprised me is, even with the timing regression, the view should update itself when router was initialised later. Because in router source code, I can see we only use push and sort to mutate router.navigation array. Those changes should be picked up by CollectionObserver, why it doesn’t?


#8

@bigopon the https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js looks using aurelia-binding 2.x, so the gap between the bundle and my local Aurelia should be very small.


#9

I cannot reproduce this with webpack. And aurelia-cli requirejs doesn’t automatically track node_module files makes it really hard to dig into this. @huochunpeng @leo-mck can you give webpack a go to check if it breaks there ?

import { RouterConfiguration, Router } from 'aurelia-router';
import { PLATFORM } from 'aurelia-pal';

export class App {
  router: Router;

  configureRouter(config: RouterConfiguration, router: Router): void {
    config.title = 'Aurelia';
    config.map([
      { route: '', redirect: 'view1' },
      { route: 'view1', name: 'view1', moduleId: PLATFORM.moduleName('view1'), nav: true, title: 'View 1' },
      { route: 'view2', name: 'view2', moduleId: PLATFORM.moduleName('view2'), nav: true, title: 'View 2' }
    ]);

    this.router = router;
  }
}


#10

Strange, I can repeat it in webpack. I pushed up the whole app including yarn.lock for you to reproduce.


#11

@bigopon, remember I questioned CollectionObserver? Behold, it got no issue for Chrome to pick up later router initialisation. But it killed Firefox and Safari.

I guess that’s why you cannot reproduce it, because you use Chrome, it re-rendered even with the timing regression.

@leo-mck @rhunter what browser are you using?


#12

I have the repro given by @leo-mck using requirejs also breaks on Chrome. So far I have:

webpack + chrome -> fine
requirejs + chrome -> break

You have

webpack + not chrome -> break


#13

Right, I confirm I can reproduce on requirejs + all browsers too.

Can you try webpack + firefox (broke for me)?


#14

@bigopon

To summarise, there are two issues here.

  1. the timing regression, bind() is now called after router initialisation.
    • it is unknown what change introduced this.
    • (probably aurelia-templating 1.8.0, could not test old version of aurelia-templating due to broken dependency)
  2. with presence of the above issue, CollectionObserver didn’t pick up changes of router.navigation array.

While reverting to aurelia-templating-resources 1.6.1 does solve this problem on the surface, it did not answer why there is (1) timing regression.


#15

@huochunpeng and @bigopon , THANK YOU for your time and attention. I am developing 3 projects with aurelia for about 6 months, 2 of them that will go to production on the next weeks and until now, it has been an amazing experience and I have never found a problem that had stopped me like this. For now, reverting to aurelia-templating-resources 1.6.1 corrects this issue.


#16

@huochunpeng

Nice observation, indeed if we comment out the fix from my PR in templating resources https://github.com/aurelia/templating-resources/pull/349, the issue is gone.

Now I will need to verify the timing regression of bind() called after router initialization. But shouldn’t the router be initialized before any life cycle. And what initialization are we talking about ?


#17

not sure if it’s related but the routes activate() is called before the aurelia-composed event has fired. seems that was different in some earlier version


#18

@bigopon for the timing regression,

If you check my gistrun link (the gistrun bundle probably was built with some older version) the same code prints router.navigation size 3 in bind(), means the router.navigation is already populated by the time of bind().

But with latest version of Aurelia, it prints router.navigation size 0, means the router.navigation is yet to be populated by the time of bind().

It’s probably related how aurelia executes router’s instructions. It seems now it executes them after bind() which is not ideal. But I can confirm the regression is not from aurelia-router’s recent change, as reverting to old router does not help.


#19

Ok, i think this only happens when used with Bluebird. Try removing any trace of bluebird from the test app and you will see that it’s 2 in bind. This is getting … weird … so weird

Btw, shouldn’t navigation.length be 2 ?


#20

In my demo app, I mapped router with 3 routes, navigation.length should be 3, not 2.

Indeed, removing bluebird solved the timing regression. :open_mouth:

It’s not caused by recent bluebird update either. I tried few older versions of bluebird, all fail.

Some recent Aurelia changes revealed a hidden bluebird bug??

I would like to vote the easier solution, dump bluebird :smile: and move on.