Publishable libraries with Nx Monorepo - part 1
Arthur Groupp
Posted on July 20, 2020
Every developer one day come to a moment when he has number of ideas in different projects that will be great to combine and structure in one or more libraries. I came to this thoughts a few weeks ago and decided to express my last year experience in an open source project that I will constantly supplement in future. Maybe this project will grow up into something useful for other people. Anyway, it gives me opportunity to bring some order on the table.
To whom who is interested in project progress and resulting code – welcome to the repository.
I started this project many times and every time something went wrong. Building, testing, tons of work to bring everything to order and then small change breaks everything. Thanks G-d I meet wonderful people Lars Gyrup Brink Nielsen and Santosh Yadav and their great articles. I opened for myself wonderful world of Nx that solved all my previous problems almost out of the box (not all of them but it’s even more interesting this way).
I decided to base my project on Nx Workspace.
Naming
Choosing name is very important part for the repository creation process. Because we are building repository of publishable libraries, we will need to add them to Npmjs later on. So, the name of the repository will become the name of the organization on Npmjs.
Let’s register one right now. Go to Npmjs and signup/sign in. Then, click on your avatar at the right and open account menu. Click “Add Organization”. Now choose the name for your new organization. It must be unique in the scope of all npm world. Choose wisely, you won’t be able to change it later.
Workspace creation
Now, let’s create the workspace:
$ npx create-nx-workspace@latest <organization_name>
It can take a while to fetch necessary packages, so be patient. Choose “empty” as the answer to “What to create in the new workspace”, “Nx” to “CLI to power the Nx workspace” and “Only use local computation cache”. In a few minutes, we get our blank canvas where we will express our ideas.
Workspace adjustments
I prefer to use the latest versions of my tools, so let’s go into package.json
and update the versions of typescript, ts-node and eslint. Then delete node_modules
folder and re-install it. Then, let’s remove "private:true
" from package.json
.
Code formatting
Good code formatting is important. It improves code readability that highly help when you return to your code in a while. Additionally, it helps other people to understand your code quicker. Some people write the code well formatted from the beginning, others write everything in one line and happy with it. Generally, it’s a matter of taste and doesn’t effect on code behavior. I’m perfectionist by my nature and I want everything to be perfect. Great news for me was that my new workspace includes Prettier out of the box. Prettier is the package that allows you to format your code automatically according to rules. The rules are set in .prettierrc
file as a json
.
I made few changes in it just according to my own preferences. For example, I don’t like parentheses around a sole not necessary type annotated arrow function argument, or I want width of my page to be 110 chars, not 80. This is my .prettierrc
:
{
"singleQuote": true,
"arrowParens": "avoid",
"printWidth": 110
}
Initial commit
Nx already created the local git repository inside our workspace. Then, this is the right place to make first initial commit.
$ git commit -a -m "initial commit"
Repository
Now, when the changes are commited, let us add our project to GitHub. First, we need to create the repository on GitHub and then tell our local repository that now its remote is on GitHub.
$ git remote add origin https://github.com/user/repo.git
And push it to origin:
$ git push –u origin master
-u
parameter makes git to remember the “remote” and “branch” and allows you all next times just use git push
.
Starting to paint
The first set of libraries I plan to create will be universal ones that must work on server and client sides. Until now, our monorepo is empty and can do not much. To teach it how to do useful things we need to install plugins.
Let’s use nrwl/node
plugin for our first project. This plugin gives us the functionality of creating, testing and building ready to use npm packages.
$ npm install -save-dev @nrwl/node
Scaffold new libraries:
$ nx g @nrwl/node:library lib1 --publishable --importPath="@<organization_name>/lib1" --tags="scope:public,type:util,target:all"
$ nx g @nrwl/node:library lib2 --publishable --importPath="@<organization_name>/lib2" --tags="scope:public,type:util,target:all"
--publishable
parameter makes our library literally publishable on npm after building.
Tags are useful if the tags constraints in “.eslintrc” are set up. With these constraints, you can set up which projects can depend on which. We will return to this topic later.
Testing
Now, when we have our new projects in place we can start to fill it with code. Dramatically important part of the development is testing. Good test is not less art then a good code. Sometimes it is even more complex to test the behavior then to build it. The process of building unit test suites in Nx is very simple, all you need to do is to create file with suffix .spec.ts
within your project folder and put your test code in it. Nx uses Jest as its default testing framework.
After scaffold of new library, you already have dummy simple test in it, so feel free to use it as an example in future.
To run test:
$ nx test lib1
$ nx test lib2
That is great during development phase. However, we need a way to test all of the projects at once. To achieve this we need to create command in our package.json
:
"scripts": {
...
"test:all": "nx affected:test --all --codeCoverage --skip-nx-cache"
}
Now, if you run npm run test:all
all test suits will be run through all of the solution.
Building
After writing the code and being satisfied with the tests results, we want to publish our projects, so all other world will enjoy using it as we do. In order to publish we need to build our projects first:
$ nx build lib1
$ nx build lib2
You will find built and ready to publish versions in dist/libs/lib1
and dist/libs/lib2
. Now we ready to publish it to npm. You need to go to dist directory of your project
$ cd /dist/libs/lib1
Important! When you publish public package for the first time you need to specify "--access public
".
$ npm publish --access public
The rest times when you will publish this package, you can do it with
$ npm publish
Conclusion
We created the monorepo and two publishable libraries. We tested it, pushed source to GitHub, built and published to Npmjs. This is big and at the same time very basic step. Nx present perfect tool that allows us to concentrate on development and not on initial setup.
To be continued
Posted on July 20, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.