@adlib/cli
Simple, flexible, and sharable project configuration.
- Reduce configuration clutter.
- Tool configuration files (eg. Babel, Webpack) can be copied into your project "just-in-time", and then removed after use.
- Isolate development dependencies.
- Configuration package dependencies are kept outside of your project's resolve paths.
- Simplify configuration creation and sharing.
- Define project initialization and tasks in a simple and friendly YAML file.
- Use configuration packages published to NPM or Git, or just use a local directory to get going fast.
- Meet the needs of any project.
- No preference for any specific tools or build strategies.
- Anyone can create and publish a configuration.
Getting Started
Install Adlib globally. This makes it simple to run Adlib tasks in any project with an adlib configuration.
$ npm add -g @adlib/cli
Add the Adlib configuration to your package.json
file. The config
value can be an NPM package (with optional version range), Git repo URL, .tgz
file (local or remote), or a local directory. The optional pm
value can be set to npm
, yarn
, or omitted for auto-detection.
{
"adlib": {
"config": "@adlib/config-typescript",
"pm": "npm"
}
}
Run the init
task in your project directory to install your chosen configuration and to perform any project "bootstrapping" the configuration may include. This is technically optional because it is done "on-demand" when running all Adlib tasks.
What does the init
task do?
- It installs the
adlib.config
package and its dependencies into the ".adlib/node_modules" subdirectory of your project. These will not be resolvable in your project's source.
- It creates an ".adlib/config" symbolic link to the installed configuration package directory.
- It may (configuration dependent) install new development dependencies in your project. It will not re-add dependencies that already exist. These dependencies may be necessary for tools that your IDE runs in the background (eg. ESLint)
- It may (configuration dependent) inject new top level keys into your project's "package.json" file. It will not modify keys that already exist. This configuration may be necessary for tools that your IDE runs in the background (eg. ESLint), or helpful for adding project configuration which matches the Adlib configuration (eg. the "main" entry in "package.json").
- It may (configuration dependent) copy new files into your project. It will not modify files that already exist. These files may be configuration files necessary for tools that your IDE runs in the background.
Ideally, the configuration package wouldn't need to install dependencies or copy anything into your project, allowing Adlib to completely isolate the dev dependencies and configuration. Unfortunately, this just isn't practical in some cases. So for now, Adlib includes a mechanism to do some project bootstrapping, with the suggestion that it be kept to a minium.
$ adlib init
Run tasks defined by the configuration.
$ adlib <task>
If you don't know the tasks defined by the configuration, you can run the ls
task to list them.
$ adlib ls
Built-in Tasks
Adlib has the following built-in tasks.
adlib help
- Print the Adlib help text.
adlib version
- Print the Adlib version in use.
adlib init
- Restore the configuration.
adlib ls
- List the tasks defined by the configuration.
adlib eject <task>
- Permanently copy a task's "just-in-time" configuration files into your project for customization.
adlib exec <...args>
- Execute an arbitrary command within the configuration context. The process will be able to resolve configuration dependencies and invoke executables locally installed to the configuration.
Optional Setup
Install Adlib as a dev dependency of your project. The globally installed Adlib will always delegate to a locally installed version if it exists. This can be used to "pin" the Adlib version that your project uses.
$ npm add -D @adlib/cli
Adlib itself has no dependencies, and exports nothing, so it won't pollute your project scope.
Create A Configuration
A configuration must have at least two files: package.json
and adlib.yaml
.
The package.json
file is required because Adlib uses npm
internally to get configuration packages. So, Adlib configurations must actually be valid NPM packages. Everything in this file is up to you.
The adlib.yaml
file has the following structure:
init:
copy:
- filename
- from: filename
to: subdirectory/renamed
config:
key: value
install:
- package
- package@^1.2.3
- package@prerelease
tasks:
myTask:
describe: My Task
copy:
- myFile
- from: myFile
to: subdirectory/renamedFile
run:
- echo "quoted argument"
Managing Dependencies
Whenever possible, avoid adding dependencies to the init.install
array in your adlib.yaml
file. Reducing the number of dependencies in target projects should be a top priority.
The unfortunate current exception is usually ESLint (or other linter dependencies), because your IDE will probably need to know about those dependencies in order to provide inline linting hints.
Managing Tool Configuration Files
Use the "just-in-time" feature (tasks.<task>.copy
) whenever possible. It allows target projects to eject configuration files for customization. Many tools will allow you to give an explicit configuration path, which would let you simply target the configuration in the .adlib/config/...
directory. But, this will make it hard for consumers to customize.
If you do need to add permanent configuration to target projects, consider adding it to the target's package.json
using the init.config
map in your adlib.yaml
file. This will keep the file structure of the target project cleaner than copying in configuration files.
Sharing Configurations
Add the adlib-config
keyword to your package and publish it to NPM. Adding this keyword will allow others to find your configuration using the keywords:adlib-config query.
As a best practice, describe the intended use, target environments, and tool-chain in the configuration's README.md
file.