Presetter - Reuse your config files and build scripts over JS projects
Tags: npm, productivity, tooling, showdev
Published: 2021-08-27 10:14:22

Nowadays, as the JS/TS ecosystem continues to mature, developers are writing more and more build scripts and configuration files for their projects. How many times you've copied identical configs for babel, eslint, jest, typescript and the life cycle scripts in package.json?

For me, I've 40 common devDependencies, 24 scripts and 7 config files across my npm projects. Putting the need to copy and paste these things to bootstrap a new project aside, updating these tools across existing projects is just horrible pain. 🤦‍♂️

So I spent my spare time making **presetter**, a utility tool you'd love to use for easily and quickly reusing build scripts/configs across different npm projects. Now, instead of these countless devDependencies, build scripts, and config files, I can reduce them into just 2 devDependencies (or just 1 if you use npm 7+ which auto install peer dependencies automatically) and 1 config file (for presetter to determine which preset to use)!

![Before and After](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9pqxp0f27va7nodj50b.jpg)

## 😀 Sounds good. What is presetter and a preset then?

Presetter is a new open-source project that simplifies workflow for js/ts developers by providing a utility tool to enable us to store all common developmental configurations in one place, not a copy of those on each repo. This allows not only for the reuse of configurations but also reduces time spent on setup and maintaining the build systems across projects. Presetter is written in typescript but compatible with all js packages, backend, or frontend, as long as you use a package.json.

In a nutshell, **presetter** is a utility tool that set up and manage common devDependencies specified by a **preset**, which provides 3 types of common building configurations: devDependencies, build scripts, and config files. With presetter, you can replace many of your common devDependencies like eslint plugins etc and its config files and scripts into only two dev packages and a config file, namely _presetter_, your preset choice, and a `.presetterrc` file.

By pairing them up, you no longer need to spend hours on maintaining the build systems across projects. Instead, simply pick (and customise) a predefined preset either off-the-shelf from the community or an unpublished private package living in your git repository. What's more? You get version control on the build system for free due to the way how a preset is packaged. Life is much simpler since then!

## 😻 Wow. Tell me how to use it

To setup presetter for managing your build system, you can easily achieve it via the `presetter use` command:

```sh
npx presetter use <preset package name e.g. presetter-preset>
```

which would perform the following few things:

1. Install presetter and your choice of preset as devDependencies,
2. Patch the `scripts` field in your `package.json` to enable automatic bootstraping via the `prepare` life cycle script,
3. Bootstrap the preset by installing all the peerDependencies provided by the preset and create symlinks pointing to the generated config files on your project root, and
4. Create a `.presetterrc` file on the project root with the following content

```json
{
  "preset": "<preset package name>"
}
```

![Bootstrap Presetter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36m9ul90iw67t6h2tig9.gif)

After starting the project through bootstrapping, you have reached a point where it normally takes 5-10 minutes to duplicate all configuration settings from another repository. Now, you can achieve it by just **ONE COMMAND**!

To apply the preset scripts, you can execute a script by using the `presetter run <script name>` or shorthanded `run <script name>` command.

Using **presenter-preset** for example, when you invoke `run build`, presetter will merge the custom scripts defined in your package.json and the [templated defined here](https://github.com/alvis/presetter/blob/master/packages/preset/templates/scripts.yaml), then invoke `run-s clean build:*`.

**Tips**

You can also use `run <script name>` as part of your life cycle scripts to make your build experience identical to what you have before. For example,

```json
{
"scripts": {
  "build": "run build",
  "coverage": "run coverage",
  "lint": "run lint",
  "prepare": "presetter bootstrap && run prepare",
  "prepublishOnly": "run prepublishOnly",
  "release": "run release --",
  "test": "run test --",
  "watch": "run watch"
 }
}
```

## 👻 BUT. Can I customise it?

Short answer, SURE! You may be just 99% satisfied with the preset and want to change a little thing like turning on/off a lint rule, presetter just get you covered!

To do this, you just need to pass your customised config in the `config` field in `.presetterrc.json`. This config will be passed to the preset's configurator to achieve customisation. After adding your config, run `npx presetter bootstrap` again to regenerate the config files.

For example, to add `DOM` as a library in tsconfig.json provided by **presetter-preset**, simply add these lines in your `presetterrc.json`:

```json
{
  "preset": "presetter-preset",
  "config": {
    "tsconfig": {
      "compilerOptions": {
        "lib": ["DOM"]
      }
    }
  }
}
```

Each preset can have its own set of customizable features. So check the preset's  documentation for a full list of customisable elements.

## 🎩 Cool! What's the magic behind it?

Presetter may sound too good to be true. Now you don't need to copy and paste all the time. But you may wonder how does it work?

Well, it's actually pretty simple. Presetter basically does the following few things.

When you run `presetter bootstrap`, it
* generates config files provided from the preset's template with your customisation applied and create symlinks on your project root, and
* uses npm's arborist to install all peer dependencies defined in the preset's package.json, so that it works even with npm <7.

When you run `presetter run <command>`, it
* merges your project's package.json with the script template provided by the preset and invoke the command.

That's basically all about how preset works. Now, let's see what kinds of presets are available and how to contribute one!

## 🐣 Alright. What presets can I try today?

A preset is a collection of common development configurations that can be applied to a project. It provides 3 groups of common building tools

1. devDependencies,
2. build scripts, and
3. config files

Today, we have 4 official presets for different kinds of projects:

* [presetter-preset-essentials](https://github.com/alvis/presetter/tree/master/packages/preset-essentials): The starter kit for your typescript project, including settings for typescript, eslint, jest, prettier, standard-version and many others
* [presetter-preset-rollup](https://github.com/alvis/presetter/tree/master/packages/preset-rollup): A collection of opinionated configurations for a building a code bundle via rollup.
* [presetter-preset-web](https://github.com/alvis/presetter/tree/master/packages/preset-web): A preset for a modern web project
* [presetter-preset-react](https://github.com/alvis/presetter/tree/master/packages/preset-react): A preset for a react project

Each preset is a single npm package. You can publish yours to share it with the community or just make it as a github repo without publishing it. Both works.

Another thing is that you can also contribute to the official presets. See [CONTRIBUTING](https://github.com/alvis/presetter/blob/master/CONTRIBUTING.md) for all things related to preset's development and contribution!

## 👾 To Conclude...

Now you can stop worrying about managing devDependencies, scripts and config files. Presetter is a tool that reduces the complexity of your build system. 

We all know that duplication of code is a bad thing, and there are many tools to eliminate it, but we don't have a tool for avoiding copying build configuration.

It's time to put the messy build configs aside. Try **presetter** today and visit [the repository on Github](https://github.com/alvis/presetter) for detailed documentation.

Don't forget to star or watch this repo if you like it! And don't forget to leave your comments below too. 👇