clark
Monorepo tools
Clark is a toolkit for interacting with alle-inspired monorepos. This is a productization of practices found in PouchDB, the Cisco Spark JavaScript SDK, and other monorepo projects.
Table of Contents
Install
npm install @ianwremmel/clark
Usage
Unlike lerna or similar tools, clark
lets you keep track of your dependencies all in your main package.json
(key benefits being significantly faster npm install
times and the ability to use greenkeeper). In order to get this benefit, however, you'll need to follow one of two patterns (alle or non-alle, described below). Once you pick one of those patterns and configure your repository accordingly, you can use clark hoist
, to move your deps from you individual subpackages to your repo root.
Alle
Alle was originally described as just an example of how things could work, before eventually being enacted by pouchdb. In order to follow the Alle pattern, all of your package must be kept in ./packages/node_modules
and the name of each package.json
should match the subfolder path (yes, this includes the org/user scope if present).
Benefits
- Alle is symlink free. It relies on the behavior of
require()
inside anode_modules
directory to search both up the tree and in sibling folders, thus letting your packages find each other automatically.
Caveats
- Many tools have hardcoded excludes for
node_modules
and some can't be overridden at all. Perhaps most problematically, GitHub PR will collapse most of your diffs assuming that anything innode_modules
is vendored. GitHub language stats also get confused. - If you already have an established project, moving every folder can be problematic.
Non-Alle
When npm encounters a package version that's simply a file path (e.g. "my-package": "file:./packages/my-package"
), it will symlink it into ./node_modules
. By putting all of our local node_modules in the top-level package.json
, we can expose our local packages to each other without making any other repo changes.
In addition to moving dependencies to the top-level, if
clark
sees your in a non-alle monorepo, it will automatically add the localfile:
entries to the top-level as well. You may want to run hoist whenever you create a new package.
Simply add your package directories the include
section of .clarkrc
.
//.clarkrc
{
"include": ["frontend/*", "backend/*"]
}
Benefits
- No need to move anything in your existing project.
- Doesn't break GitHub.
Caveats
- Not yet tested in the wild.
- Likely requires a very recent version of npm. (Though, clark requires node 8 or later, so this may not be an issue).
Commands
clark deps:generate
clark exec COMMAND
clark help [COMMAND]
clark hoist
clark init
clark list
clark run SCRIPT
clark deps:generate
Generate package depencies
USAGE
$ clark deps:generate
OPTIONS
-p, --packageName=packageName The package for which to generate dependencies. May be specified more than once
-s, --silent Indicates nothing should be printed to the stdout
--fail-fast Alias of --failFast
--failFast Stop on first failure
--package=package alias of --packageName
--package-name=package-name alias of --packageName
ALIASES
$ clark deps:generate
See code: src/commands/deps/generate.ts
clark exec COMMAND
Execute a command in each package directory. Note: commands with spaces and pipes are supported, but must be wrapped in quotes.
USAGE
$ clark exec COMMAND
OPTIONS
-p, --packageName=packageName The package against which to run this command. May be specified more than once.
-s, --silent Indicates nothing should be printed to the stdout
--fail-fast Alias of --failFast
--failFast Fail as soon as a command fails, rather than running all to completion
--package=package alias of --packageName
--package-name=package-name alias of --packageName
See code: src/commands/exec.ts
clark help [COMMAND]
display help for clark
USAGE
$ clark help [COMMAND]
ARGUMENTS
COMMAND command to show help for
OPTIONS
--all see all commands in CLI
See code: @oclif/plugin-help
clark hoist
Migrate dependencies and dev dependencies from a sub package to the root package.json
USAGE
$ clark hoist
OPTIONS
-p, --packageName=packageName The package against which to run this command. May be specified more than once.
-s, --silent Indicates nothing should be printed to the stdout
--fail-fast Alias of --failFast
--failFast Fail upon encountering a package that cannot be hoisted, rather than running all to
completion
--package=package alias of --packageName
--package-name=package-name alias of --packageName
--risky Indicates if clark should attempt to reconcile semver mismatches.
See code: src/commands/hoist.ts
clark init
Create a .clarkrc file in your project root
USAGE
$ clark init
OPTIONS
-f, --force Overwrite .clarkrc with new config
-s, --script=script Identifies a script to add to the config file
See code: src/commands/init.ts
clark list
List all packages
USAGE
$ clark list
See code: src/commands/list.ts
clark run SCRIPT
Runs a script in each package directory. This is different from exec
in that scripts should be defined in .clarkrc and may be overridden on a per-package basis via npm scripts. npm scripts defined only in subpackage package.jsons can be run this way, but only scripts named in .clarkrc will populate the help output.
USAGE
$ clark run SCRIPT
OPTIONS
-p, --packageName=packageName The package against which to run this command. May be specified more than once.
-s, --silent Indicates nothing should be printed to the stdout
--fail-fast Alias of --failFast
--failFast Fail as soon as a command fails, rather than running all to completion
--package=package alias of --packageName
--package-name=package-name alias of --packageName
See code: src/commands/run.ts
Maintainer
Contribute
PRs Welcome
Development
Use ts-node
to test your changes without rebuilding
ts-node ./src/cli.ts --help
License
MIT © Ian Remmel 2018 until at least now