cli: Dependencies are bundled in the wrong order

If you create a new default typescript project, add bootstrap and jQuery, then apply the dependency to the bundle as documented it works:

"dependencies": [
  "jquery",
  {
    "name": "bootstrap",
    "path": "../node_modules/bootstrap/dist",
    "main": "js/bootstrap.min",
    "deps": ["jquery"],
    "exports": "$"
  }
]

Now, remove jasmine from the project (don’t ask, I had to experiment to find the error in my project) and the vendor bundle contains bootstrap before jQuery, so the application fails on startup.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 3
  • Comments: 23 (9 by maintainers)

Most upvoted comments

I may have some input to this one.

I wrote a fix for a deeper source location possibility (src file not in root folder): https://github.com/aurelia/cli/pull/427 During the progress i found some strange things happening to the dependency load order too - since i do some asynchronous folder lookups, the dependency order came wrong in most cases.

I tracked this issue down and found the bad-boy. (Fixed it also in the pull request) The issue seems to have its root in the aurelia-cli/lib/build/bundle.js file in the code:

static create(bundler, config) {
    let bundle = new exports.Bundle(bundler, config);
    let dependencies = config.dependencies || [];

    return Promise.all(
      dependencies
        .filter(x => bundler.itemIncludedInBuild(x))
        .map(dependency => bundler.configureDependency(dependency)
        .then(description => bundle.addDependency(description)))
    ).then(() => bundle);
  }

bundler.configureDependency is an asynchronous task. since all configureDependency get called at one point and are waiting for finish, the promises are able to resolve in different order than they occur in the dependencies array and are therefore also added to the bundle in a different order.

I fixed this with the following:

 static create(bundler, config) {
    let bundle = new exports.Bundle(bundler, config);
    let dependencies = config.dependencies || [];

    return Promise.all(
      dependencies
        .filter(x => bundler.itemIncludedInBuild(x))
        .map(dependency => bundler.configureDependency(dependency))
    )
    // Add dependencies in the same order as they were entered
    // to prevent a wrong module load order.
    .then(descriptions => 
      descriptions.forEach(description => 
        bundle.addDependency(description)))
    .then(() => bundle);
  }

This code waits for all promises to be done and then adds the descriptions in the order as they have been in the dependencies array.

I hope this clears things up a bit.

A workaround for this is to use prepend For instance instead of adding jquery to the dependencies, use "prepend": ["node_modules/jquery/dist/jquery.js"]