binge
v6.1.1
Published
Tool for managing monorepos with local packages
Downloads
31
Readme
binge - version-less JavaScript package management for monorepos
binge is a version-less JavaScript package management tool for monorepos.
It helps you to:
- achieve a clear separation of concerns through modularization by enabling the quick creation and consumption of local packages
- avoid dependency hell by enforcing dependency version consistency across different local packages
- overcome the publishing overhead of traditional packages by providing version-less local packages that otherwise behave like standalone npm packages. For example, binge supports npm package semantics, which enables custom lifecycle steps like testing, building and linting
Getting started with binge
Install binge by running yarn global add binge
.
Note: binge requires Yarn and doesn't support npm.
Repository structure
You could, for example, structure your repository as follows:
…
- client
- package1
- …
- src
- .babelrc
- .npmignore
- package.json
- yarn.lock
- …
- packageN
- …
- app
- src
- package.json
- …
…
In our simplified example (see: ./examples/watch-app), our client folder contains a root-level folder for each local package.
The app
folder also is the global entry point to (the root of) our app.
Note: binge supports nested local packages. However, we recommend we recommend not to nest too deeply to control complexity and allow a clearer overview. Also, make sure there are no dependency circles between (nested) packages.
Local packages have the same structure as ordinary npm packages, except that they are not versioned.
To include a reference to a local package include it in package.json
as a file reference.
The package.json
in the root folder lists the other local packages as dependencies:
{
"name": "app",
"dependencies": {
"i-filter-stuff": "file:../i-filter-stuff",
"i-provide-text": "file:../i-provide-text"
},
…
}
Of course, you can have multiple entry point packages in your repository and also reference local packages in other local packages that aren't entry points.
To build the app, navigate to the app
directory and run binge bootstrap
.
binge now installs all dependencies in the hoisting location, builds the local packages, connects all bin
folders, and deploys the local packages to the node_modules
folder of the app
directory.
For example, if the app is built with webpack, the build command could be binge bootstrap && webpack
.
To run the app and watch the source files, run binge watch
in the app
directory.
Reference documentation
This section lists and explains all binge commands. You find minimal example apps that illustrate the commands at ./examples.
bootstrap
:Installs, builds and deploys the local package tree. For example, running
binge bootstrap
in ./examples/bootstrap/app:- installs the dependencies of the three local packages
i-filter-stuff
,i-print-stuff
andi-provide-colors
, - builds the three local packages,
- deploys the local packages to the
node_modules
folder of the app directory.
binge bootstrap
bootstraps not only the entry point, but all local packages.Note:
bootstrap
also runscheck
(see below) and fails ifcheck
fails.- installs the dependencies of the three local packages
copy <file> [newName]
:Copies a file into each node of the local package tree, optionally with the newly specified file name. This is helpful to manage configuration file or credentials when preparing production releases. For example, when creating the file
.cred
in ./examples/bootstrap, navigating toapp
and runningbinge copy ../.cred .credentials
, binge copies the file.cred
with the new name.credentials
to the following directories:i-filter-stuff
,i-print-stuff
,i-provide-colors
,root
.
graph
:Prints the package tree and the layer topology (the build order of the nodes). For example, running
binge graph
./examples/bootstrap/app returns:[Binge] Christmas Tree root ├── i-filter-stuff └─┬ i-print-stuff └── i-provide-colors Layers: 1 root 2 i-print-stuff 3 i-filter-stuff 3 i-provide-colors
harmony
:Checks the local package tree for dependency consistency. For example,
binge harmony
returns an error when two local packages contain incompatible version specifications of the same dependency…------------------ | q failed | ------------------ module-a -> 1.5.0 module-b -> 1.5.0 module-c -> 1.5.1 … Error q failed -> [email protected], [email protected], [email protected]
…and a warning when version specifications are inconsistent, but not incompatible:
------------------- | fbjs 0.8.14 | ------------------- module-a -> 0.8.14 module-b -> 0.8.14 module-c -> ^0.8.14 … Warning fbjs 0.8.14 -> [email protected], [email protected], module-c@^0.8.14
binge harmony --fix
harmonizes dependencies across all packages. Updates theyarn.lock
files in the local packages and in the entry point accordingly.harmony --fix
does not updatepackage.json
files. Fixing inconsistencies there requires explicit (manual) action.nuke [target]
:Removes the
node_modules
folders in the local package tree. For example, runningbinge nuke
in ./examples/bootstrap/app deletesnode_modules
folders in the following directories:i-filter-stuff
,i-print-stuff
,i-provide-colors
,root
.
binge nuke target
removes the specified file from all local packages and the root package, analogous tobinge copy
.remove <dependencies...>
Removes one or multiple specified dependencies from the current package. For example, running
binge remove invariant
in ./examples/bootstrap/i-filter-stuff removes the dependencyinvariant
from ./examples/bootstrap/i-filter-stuff/package.json.binge remove --all dependencyName
removes one or multiple specified dependencies from all packages.trace <targetBranch>
:Compares the current branch with the target branch, transitively finding changed files. Outputs the list of affected local packages.
trace
helps optimizing the test set your CI server runs when checking a merge request by considering the packages that changed and the packages that depend on changed packages. If theoutputDirectory
argument is provided, binge adds the following three files to the specified path:karma.txt
: Lists all packages that havetestMode
in the.bingerc
file (see below) set tokarma
.mocha.txt
: Lists all packages that havetestMode
set tomocha
-none.txt
: Lists all packages that havetestMode
set tonone
or no test mode specified.
The contents of these files provide your CI server with more details on which tests it should run.
watch
:Builds and watches the local package tree. You can try out
binge watch
in ./examples/watch-app/app.
Similarly to Lerna, binge hoists dependencies.
This means binge moves shared dependencies up the dependency tree to avoid unnecessary duplication of code.
This process is called hoisting.
The path of the node_modules
folder to which the packages will be installed is called the hoisting location.
To determine the hoisting location, binge starts at the current level of the directory tree and moves upwards until it finds a package root (a directory with a package.json
file) that can reach all packages, including the entry point, both physically and through the dependency graph.
For example, in ./examples/bootstrap the hoisting location of app
will be the root directory, because ./examples/bootstrap/app is only the dependency graph parent of the other local packages, but not their physical parent.
To support proper hoisting, run the following Yarn commands via binge (for example: run binge add left-pad
):
add
,cache-clean
,list
,outdated
,remove
,upgrade
.
Hoisted Yarn Commands follow these steps:
- Hoist
package.json
. - Call Yarn.
- Unhoist
package.json
and apply the resulting dependency delta.
Binge pipes trailing command arguments to Yarn.
For add
and upgrade
, the dependency delta is applied to local packages that have a dependency intersection with the delta.
For example binge add [email protected]
will transitively set the React dependency to 16.0.1
in local packages that depend on React.
The .bingerc
configuration file
Optionally, you can add a .bingerc
configuration file to any package root directory.
This allows you to configure the following settings:
isApp
(Boolean): Specifies if the package is a full app you can run in your browser.scriptBuild
: Overrides the defaultbinge watch
command.scriptWatch
: Overrides the defaultyarn/npm build
command.testMode
(none
,karma
ormocha
): Specifies the test mode to better identify CI-relevant changes (see above;binge trace
).
A .bingerc
file could look like this, for example:
{
"isApp": true,
"testMode": "none",
"scriptWatch": "webpack:watch"
}
Binge vs. Lerna
Lerna is a popular tool for managing JavaScript repository containing multiple packages.
The following table gives an overview of the core differences between binge and Lerna:
| Lerna | binge |Explanation
| --- | --- | --- |
|Versioned packages|Unversioned packages|Lerna requires you to version local packages. While versioning is great for external stakeholders, who install the package via a package manager, binge assumes versioning packages within a monorepo is confusing and source of overhead. This carries even more weight as the monorepo and development team grow in size. Let's look at an example: Package A
, B
, C
are in the same repo. The current versions are A=1
, B=2
C=1
. A
depends on B=1
, C
on B=2
. This means we are currently accumulating technical debt. The desired state is to release a new version of B
that is compatible with both A
and C
. Developers working on C
have the incompatible code of B
checked out (as it's in the same repo) and need to switch to a legacy branch/tag to work on the compatible version of B
.|
|Allows multiple versions of same dependency across packages|Enforces consistent dependency version across packages |binge ensures dependency versions are consistent across your local packages. This reduces the file size of your application and improves the developer experience (developers don't need to worry where in your code version 1.x and where version 2.x of the same library is used).|
|Watches all packages simultaneously|Optimizes watch processes|Lerna watches all of your packages simultaneously, which can result in a large number of concurrent watch processes. binge watches one app at a time and optimizes watch processes by running it only for packages that are affected by recent changes. This frees CPU and RAM resources.|
|Symlinks|No symlinks|Lerna uses symmetric links to reference sub-dependencies. These sub-dependencies can't be de-duped and are not handled consistently to 'normal' dependencies by yarn. For example, yarn list
doesn't consider symlinked sub-dependencies. binge addresses this problem by properly installing sub-dependencies into the node_modules
folder of the global entry point.|
We recommend using Lerna if you need to version your packages for external users, who work outside the context of your monorepo. In contrast, if your packages are primarily used from within your monorepo, we recommend you use binge to avoid the versioning overhead.
Contribution
Contributions are welcome. Make sure you run the tests before creating a pull request and add test cases that cover the contributed code.
To build binge from its source files run yarn run build
.
Execute the tests by running yarn run test
.
Authors
- Cristóvão Honorato - @CristovaoHonorato (architect & maintainer)
- Timotheus Kampik - @TimKam (docs)