Lerna Setup in Aurelia 2 - How does it work?

Hello, I’m looking into creating a Lerna project and I’m looking a lot at the Aurelia 2 project for arranging my own project. I want to move Aurelia-Slickgrid as a package, and move all the common code into a Common package and finally an Aurelia demo as a 3rd and last package.

So in short, the packages have to be executed in the following order

  1. build Common into a dist folder with "main": "dist/es2020/index" set in the package.json
  2. build Aurelia package with again main configured similar to step 1
  3. finally run the Dev demo (but only after step 1 and 2 are ready or have dist code)

In other words, if C requires B and B requires A, it should build A then build B then C.

If I look at Aurelia 2 setup with Lerna, the script to run Dev with a Watch is on this line, the argument --parallel is used

"scripts": {
  "dev": "lerna run dev --parallel"

then if I go in any of the packages under Aurelia, for example the aurelia package, they have few dependencies that are packages, like this (most of the Aurelia packages follow the same pattern)

 "scripts": {
    "dev": "tsc -b -w"
"dependencies": {
    "@aurelia/debug": "0.6.0",
    "@aurelia/fetch-client": "0.6.0",

but in Lerna docs, they mention that the Parallel flag doesn’t follow any order…

Similar to --stream , but completely disregards concurrency and topological sorting, running a given command or script immediately in all matching packages with prefixed streaming output. This is the preferred flag for long-running processes such as babel src -d lib -w run over many packages.

So my question is this, how can the Aurelia 2 project even work with the Dev setup when the Parallel flag completely ignores the order of the packages?

If I run the npm run dev the first time, I get an error saying that the Common package is not found because the Aurelia package tries to use it without waiting or caring about the dependencies order… now of course if I run it the command a second time, it’s all good but it’s not exactly good for other users who might want to contribute to my project. Isn’t Aurelia 2 having the same issue?

1 Like

The only way I can think of to fix this is to add a predev script to run each Dev build without the --parallel flag (hence without a watch mode) and without it, it does keep the order of dependency requirements (if B requires A, it will build A then build B)

"scripts": {
  "predev:watch": "lerna run dev",
  "dev:watch": "lerna run dev:watch --parallel",

it might not be the most efficient but it seems to work. That will run the TypeScript builds in sorted order of dependencies (symlink by Lerna) and once that predev is all done, we can move on with a watch mode since the dist folder now exist in each Packages and so it works.

Also from what I read on Lerna and some watch related GitHub issues, it kinda make sense since a watch build is always watching, you don’t know what the build is actually finished since the process is always running in watch mode.

1 Like

You’re correct about the lack of guaranteed order in --parallel. Our dev setup is indeed intended to be run after an initial build, in which case the order isn’t important anymore.

That said, a word of caution with regards to looking at the v2 repo as an example for monorepo setup. It’s complex and specifically tailored to some of our very demanding scenarios, most of which you’ll likely not run into. There is also a lot of interaction between our scripts and the circleci setup.

I should also point out that I ran into numerous limitations with lerna (as well as with some of the other tools we’ve used / are still using) and are in the process of replacing them with custom created stuff. This is one of the reasons for the delay of v2 alpha.

Be careful with heavily investing in tools like this. We’ve burned ourselves over and over with this.


Our dev setup is indeed intended to be run after an initial build, in which case the order isn’t important anymore.

Ok I found the steps you mentioned in this Aurelia 2 Building and Testing doc. Perhaps I should do the same in mine.

Thanks for the word of caution, I think it will be ok in my use case since it should be simple enough (I think). My goal is to replace/merge Aurelia-Slickgrid and Angular-Slickgrid (datagrid libs) into a monorepo and the structure will be

  1. One common (you can call core) package, that is the entry point
  2. couple of TS Services like OData, GraphQL, ExcelExport as packages that not all user need
  3. some Framework packages which are using the common package (Aurelia, Angular, Vanilla)
  4. some Framework examples, this is the deepest level (3) since it requires Step 1 and 3.

and are in the process of replacing them with custom created stuff

will that still be monorepo/workspace related stuff? and are you intending to replace Lerna?

Anyway, what I have so far is a monorepo project setup with Lerna which has step 1, 3 & 4 (vanilla framework for now, Aurelia package inside it will come later). I got most of the basic setup working with Vanilla (no framework) though I had to do the config that I wrote a bit earlier with the predev to make sure my dist folder all exist prior to running the watch and that seems enough. Apart from that, I don’t think there will be that much of issues with the small monorepo structure that I have… oh I also won’t (and cannot) use the hoist mode that Aurelia uses because I’ll have multiple Frameworks, so that might be lots of node_modules to download when calling the Lerna Bootstrap but that should be acceptable (I think).

Anything else I should be aware of before going too far with this?


I’m actually wondering if I should omit any framework related from my monorepo!?! I think I might end up with 3 different frameworks, I wonder if that kind of feature should go in a monorepo if it’s discouraged to do that kind of merging from multiple external repo/framework vs all in the monorepo… hmm need more to do more investigating about this. Might be challenging with unit testing.

1 Like