I made a list of 20 things I might want out of a monorepo tool for a Design System to use as a basis for comparing some of the options including Lerna, Northbrook, and Rush.
- Supports both NPM and Yarn: We have projects using both, plus options are good.
- Build one, some, or all modules: Change detection is nice, but also looking at whether a user can choose.
- Test one, some, or all modules: See if there's any specific features, otherwise overlaps with arbitrary commands.
- Distribute one, some, or all modules: Change detection is nice, but also looking at whether a user can choose.
- Distribute arbitrary bundles: See if there's any way to compose ad hoc bundles, or at least be able to make a bundle module.
- Run arbitrary commands and tasks for one, some, or all modules: I view this as one of the most important core features.
- "Share" dependencies across modules safely: I view this as one of the most important core features.
- "Pin" common dependencies across modules: I view this as a very important feature.
- "Link" module-to-module dependencies safely: I view this as one of the most important core features.
- Install unique dependencies for individual modules: I view this as one of the most important core features.
- Distribute to a pre-release channel: See if there's any specific features, otherwise overlaps with arbitrary commands.
- Parallelization of tasks: Need depends on the project, but potential monorepo size makes this something to consider before you need it.
- Support change log generation: See if there's any specific features, otherwise overlaps with arbitrary commands.
- Support documentation generation: See if there's any specific features, otherwise overlaps with arbitrary commands.
- Support UI style guide generation: See if there's any specific features, otherwise overlaps with arbitrary commands.
- Ability to use Semantic Release in distribution: The tool's release feature may fill need, but options are good.
- Ability to use Commitizen in development: The tool may have a feature that fills a similar need, but options are good.
- Ability to use Greenkeeper for dependencies: Support for multiple
package.json
may be more a feature for Greenkeeper, but want to make a note. - Sufficiently documented: Is there enough to get started and to go deeper as use evolves?
- Community Activity: Are other developers posting about it? What's the GitHub activity like?
Research was done using the documentation, googling for articles, checking out issues, and a little poking around on basic demo repos. I haven't used any of these tools extensively yet or done more than glance at their source code, so if you see anything I have wrong, please let me know. Tools included are Lerna, Northbrook, and Rush.
-
✅ Supports both NPM and Yarn
-
✅ Build one, some, or all modules
With e.g.
lerna run build
orlerna exec --scope moduleOne -- gulp build
-
✅ Test one, some, or all modules
With e.g.
lerna run test
orlerna exec --scope moduleOne -- gulp test
-
✅ Distribute one, some, or all modules
Has both fixed and independent options. With e.g.
lerna publish
will distribute any with changes Kinda can with e.g.lerna publish --force-publish=moduleOne,moduleTwo
Beware issues with--scope
and--ignore
! See #1055 and #1384. Isn't actually effective, the way I mean it. -
✅ Distribute arbitrary bundles
With e.g.
lerna publish --force-publish=bundleOne
-
✅ Run arbitrary commands and tasks for one, some, or all modules
With e.g.
lerna run {{whatever}}
NPM scripts run conditionally With e.g.lerna exec --scope moduleOne,moduleTwo -- {{whatever}}
anything -
✅ "Share" dependencies across modules safely
Almost with
lerna bootstrap --hoist
, except see #867. Now can be assisted by Yarn Workspaces for improved sharing that is as safe as Yarn can make it. -
✅ "Pin" common dependencies across modules
Can be used with NPM shrinkwrap, NPM lockfiles, or Yarn lockfiles. But see issue #377
-
✅ "Link" module-to-module dependencies safely
With e.g.
lerna bootstrap
-
✅ Install unique dependencies for individual modules
With e.g.
lerna bootstrap
-
✅ Distribute to a pre-release channel
With e.g.
lerna publish --canary
-
✅ Parallelization of tasks
Has relevant options including
--stream
,--parallel
, and--concurrency
-
✅ Support changelog generation
With e.g.
lerna publish --conventional-commits
orlerna run
orlerna exec
-
✅ Support documentation generation
With e.g.
lerna run docs
orlerna exec -- gulp docs
-
✅ Support UI style guide generation
With e.g.
lerna run styleguide
orlerna exec -- gulp styleguide
-
✅ Ability to use Semantic Release in distribution
-
✅ Ability to use Commitizen in development
-
✅ Ability to use Greenkeeper for dependencies
Only for top level
package.json
, not individual modules. But note this may more appropriately be a feature for Greenkeeper to support. -
✅ Sufficiently documented
Good documentation for getting started and a little beyond, not great yet
-
✅ Community Activity
Some community posts, active on GitHub
- Has required configuration file created by
lerna init
- Can use custom project structure
- Seems to support non-master branches with
--since
flag - Builds in debugging with
--loglevel
andlerna-debug.log
- Has
import
command for combining previously separated repos into a monorepo - Has a number of additional configurations, commands, options, and flags that may be useful
Score: 20/20
Perhaps unsurprisingly, Lerna did the best at meeting the qualifications, although Northbrook has appealing simplicity and flexibility and Rush's relatively safer strategy for sharing NPM dependencies and ability to deterministically install and to pin dependencies stood out. Lerna used with Yarn and Yarn Workspaces seems equal to Rush in these respects.
-
✅ Supports both NPM and Yarn
-
✅ Build one, some, or all modules
With e.g.
nb --only moduleOne,moduleTwo exec -- npm run build
-
✅ Test one, some, or all modules
With e.g.
nb --only moduleOne,moduleTwo exec -- npm run test
-
✅ Distribute one, some, or all modules
Seems to have both fixed and independent options. With e.g.
--comver
is default, independent presumably via--semver
With e.g.nb release --only moduleOne,moduleTwo
also supports detecting changes. -
✅ Distribute arbitrary bundles
With e.g.
nb release --only=bundleOne
-
✅ Run arbitrary commands and tasks for one, some, or all modules
With e.g.
nb --only moduleOne,moduleTwo exec -- {{whatever}}
-
🔲 "Share" dependencies across modules safely
Supported with package.json in root and plugin system. Result should be similar to Lerna, however.
-
✅ "Pin" common dependencies across modules
Can use normal NPM install with shrinkwrap/package-lock or Yarn.
-
✅ "Link" module-to-module dependencies safely
With e.g.
nb link
-
✅ Install unique dependencies for individual modules
With e.g.
nb exec -- npm install
-
🔲 Distribute to a pre-release channel
Possibly as arbitrary command, otherwise appears unsupported.
-
🔲 Parallelization of tasks
Not mentioned anywhere, so appears unsupported.
-
✅ Support changelog generation
Users can generate from
nb commit
format, write custom plugins, etc. -
✅ Support documentation generation
With e.g.
nb exec -- npm run docs
or write a plugin. -
✅ Support UI style guide generation
With e.g.
nb exec -- npm run styleguide
or write a plugin. -
✅ Ability to use Semantic Release in distribution
Doesn't appear to be any existing integration, could write a plugin. Unclear if you could replace
nb release
. -
✅ Ability to use Commitizen in development
Doesn't appear to be any existing integration, could write a plugin (or just use alongside?). Unclear if you could replace
nb commit
. Unclear how a non-conventional commit format would impactnb release
. But it passes because it does support plugins and by-module tasks, meaning tooling around the related areas will be easier. -
✅ Ability to use Greenkeeper for dependencies
Only for top level
package.json
, not individual modules. But note this may more appropriately be a feature for Greenkeeper to support. -
🔲 Sufficiently documented
Enough documentation for basics, but not quite good yet.
-
🔲 Community Activity
No community posts found, some activity on GitHub.
- Has a required configuration file & manifest
- Can use custom project structure
- Supports non-master branches with
--release-branch
flag - Builds in
--debug
- Extensible, plugin oriented architecture
- Based on a tool for making composable command line apps
Score: 15/20
Northbrook's design is really appealing to me personally, but as it is mostly an orchestrator of plugins and I'd rather use Semantic Release and Commitizen directly for functionality like nb release
and nb commit
the appeal over Gulp is mostly in nb exec
and nb link
. Its relatively lower profile in the community in comparison to Lerna is also, unfortunately, persuasive.
-
🔲 Supports both NPM and Yarn
NPM only for now, though it's worth noting that Rush claims to be able to deterministically install NPM dependencies, which is one of Yarn's major benefits.
-
✅ Build one, some, or all modules
User defines NPM
test
script, Rush assumes it builds and tests. With e.g.rush rebuild --to moduleOne --to moduleTwo
-
✅ Test one, some, or all modules
User defines NPM
test
script, Rush assumes it builds and tests. With e.g.rush rebuild --to moduleOne --to moduleTwo
-
✅ Distribute one, some, or all modules
Change detection based with
rush change
andrush publish
. Unclear if able to force changes. Maybe always usingrush publish --include-all
could simulate fixed versioning? -
✅ Distribute arbitrary bundles
Probably, with a
bundleOne
module and above. -
🔲 Run arbitrary commands and tasks for one, some, or all modules
Can still set up tooling and run commands normally, but doesn't assist with by-module tasks.
-
✅ "Share" dependencies across modules safely
Supported with implicit pinning during
rush install
. Unclear if or how a rootpackage.json
is handled. -
✅ "Pin" common dependencies across modules
With
rush generate
it makes installs deterministic. Also has a manual pinning option. -
✅ "Link" module-to-module dependencies safely
With e.g.
rush link
-
✅ Install unique dependencies for individual modules
Happens during
rush install
. -
✅ Distribute to a pre-release channel
At minimum, can make pre-release versions with
--prerelease-name
flag. -
✅ Parallelization of tasks
Supported and has
--parallelism
flag. Also does subset builds, provides incremental through optional Gulp integration. -
✅ Support changelog generation
It appears so, how is unclear; seems to have to do with
rush change
. Thenrush publish
will automatically generate one according to docs. -
🔲 Support documentation generation
It appears it might have an "AEDoc" (API Extractor) integration. But would have to set up custom in project root, and Rush doesn't assist with by-module tasks.
-
🔲 Support UI style guide generation
Would have to set up custom in project root, and Rush doesn't assist with by-module tasks.
-
🔲 Ability to use Semantic Release in distribution
Would have to set up custom in project root, and Rush doesn't assist with by-module tasks. Also unclear if you could replace
rush publish
. -
🔲 Ability to use Commitizen in development
Doesn't appear to be any existing integration, could just use alongside? Not marking because it's unclear if it's possible to integrate with
rush publish
changelog, which would add complication since Rush doesn't assist with by-module tasks. -
✅ Ability to use Greenkeeper for dependencies
Not checked because it's unclear if or how a root
package.json
is handled. As with the others, can't use for individual modules. But note this aspect may more appropriately be a feature for Greenkeeper to support. -
🔲 Sufficiently documented
Okay documentation, have to fill in with CLI
-h
. Missing some critical parts aboutrush change
, etc. -
🔲 Community Activity
No community posts found, some activity on GitHub
- Has a required configuration file & manifest
- Can use custom project structure
- Supports non-master branches with
--target-branch
flag - Builds in
--debug
- Has some enterprise-targeting features that might be useful
- Rush is at its most robust if you use their optional Gulp plugins
Score: 12/20
At first, I thought I'd end up favoring Rush because of how well their doc explained the underlying functionality of rush install
. But I couldn't find some relevant and clearly necessary-to-me docs about how rush change
works; on the test repo I always got output that No change file is needed.
Combined with a lack of findable posts from developers that becomes a bigger issue. Side-by-side with Lerna its appeal is mainly its use of safer linking and some of the more enterprise features.
- https://www.npmjs.com/package/zelda
- https://github.com/whoeverest/wsrun
- https://github.com/JamieMason/syncpack
- https://github.com/guigrpa/oao
- https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/
- https://github.com/boennemann/alle
- https://gist.github.com/nolanlawson/457cdb309c9ec5b39f0d420266a9faa4
- https://github.com/boltpkg/bolt
Finally, here's a presentation I gave on how I'm using Lerna monorepos for Design Systems.
The Gist talks only about JavaScript-specific tools