Splitting our services into microservices had led us to wonder: what do we do with the shared code? Especially code for basic functions, such as logging or error handling.
Because the code of each microservice lives in its own project folder, and we obviously can’t replicate our shared code in each project folder, we have to place it in a separate shared/common/utils folder outside of any project folder. But how to access an external directory from our projects then? Solutions with npm –link proved to be uneasy to set up, and were causing problems with namespace aliases. Plus, if your common code evolves with even a minor breaking-change, and all your projects are linked to it that way, you have to make the required adaptations in all your projects before you can go on working on them. Not so flexible.
In the end, we decided to go the long, but righteous way: to store such common code in a special project of its own, which we would build as versioned npm package, store on a private repository, and access from any of our projects. It was actually pretty easy to do. Let’s check the few steps to get there:
Host a private NPM repository
Seems like all the thing seen from afar, but it can actually be a breeze, provided you have a server at hand which can run Docker.
We used Verdaccio, which requires no setup at all. Check out https://hub.docker.com/r/verdaccio/verdaccio/ for details. Publishing restrictions on the generated repository are not covered here. Simply make sure you mount a volume to store published packages, as in docker-compose.yml:
volumes:
- /path/to/storage:/verdaccio/storage
Create the shared code library project
We use a NestJs project, compiled with Typescript. Your shared code should reside in /src as usual. Now for the configuration of the library building and publishing:
Notable options within tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
...
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": "./",
"noLib": false
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
tconfig.build.json
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
package.json
{
"name": "@ceneau/backoffice",
"version": "1.0.0",
...
"main": "dist/index.js",
"files": [
"dist/**/*",
"*.md"
],
"scripts": {
"build": "tsc -p tsconfig.build.json",
...
},
"publishConfig": {
"access": "restricted"
},
...
}
index.ts should be a barrel file at the root of src/ whose goal is to re-export every objects you want to export in the package. index.ts will be transpiled and become dist/index.js, the root of your exported objects.
With that, the library is ready for building and publishing, but we still have to tell it where to store the generated package, as well as few optional behaviors to follow on each build.
.npmrc (at project’s root) – even if you use yarn
@ceneau:registry=http://url.to.private.npm.repository/
.yarnrc (at project’s root) – obviously if you use yarn to build
version-commit-hooks false
version-git-tag false
version-git-message "Ceneau backoffice common - v%s"
These options handles the generation of tags for each build, and associated git message. Check documentation for more details.
Now, to publish a new version of the shared code:
npm adduser --registry http://url.to.private.npm.repository/
This, if you created your npm repository with no publishing restriction, allows you to create a user within it. You’ll be ask for details and password.
yarn publish
Builds and publishes the package. Hooray !
Use your common library in projects
Now that we’re here, the only remaining trick is to tell your project where to search for your common packages, in addition to the other default npm repositories.
.npmrc (at project’s root) – even if you use yarn
@ceneau:registry=http://url.to.private.npm.repository/
package.json
{
"dependencies": {
"@ceneau/backoffice": "^1",
...
},
...
}
You should be good to go !
Bonus: recover from wrong npm config
If you accidentally changed your global npm registry, your next npm/yarn commands are likely to fail (right now with a 500 error coming from I have no idea). My NPM config was showing some concerning bits:
> npm config list
; userconfig C:\Users\L.npmrc
registry = "http://npm-repo.x.ceneau.com/"
Quick! Hurry and set back the default registry up !
> npm set registry https://registry.npmjs.org/
