DEV Community

Cover image for Publishable libraries with Nx Monorepo - part 1
Arthur Groupp
Arthur Groupp

Posted on • Updated on

Publishable libraries with Nx Monorepo - part 1

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>
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And push it to origin:

$ git push –u origin master
Enter fullscreen mode Exit fullscreen mode

-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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

--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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Important! When you publish public package for the first time you need to specify "--access public".

$ npm publish --access public
Enter fullscreen mode Exit fullscreen mode

The rest times when you will publish this package, you can do it with

$ npm publish
Enter fullscreen mode Exit fullscreen mode

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

Photo by Tekton on Unsplash

Top comments (5)

Collapse
 
chts profile image
C.H.

Hi Arthur, thanks for the comprehensive article :)

could you please go a bit more into detail about the option
--tags="scope:public,type:util,target:all"

What are the valid types for the constraints you mentioned?

Collapse
 
mwoodpatrick profile image
Mark Wood-Patrick

Cool article, very helpful. Any thoughts on how to use Nx in a dev container?

Collapse
 
brianmcbride profile image
Brian McBride

Can you go into detail on how to manage the package.json
Nx seems great. Each lib or app sharing a root package.json works for development. For production.... not so much.

Collapse
 
agroupp profile image
Arthur Groupp

inside every new generated library you have its package.json and its README. You need to update it by yourself and after building you'll get it in dist.

Collapse
 
vandriesh profile image
Vitalie Andries

any discovery how to uglify and add revision hash to the dist files?

I see no effect from optimize flag.

I just want to "publish" internally.