DEV Community

Clay Risser
Clay Risser

Posted on

1000 ways to npm clean

Ok, well there's not really 1000 ways to npm clean, but it certainly feels like it. Below is my journey figuring out the best approach. And yes, I finally stumbled upon the holy grail of npm clean.

SPOILER ALERT: Skip to the last approach if you don't have the patience to read through all of this.

rm -r

Yep, classic Unix commands are probably the easiest way to create an npm clean script. This was my goto for quite a while because it just made sense coming from a Unix world.

It has drawbacks though . . . windows != Unix, so don't expect it to work on windows.

package.json

{
  "scripts": {
    "clean": "rm -rf .cache .tmp lib build"
  }
}
Enter fullscreen mode Exit fullscreen mode

rimraf

So, the solution to a cross-platform npm clean script is rimraf. rimraf was bulit by the creator of npm in 2011 (back in the day when NodeJS was just beginning to gain traction). It works almost like rm -r.

I guess the only drawback is that you have to install it as a dev dependency.

package.json

{
  "scripts": {
    "clean": "rimraf .cache .tmp lib build"\
  },
  "devDependencies": {
    "rimraf": "^2.6.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

clean script

Sometimes your build is so complex you need to describe the process in JavaScript. In this case, building a designated script for cleaning makes sense. If you build it right, you can simply add it to the package.json clean script.

This approach certainly has the drawback of requiring a lot of code for a simple task.

package.json

{
  "scripts": {
    "build": "node tools/build.js",
    "clean": "node tools/clean.js"
  },
  "devDependencies": {
    "fs-extra": "^7.0.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

tools/clean.js

import fs from 'fs-extra';

import path from 'path';async function main() {\
  await clean();\
}

export default async function clean() {
  await fs.remove(path.resolve(__dirname, '../.cache'));
  await fs.remove(path.resolve(__dirname, '../.tmp'));
  await fs.remove(path.resolve(__dirname, '../lib'));
  await fs.remove(path.resolve(__dirname, '../build'));
}

if (typeof require !== 'undefined' && require.main === module) {
  main();
}
Enter fullscreen mode Exit fullscreen mode

tools/build.js

import clean from './clean';async function main() {
  await clean();
  await build();
}

export default async function build() {
  console.log('building something special . . .');
}

if (typeof require !== 'undefined' && require.main === module) {
  main();
}
Enter fullscreen mode Exit fullscreen mode

git clean

So . . . I did promise the holy grail of npm clean. It is probably safe to assume your node project is in a git repo. If it is, why not use git to clean your repo. I stumbled upon this fairly recently, and it is amazing. The .gitignore file already tells me everything I don't want in my repo.

The following command will remove all files from your git repo that are in your .gitignore file.

git clean -fXd
Enter fullscreen mode Exit fullscreen mode

However, when I clean my repo, I don't want to remove all my dependencies in the process. Simply adding !node_modules and !node_modules//* to the exclude flag will keep that folder. It's a double negative. You're basically saying do not exclude node_modules. Make sure you escape the bang so bash can understand it.

git clean -fXd -e \!node_modules -e \!node_modules/**/*
Enter fullscreen mode Exit fullscreen mode

When adding it to our package.json clean script, we have to escape the escape symbol so JSON can parse it, hence it becomes \!node_modules and \!node_modules//*.

The only drawback to this approach is it does not work unless you are in a git repo.

package.json

{
  "scripts": {
    "clean": "git clean -fXd -e \\!node_modules -e \\!node_modules/**/*"
  }
}
Enter fullscreen mode Exit fullscreen mode

If you have used other approaches for cleaning npm repositories, please let me know in the comments.

Top comments (0)