- read

Using Angular cache with library

Alain Boudard 39

How the angular cache can interfere with the build of an application.

I was reading this nice article about Angular cache (starting with version 13), and it reminded me that I stumbled upon an issue with this feature regarding the development of libraries. Basically, if you install a library with npm, if the source code of the library changes but not the version number, what happens.

The project

The Angular project we will be using consists of a workspace in which there will be a library and an application. Normally, when we develop an Angular library in the same workspace than the application, the local tsconfig file takes care of telling Angular where the source code is so that we don’t need to install the library.

For this project, we won’t be using the library directly, but we will publish it to any kind of registry compatible with npm and install it with npm install command.

I had 2 tools available :

  • A free demo account with jfrog.io that allows you to host your Artifactory registry in the cloud. You get a domain name like `https://username.jfrog.io` and can publish right away.
  • A local install of Verdaccio running next to our app.

The first option is really nice to test, but it’s limited in time, and our actual needs for this demo are very simple and Verdaccio is more than enough.

The local npm registry

Using verdaccio is very simple :

  • Install the package globally :
npm install -g verdaccio
  • Run verdaccio
verdaccio

You should see the server running :

Running local Verdaccio instance

And access your empty registry (note these commands for using this registry for later) :

Local empty install of Verdaccio for npm registry

The Angular workspace

Let’s create a very simple angular workspace and add a library and an application.

ng new ng-lib --create-application false
ng g application testapp
ng g library @abo/testlib

This way we have both projects in the workspace. Let’s remove the path configuration from the tsconfig file :

This way, we will only use the library through the npm install, using our Verdaccio registry.

Note : I’m aware that using an Angular library this way is not the proper way when you’re in dev mode but this is not the point here.

Publish our library with npm

We must have followed the Verdaccio instructions to create the user we will login with. Then we can actually login, build the library and publish it :

npm login - registry http://localhost:4873/
Username: admin
Password:
Email: (this IS public) [email protected]
Logged in as admin on http://localhost:4873/.

Building and publishing the angular library with the publish:lib script :

"scripts": {
"ng": "ng",
"start:app": "ng serve testapp",
"build:app": "ng build testapp",
"build:lib": "ng build @abo/testlib",
"publish:lib": "ng build @abo/testlib && cd dist/abo/testlib && npm publish --registry http://localhost:4873/",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},

The result must look like that :

Angular build of a local library and publish to registry

And in our Verdaccio console, we should see the library added to the registry :

Add the library to the application

This is pretty easy, let’s clean up the code of the placeholder Angular application, install our library via the registry and add the single component exposed to our home page.

npm i @abo/testlib --registry http://localhost:4873/
...
+ @abo/[email protected]
added 1 package, removed 1 package and audited 992 packages in 8.988s
The app.component with the library component

Be careful when adding your library because some IDEs have an auto-import feature that is a little bit too fast to find the proper import. You could have something like that (and this would trigger application recompile when unwanted) :

import { TestlibModule } from "../../../abo/testlib/src/lib/testlib.module";

When you would only want this :

import { TestlibModule } from "@abo/testlib";

Let’s alter the library and publish a new version to see the changes. I don’t use any automatic semantic versioning system, let’s use simply the npm version command to upgrade the library and then re publish.

"scripts": {
"upgrade-version:lib": "cd projects/abo/testlib && npm version patch",
"publish:lib": "ng build @abo/testlib && cd dist/abo/testlib && npm publish --registry http://localhost:4873/",

Check that your library is up to date in Verdaccio and re install in your Angular workspace (the new 0.0.2 version).

npm i @abo/[email protected] --registry http://localhost:4873/

The application should show the new library version :

Publish the same version of Angular library

Now, why would we want to publish the same version ? This could be a typical use case when you want to strictly control a release version, maybe aligned with a Maven package or something else. Anyway, let’s see what happens.

If you alter your code in the library and simply try to re publish it, you will get an error like this :

Most of the npm registries prevent from publishing the same version, some allow you to set options to override, but I didn’t find the option in verdaccio — if anyone knows about it, feel free to say it in the comments.

Anyway, we will simply unpublish the npm package and re publish it.

"scripts": {
"unpublish:lib": "npm unpublish @abo/testlib --registry http://localhost:4873/ --force",

So the tasks here are :

  • Alter the library component
  • Unpublish the library on Verdaccio
  • Re build et re publish the library
  • Uninstall / re install the library in our Angular workspace
  • Run the application and see the result

Well, there is no difference, the application was built with a previous verison of the library. Yet, when we take a look at the package-lock.json we see that even if the version number is the same, the integrity property hash is different :

Same npm version but different archive

And actually, if we take a look in the node_modules/@abo/testlib we see that the source code is the one we should expect :

This is the proper updated source code of our library

So, what happend ? Well as you guessed, the angular cache is responsible for this, let’s see how we can act on this.

Remove the cache and then simply re start the application, which will force the build based on the actual node_modules version of the library. In the latest versions, there is a CLI command that doesn’t exist in version 13.

ng cache clean

rimraf .\.angular\

Of course this solution is far from excellent, but at least it works. The alternative would be to deactivate the cache on the build of the application (we don’t care about the build of the library, but since we are in a single workspace, no cache will be used at all). We will try with a fourth version of the library and the following configuration :

ng cache disable
Angular cache disabled

Then we can rebuild the application anytime we want and whatever the version of the library, we will have the proper version. Of course it’s not a perfect solution because caching would improve our build time, but it’s good to know that even if the hash of the library is ok, even if the local source code is ok, well you really can’t know what version is actually stored in the cache, because if we look into the cache, we can see that the code is already precompiled by Angular :

ng-lib\.angular\cache\13.3.11\babel-webpack (for example)
Angular precompiled cache

Conclusion

This local npm registry Verdaccio is really nice to test your Angular library publish skills and parameters. In many cases we don’t really care about the actual version of our libraries other than compatibility, but sometimes, well things happen.