Tool Kit is modern developer tooling for FT.com repositories. It's fully modular, allowing repos that need different tooling to install separate plugins that work consistently together.
Tool Kit has been created to enable the FT.com development workflow and only handles common tooling use cases that are required for most apps to work. Tool Kit sets up the minimal configuration for third party packages to run.
Your application does not need to use Tool Kit for all of its tooling and tooling not supported by Tool Kit can be configured directly in your application.
Tool Kit follows a set of principles that guide its development.
For general questions about using Tool Kit please see the Tool Kit FAQs.
For an empty repository (containing at least a valid package.json
), or to migrate an existing repo from n-gage, you can run the interactive Tool Kit init script:
npm init @dotcom-tool-kit
See the migration guide for a full explanation of what this script does.
Install the core of Tool Kit as a devDependency
:
npm install --save-dev dotcom-tool-kit
On its own, Tool Kit doesn't do anything, so you'll need to install some plugins to give it functionality. For example, if you want to run Jest tests with npm run test
via Tool Kit, you can install the jest
and npm
plugins:
npm install --save-dev @dotcom-tool-kit/npm @dotcom-tool-kit/jest
Add a .toolkitrc.yml
to the root of your repository to include these plugins:
plugins:
- '@dotcom-tool-kit/npm'
- '@dotcom-tool-kit/jest'
Every time you change your .toolkitrc.yml
, e.g. adding or removing a plugin, you should tell Tool Kit to install configuration files in your repository:
npx dotcom-tool-kit --install
If your project already has a .toolkitrc.yml
file you can add a new plugin to it by following the steps in the README for that plugin.
At any time you can run npx dotcom-tool-kit --help
to review the full list of hooks and tasks configured in your project.
You can see the list of all available hooks and tasks provided by Tool Kit in the FAQs.
You don't run Tool Kit directly; you run plugin tasks using things like npm scripts, automatically configured in your package.json
by Tool Kit. With the npm
and jest
plugins installed, Jest tests are run with the npm test
script:
npm run test
At any time, you can run --help
to see what plugins you have installed, what configuration files they're managing, and what tasks you can run with them:
npx dotcom-tool-kit --help
Tool Kit is a fully modular set of developer tooling. Not every project requires the same tooling, so to make sure different projects only have to install and configure what they need, Tool Kit is made up of several plugins that you can install separately to provide different groups of functionality, like the npm
plugin, which lets Tool Kit manage things like package.json
scripts.
This means a project that uses Jest for its tests can install the jest
plugin, and a project using Mocha can install the mocha
plugin, and be able to run them consistently anywhere they're needed, e.g. the npm run test
script. Plugins can depend on other plugins, so we can also publish plugins like frontend-app
that bundle up most of the tooling you'll need into a single package.
And if there's something you want to use in your repo that's not yet supported by Tool Kit, you can write a custom plugin so it can work consistently with any officially-supported tooling.
Plugins provide tasks, which provide the code for running external tooling, and hooks, which manage configuration files in your repo that will be running tooling.
A task is a lightweight abstraction for running some tooling from outside of Tool Kit. Tasks are written in TypeScript, so we can make use of modern Javascript-based tooling and libraries, easily provide structured logging and actionable error messages, and debug them more easily than things like Bash scripts.
An example of a task is JestLocal
from the jest
plugin, which abstracts running Jest tests in a local development environment. Some tasks support configuration. This doesn't replace any native configuration that tooling might have (like a jest.config.js
).
A hook is the glue between configuration in your repo that will be running Tool Kit and the tasks themselves. Things like scripts in package.json
or jobs in your CircleCI config can be automatically managed and kept consistent by hooks.
For example, the test:local
hook in the npm
plugin ensures the test
script is defined in package.json
to run dotcom-tool-kit test:local
, then any tasks that are configured to run on test:local
will be run when you run npm run test
.
Plugins can set a default hook for their tasks to run on; for example, the JestLocal
task runs by default on the test:local
hook. If you've got multiple tasks trying to run on the same hook by default, you'll need to configure which you want to run.
Hooks are there to be installed in your repository. Hook classes contain an install
method that updates the relevant configuration files to run that hook. This install
method is called when you run npx dotcom-tool-kit --install
. This lets Tool Kit plugins automatically manage files like package.json
or .circleci/config.yml
. Any changes made by hook installation should be committed.
When Tool Kit starts up, it checks whether the hooks in your plugins are correctly installed, and will print an error if they're not. This prevents repos from getting out of sync with what Tool Kit expects, ensuring repos are fully consistent and controlled by Tool Kit plugins.
The .toolkitrc.yml
file in your repo determines everything about how Tool Kit runs in that repo. It controls what plugins are included (which determine what hooks and tasks are available), gives you fine-grained control over what tasks are running on what hooks, and lets you provide options to plugins.
An example .toolkitrc.yml
might look like:
plugins:
# provides the test:local hooks
- '@dotcom-tool-kit/npm'
# provides the JestLocal task
- '@dotcom-tool-kit/jest'
# provides the Eslint task
- '@dotcom-tool-kit/eslint'
hooks:
# run both Jest and ESlint when running `npm run test`
# required to resolve the conflict between their defaults
test:local:
- Eslint
- JestLocal
options:
# ESlint plugin needs to know which files to run ESlint on.
# there's a default setting, but your repo might need something else
'@dotcom-tool-kit/eslint':
files:
- server/**/*.js
The options available for each plugin are documented in their readmes. If the tooling that a plugin is using has its own method of configuration (like .eslintrc
, .babelrc
, jest.config.js
, webpack.config.js
), Tool Kit options aren't used for that; they're not merged with that config and don't replace it. Tool Kit options are only for things that need to be known to run the tooling in the first place, or where tooling doesn't provide its own configuration.
Tool Kit is organised as a monorepo with all the different plugins and libraries stored in a single repository. This allows us to quickly investigate and make changes across the whole codebase, as well as making installation easier by sharing dependencies. See the developer documentation for a full explanation of the internal architecture of Tool Kit.
Release versions are not kept in sync between the packages, as we do not want to have to a major version bump for every package whenever we release a breaking change for a single package.
We use release-please to manage releases and versioning. Every time we make a merge to main, release-please checks which packages have been changed, and creates a PR to make new releases for them. It uses the Conventional Commits standard to determine whether updates require a patch, minor, or major version bump, and we use commitlint to enforce the standard in all of our commits.
This means you should make an effort to think carefully about whether the changes you're making are a new feature or bug fix, and whether they contain any breaking changes. This might seem burdensome at first but it's good practice to make sure you can predict whether other teams' builds are going to break because of your code changes! If your commit will only affect a single package then please also include the name of the package (without the @dotcom-tool-kit
namespace) in the scope of your commit message, as this makes it easier to see where changes are being made just by a quick glance at the git log. For example, a commit message for a new feature for the circleci
plugin might look like:
feat(circleci): add support for nightly workflows
Note that new plugins should be created with a version number of 0.1.0
. This indicates that the package is still in the early stages of development and could be subject to many breaking changes before it's stabilised. Committing breaking changes whilst your package is <1.0.0
are treated as minor bumps (0.2.0
) and both new features and bug fixes as patch bumps (0.1.1
.) When you're ready, you can release a 1.0 of your plugin by including Release-As: 1.0.0
in the body of the release commit.