Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nrwl Nx: different version numbers and libs

I want to start an Angular project using Nrwl Nx (multiple apps in one project; https://nrwl.io/nx), but I have two questions:

  1. How can I specify different version numbers to the different apps? Usually I give a version number in package.json, but with Nx there are only one package.json for all of my apps. Should I put it in the environment files? Or in the .angular-cli.json file?

  2. I read this: 'An upgrade to a lib requires a change to all implementors.' Is there any solution (bypass) to use different versions of a lib or NPM package in different apps? There is only one node_modules, but this is critical for my apps.

As you know, the structure of an Nx project looks like this:

apps
    app1
    app2
libs
    lib1
    lib2
node_modules
package.json
.angular-cli.json
...

Maybe these two questions are a little bit opinion-based (I'm not so sure about that tbh), but there are very few articles about Nrwl Nx, and the answers can help others too. Thank you.

like image 437
Roland Rácz Avatar asked Mar 06 '18 13:03

Roland Rácz


People also ask

What is the difference between Ng and NX?

If you add Nx to an Angular CLI project, ng and nx are interchangeable (they invoke the same command, which is nx ). So anywhere you see "nx build" or "nx affected" , you can also use "ng build" or "ng affected" . Nx integrates well with the Angular CLI: It decorates the Angular CLI.

Does NX support Angular 14?

As such, if you upgrade to Nx 14.2 ( npx nx migrate latest ), Nx will make sure to also trigger all the Angular v14 related migration scripts to update your workspace to the latest Angular version.

What is NX Monorepos?

A monorepo is a single git repository that holds the source code for multiple applications and libraries, along with the tooling for them.

What is NRWL workspace?

The workspace plugin contains executors and generators that are useful for any Nx workspace. It should be present in every Nx workspace and other plugins build on it.


1 Answers

I have some ideas here. I work with the NX Extensions every day, and IMHO, leaning on, "that's not the mono repo way" is fine as an ideal but fails in practice. You WILL sooner or later want to make a breaking change to a lib, and you don't want all your tests in the apps failing when you do it (prevent you from releasing, etc, which you may not have the luxury of time to clean up). This might not be exactly what the OP is getting at, but I think with a little change in thinking these solutions might serve. I've tried 'em all, they seem to work.

Note that I am aware of the google way (I worked there). I ran into this problem on the first project I worked on. Their dev environment provides an analog of "if you could have different package.jsons in each app..." so comparing NX to Google's internal system as an absolute 1:1 is a bit off.

Qualifier: this is not "the answer". It just shares some ways I've overcome these problems.

  • Branch the entire repo, call it a version. Make your breaking change, see it all fall apart. Fix everything, update from master, looks good, merge it. Optional: release from this branch.

That "devbranch" thing works for most "breaking lib change" kind of things.

  • In tsconfig.json, provided you aliased your library (@myorg/blah), your app will point at the path you configure. In master, build your lib (ng-packagr). Using the output config, you can call the dist whatever you want (@myorg/blah-v1, v2, as many as you want). Point tsconfig at it (tsconfig will be pointing to the non-build path). Master will now use a locked, known version of the lib (just DON'T REBUILD IT WITH CHANGES). You are now free to abuse your master library as you see fit. To keep an "everything in master working" mindset, you would branch master and then make this change, which would allow you to work on the lib independent of the apps that use it with master untouched.

  • Build your library (versioned, and assumes ng-packagr), npm pack it (you now have a tarball), do what you want with it. Branch master, remove the path entry from tsconfig, add an install entry to package.json (you can install from a file), and your apps should pick it up (again, the import aliases should match). You can also do the install in master (known working version as a tarball), and again abuse your libs as you want.

That latter solution I tested a little and I saw it works, but if you don't have to pack a tarball and mess with package.json, why bother. Good option to know though, and it doesn't incur the downside of not being able to rebuild the library (as you'll overwrite the known working version unless you change the output target).

Using these ideas, I can pretty much get us out of any breaking change jam and provide at least provide one other known working version of any given lib.

I'll put these out there too though:

A primary benefit of a mono repo is that it forces you to avoid incurring the technical debt that multiple lib versions cause, which is SEVERE if you let it go for any period of time. If you let it go long enough, sooner or later you'll have problems with the overall version of Angular, which is a problem you WANT to avoid.

If it gets to the point that you have an app that requires a lot of drift, IMHO, you'd be best served by creating a new repo, dumping the code into it, wiping it from your main repo, wait until it gets into shape, and put it back when it's ready (if ever).

And, remember, when you are working on a library, you need to think a bit differently. It's shared code, and every time you make a change to it, it can't be breaking. Instead of renaming that input, create another one and point it at the original (backward compat), and that sort of thing. Decorator patterns, all that. A breaking change in a lib should NOT be a casually committed thing.

Hope that helps.

like image 187
Tim Consolazio Avatar answered Sep 19 '22 14:09

Tim Consolazio