Software development is about solving problems. Sometimes the problems are tightly coupled with the domain and other times they are generic, not related to a specific business or field.
To avoid repetition in solving problems, we as developers have the ability to abstract & extract our solutions to self-contained modules, most often called libraries or packages.
JavaScript is no exception to this, and therefore we currently have a plethora of options available.
Despite the fact that there are currently more than a million packages available on NPM, there is still potential and value in creating your own.
What makes a good library?
There are different kinds of libraries in terms of size and purpose. Whole frameworks could fall into an umbrella term of software libraries, but there are also one-liner functions wrapped in packages that are by definition, also considered libraries. Their context is often different, but some common rules can be applied to all of them.
- solves a specific problem
- has good documentation
- easily extendable
- well tested
Why even bother making a library when you can copy and paste?
Abstracting a problem has its own costs. Sometimes, making an abstraction too early or without a defined plan can lead to accidental complexity or incorrect implementation. Therefore, using good old copy and paste strategy is oftentimes preferred solution, until we know the problem deeper.
But, if the code is copied too much, it can become difficult to maintain and upgrade. The reason behind this is often because the copied code relies on repeating some patterns in a certain way and if we don't repeat the same structure, bugs can occur.
Knowing the right timing for abstraction is an art of its own, but a general rule of thumb is that a piece of code is a good candidate of abstraction after being copied for two or three times.
JavaScript library anatomy
After we've identified our candidate for abstraction, the next step is to learn about the structure of javascript libraries.
To be considered a JS package that can be published to NPM or Yarn, it should have the following set up:
- valid package.json
- exported JavaScript modules in one or multiple formats
- Universal Module Definition
- CommonJS
- Asynchronous Module Definition
- ES2015 Modules
This is a minimum requirement and, depending on the complexity of the software, there could be many more parts to it.
Local development
The best way to develop a library is to treat as a realm of its own, if possible. That means that it has its own testing strategy and its own system for running the project in isolation.
In scenarios when this is not possible or we just want to test our package in a real-world application before publishing it, there are ways to use them in locally.
Npm / Yarn Link
Local development can be achieved by linking our packages to a single local source stored on the disk. So, if we're using Yarn, we can use yarn link command, and for the NPM there is an equivalent command.
Yalc
Yalc is a great tool to achieve more control of local package installation and dependencies. It behaves as a local repository and simulates the behaviour of having a remote repository like npm.
Monorepo
Some libraries may be too big to be contained in a single package. Such libraries may be architected as a mono-repository, by storing multiple smaller packages in a single repository.
This can result in better control of source code and better modularity, especially if many parts of the system depend on different independent modules or consumers of the library don't need to use everything that the library contains.
An example of monorepo is babel repository that's developed with lerna.
Best practices
General software development practices can be applied to library development. Most notable elements are:
- tests
- documentation
- commitlint
- (auto)changelog
- semantic versioning
- linting
Zero-config solutions
Setting up a JavaScript library with all the requirements mentioned can be a bit overwhelming. After the initial development of the library, it calls for maintenance of dependent packages and upgrade of features and procedures.
To simplify the package development we can use CLI-s that solve most of the common problems of the library set up so we can focus on the code itself.
Possible options:
-
TSDX
- Zero-config CLI for TypeScript package development
-
Microbundle
- Zero-configuration bundler for tiny modules
Summary
JavaScript libraries are self-contained software modules that export reusable code for usage in different projects and scenarios. We learned about some general guides which can improve the quality of packages and what are the common parts of every package. To simplify the package development, we can use zero-config CLI-s which allow us to focus on the code, but it's important to understand what these tools do for us so we can have better control and knowledge on how to fix something if it's beyond the zero-configuration method.
Happy packaging!
Top comments (0)