Reproducible tooling & configuration
Northbrook is a bridge between the Node Package Manager (NPM)
and your terminal. Northbrook orchestrates plugins
to help you
manage your projects, including multi-package projects (monorepos). It does so
with Reginn
dynamically adding to the
command line interface.
Leveraging NPM allows users to install plugins that setup or manage all parts of
your applications lifecycle from scaffolding to releasing.
Configured through a simple JavaScript file, you
can npm install
other configurations for reuse or extension across any project!
# with npm
npm install --save-dev northbrook
# with yarn
yarn add --dev northbrook
Join us on gitter !
This is a passion project, and as such it's too easy to write documentation that assumes knowledge that perhaps only core contributors have. A real goal of the project is to make as many user's lives as easy as possible and documentation is paramount to that goal. Please, if you see something that isn't documented, isn't clear, or just plain sucks, open an issue! Let us know! Better yet, your contribution as a pull request would be graciously welcomed!
Building Community around a project is so important for the longevity of a project. We want to personally state that everyone is welcome here, and any misconduct will not be tolerated. Your contributions in the form of bug reports, pull requests, and feature requests are vital and I want to hear them all, don't be shy. :smile:
Please be mindful that this is an open-source project developed only on the free time of it's contributors. We want to help, but time is a precious thing, so please be understanding and sensitive to these types of circumstances.
Northbrook does not do very much out of the box other than orchestrate plugins, but it does have some configurable CLI flags that make using Northbrook just a bit easier.
--only, -o
Execute plugins only in specific packages
# run northbrook exec only in packageA
northbrook --only packageA exec -- npm install
--config, -c
Explicitly define where to look for a northbrook configuration file.
northbrook --config .config/northbrook.production.js
--debug, -d
Turn on a debug mode, where Northbrook will print to the console more
information about what it is doing to orchestrate your plugins. Useful to find out
how Northbrook operates, and for debugging errors that may be occuring.
Northbrook introduces a single file to use to configure how Northbrook works, out
of the box, if the defaults work for you, you shouldn't have to even touch a configuration file.
If you need to tweak some things, add or configure new plugins, this is where that
can be done. By default this configuration file should be named either
northbrook.js
or northbrook.ts
if TypeScript is for you. Throughout the
documentation these two files will used interchangably but rules or
guidelines that apply to one apply to all Northbrook configurations.
// as a TypeScript interface
interface NorthbrookConfig {
packages?: Array<string>;
plugins?: Array<string | App | Command>;
}
By default, and if no packages
are defined, just the project-level package will be
used as the only package. Likely you will never need to use the field unless you plan to develop
more than one package in a monorepo. If you are developing a monorepo see more
documentation on packages for monorepos here.
By default, and if no plugins
are defined, a set of default plugins will be
imported and used from northbrook/plugins
. The next section will go further in
depth about plugins.
Plugins are used to introduce new functionality to Northbrook, as a matter of fact, Northbrook does very little other than facilitate the creation and management of plugins. Plugins can introduce tools to transpile your source code, to help you get started with testing, build documentation, or anything that can be done with node.js. Some examples may be
As a general philosophy Northbrook likes to follow, it is encouraged that
plugins should not introduce configuration into a northbrook.js
that
is already covered by other mechanisms. For instance, a plugin for Babel has no
need to introduce a way to configure Babel plugins since there already exists a
.babelrc
to do just that. The same goes for a plugin for TypeScript as
tsconfig.json
already exists to configure how to build your projects. This is
especially important when it come to editor integrations that already exist using
these files, no need to duplicate work!
Configuring plugins should look like this
// northbrook.js
const typescriptPlugin = require('some-typescript-plugin');
module.exports = {
plugins: [
'northbrook/plugins', // leave it to northbrook to do the require()ing
typescriptPlugin, // a plugin can be user-required
'tslint'
]
}
// northbrook.ts
export = {
plugins: [
'northbrook/plugins',
'typescript',
'tslint'
]
}
Plugins can either be a require()
-able string or in the form of a Reginn
App or Command.
By default northbrook/plugins
will be used if no configuration is applied.
For information about the default plugins or creating plugins please see
PLUGINS.md.
The design of Northbrook is agnostic to the number of packages that you need to manage. This means, that you can just as easily use it to manage a single package or a monorepo with 100+ packages and share the same benefits.
Northbrook has been designed to allow plugins to move your devDependencies to the top-level. Allowing for a dependency like TypeScript to be installed 1 time and used for all managed packages. This could help cut the build time for your projects to focus on the important stuff, tests!
Benefits:
Just like dependencies, configurations are now allowed to exist at the top-level
to only be configured once when it makes sense. Configurations such as a
tsconfig.json
can be declared once at the root level, and reused across all
of your package. These leads to less duplication and configuration.
When developing a monorepo, you will need to interact with a northbrook.js
configuration file to setup where to look for each packages. Each package is
to be defined as a relative path to it.
//northbrook.js
// commonjs
module.exports = {
packages: ['relative/path/to/packageA', 'relative/path/to/packageB']
}
Additionally, if you have many packages co-located in a specific folder, it is
possible to use a short-hand syntax /**
to automatically find all packages in a directory.
module.exports = {
packages: ['relativePath/**']
}
It is important to note that this syntax is not recursive and will only look for packages at the top-level of the relative path.