How to Easily Share Reusable Modules in Node.js – at Scale

Home Dev How to Easily Share Reusable Modules in Node.js – at Scale

How to practically share common JS components between apps, projects, services and everything else… at any scale.

Source: FreeCodeCamp

Sharing common JS code through modules and components is vital to creating a scalable, stable and maintainable codebase. It’s also faster.

Traditionally, we use modules to share and reuse common JS code between different applications, projects, and services (or micro-services). This is to avoid copy-pasting, which as we all know, will end up biting us in the…

Instead, we can create self-contained modules with a clear purpose which can be reused and shared between the projects which need them. Each is encapsulated, independently tested and versioned. Each is a reusable code-unit or code components. Sharing them at scale in a fully-managed way, will enable us to build better, more maintainable software, and do it faster.

On Package Managers and Source-Control

Package managers like NPM have traditionally enabled us to publish and manage modules as packages through its online database.

This is great since it helped us install a packed project as a module in another project, without having to copy-paste it. With recent automation like Lerna, it also became more comfortable to publish a few modules from one project.

But… package managers do not manage source code. As a result, there’s a gap between your source-code management (SCM) control system and your shared modules, which starts to become painful as you share more modules.

The symptoms, eventually, make it hard to scale code sharing. It’s very hard to publish and manage 20 modules, let alone 200. Using Bit, we manage over 500 shared JS components across our services- without coupling. Here’s how.

Bit is an open source tool that brings together SCM and shared-module management in a way that integrates to both Git and NPM to fill the gap.

Using Bit you can very quickly share code components between Node.js projects and services while gaining control over their dependency graph and syncing changes to their source-code made in the different projects.

The result is instant and very scalable code-sharing even for the smallest reusable modules, with the ability to make changes and sync them anywhere.

Instantly sharing small modules as reusable components

Bit lets you “track” reusable JS code as components. Meaning, you can use the bit add command to point Bit to the reusable code in your project. It will then start tracking the source-code in these files as a reusable component. It will also let you version and manage it across projects, we’ll see that later.

Bit uses a semi-automatic dependency definition mechanism, which saves up most of the work for encapsulating the component to make them reusable!

Let’s look at the Ramda JS utility library as an example. The same workflow applies to all kinds of JS apps, services and projects.

In this example, Ramda has over 200 reusable functions in the /source directory. Each is a reusable module we’d like to share across projects.

.
├── package.json
├── source
│ ├── F.js
│ ├── T.js
│ ├── ...
│ ├── internal
│ │ ├── _Set.js
│ │ ├── ...

Let’s say we have this project developed in our codebase. We can install Bit, and use it to start tracking these reusable components:

$ npm install bit-bin -g
$ cd project-directory
$ bit init
$ bit add source/*.js
tracking 256 new components

Now, Bit goes through the files and writes the dependency graph for every component, for both internal files/components and external packages. It uses this information to create an isolated representation of the component, which can be shared, used and synced across other projects as well.

Next, let’s run a quick bit status command to see that Bit tracked the components and that they are ready to be versioned:

$ bit status
new components
(use "bit tag --all [version]" to lock a version with all your changes)
 > call ... ok
> complement ... ok
...
> add ... issues found
untracked file dependencies (use "bit add <file>" to track untracked files as components):
source/add.js -> source/internal/_curry2.js
 > add-index ... issues found
untracked file dependencies (use "bit add <file>" to track untracked files as components):
source/addIndex.js -> source/internal/_concat.js, source/internal/_curry1.js
...

As we can see, the components were not tracked properly. Bit tells us this is because the components need some files located at theinternals directory. Let’s add that too:

$ bit add source/internal/*.js --namespace internal
tracking 74 new components

Great! Now Bit shows that all the components are ready to be versioned and published:

$ bit status
new components
(use "bit tag --all [version]" to lock a version with all your changes)
 > add ... ok
> add-index ... ok
...

Great. We now have 256 components ready to be exported… but how will we compile/transpile the code? Well, Bit used pre-made configurations as components you can reuse on the project level, to make this easy.

We just need to import a pre-made compiler into the project:

$ bit import bit.envs/compilers/babel --compiler
the following component environments were installed
- bit.envs/compilers/babel@0.0.20

And now we can version the components:

$ bit tag --all 0.9.6 --message "initial component version"
330 components tagged | 330 added, 0 changed, 0 auto-tagged
added components: t@0.9.6, f@0.9.6, __@0.9.6, add@0.9.6, ...

And that’s it! All the components are now tracked, have their dependency graph resolved, versioned, and ready to be exported and reused. Let’s quickly set up a remote workspace on bit.dev, Bit’s free online databse and UI. Then let’s export the components:

$ bit export <account-name>.<collection-name>
exported components to <account-name>.<collection-name>

That’s it! Here is how it looks. Each component can be easily discovered, played-with in an online playground with hot reloading, installed with NPM/Yarn, and also imported directly with Bit- which we will dive into now.

https://bit.dev/ramda/ramda — reusable JS component collection

Reusing in another project, syncing changes

https://bit.dev/ramda/ramda/equals — reusable JS component

So now we have all the reusable modules from the original project available a bit.dev, which is great because we were able to make hundreds of modules reusable without refactoring anything or working for more than 15 minutes.

We can install these modules with package managers for Node.js like NPM and Yarn, which means we were able to scale sharing of reusable modules dramatically leveraging Bit’s automatic component tracking mechanism.

Now, let’s look at another great new ability we get from bringing SCM and management of reusable modules together. Using the bit import command, we can “duplicate” the source code of the component into a new project, while having both its dependency graph and source code changes managed!

Let’s look at the “equals” component:

You can see the small installation pane on the left, and choose “bit”.

Then, import the component into your project.

bit import ramda.ramda/equals

Now you can make changes to the actual source code of the component! This is vital when you wish to avoid coupling between services for example, or when you want to make a change to the shared module from a different repo.

Once done with the code changes, you can just tag the component with a new version, and export it back out to the collection. Then, you can import and new version into the original repo (or other repos), and use bit checkout to merge the changes! And- here you go, 2-way scalable and lightning fast code reuse for shared modules. Neat, right?

$ bit checkout 1.0.1 equals 
successfully switched ramda.ramda/equals to version 1.0.1
$ bit status 
modified components
> ramda.ramda/equals... ok
$ bit tag equals --patch 
$ bit export ramda.ramda

When you try to compare this to the traditional package workflow, from the overhead of publishing a package to the ability to make changes anywhere and sync them across projects, you get a powerful solution for increasing code reuse at the granular level of shared components, and everything else.

Feel free to comment below and ask anything, or jump in and give it a try

Leave a Reply

Your email address will not be published.