Clean up/prune unnecessary files and reduce the size of your
node_modules
directory. Useful for CI caches or for reducing the size of your AWS Lambdas/Azure Functions.
Look, it's yet another node_modules
cleaning tool! There are lots of these around, but I still
found the need to write my own. See the Alternatives section for more details.
This CLI tool combines the features that I could not find in other tools:
- 🧹 Removes directories and files that are unnecessary and safe to remove in production
- 🛠 Easily customizable through glob patterns (either through CLI args or a configuration file)
- 📁 Cleans up empty directories after removing files
- ⚡️ Super fast, but still written in Node
- 🔍 Allows analyzing results, like which pattern excluded which file
clean-modules
can be installed globally if you only want to use it as a CLI tool. You can also
install it locally if you want to use it in a package command.
# npm
npm install -g clean-modules
# yarn
yarn global add clean-modules
Simply run the command in the directory where your node_modules
are:
clean-modules
You can also pass any options that you need, like custom globs or a path to a specific
node_modules
directory.
clean-modules --directory "path/to/node_modules" --include "*.d.ts"
Check out the Options section to see all available options.
The default command, cleans up your node_modules
based on a set of most likely safe glob
patterns and removes empty directories.
clean-modules [options]
string | string[]
Accepts a glob string of files/folders to include that are not included by default. Can be added multiple times or passed multiple strings.
See the glob patterns section for info on how the globs are parsed and what globs are included by default.
Example:
# includes all TypeScript declaration files and @types folders
clean-modules --include "**/*.d.ts" --include "**/@types/**"
# or
clean-modules --include "**/*.d.ts" "**/@types/**"
string | string[]
Accepts a glob string of files/folders to exclude from the list of included files. Excludes files
included by both --include
option and by default. Can be added multiple times or passed multiple
strings.
See the glob patterns section for info on how the globs are parsed and what globs are included by default.
Example:
# excludes all sourcemap files and PNG files
clean-modules --exclude "**/*.map.js" --exclude "**/*.png"
# or
clean-modules --exclude "**/*.map.js" "**/*.png"
string
[default: ./node_modules
]
Accepts a path to a directory to run the script on.
Example:
clean-modules --directory "path/to/custom/node_modules"
string
[default: ./.cleanmodules
]
Accepts a path to a file from which clean-modules should read any custom globs. See the glob patterns section for information about how the glob file works and what patterns work.
boolean
Excludes all default globs, using only custom globs added through the glob file or by the include or exclude options. Useful if you want complete control over what files to include.
See the .cleanmodules-default
to see what patterns are included by
default by default.
boolean
Skips removing empty folders after removing files.
boolean
Runs the script and prints the result without actually removing any files. Does not count the number of removed empty directories.
boolean
Only logs a final JSON dump at the end of the script (useful for logs or services).
boolean
Skips the confirmation prompt at the start of the script.
Compiles a list of all files that would be included by clean-modules
and gives a breakdown of:
- exact file path
- what glob patterns it was included by
- how the patterns were formatted and passed along to
picomatch
- if the file was included by default
clean-modules analyze [options]
Because of the amount of data it can be useful to pipe it somewhere, like:
clean-modules analyze >> clean-modules-result.json
The analyze
command accepts several of the default command's options and applies them in the same
way:
[
{
"filePath": "/Users/me/projects/foo/node_modules/dependency/__tests__/test1.js",
"includedByDefault": true,
"includedByGlobs": [
{
"original": "__tests__/",
"derived": "/Users/me/projects/foo/node_modules/dependency/**/__tests__/**"
}
]
},
...
]
clean-modules accepts globs from either a configuration file (.clean-modules
next to
node_modules
by default) or CLI arguments. It uses
.gitignore
-like glob patterns
that are converted to valid picomatch
globs, which is
what is used to match file paths under the hood.
Differences from regular ignore syntax:
- To include a directory the pattern must end with
/
,/*
or/**
- This is to prevent directories matching common file names from being included by the globs.
- Casing is ignored.
The same type of patterns are accepted by both the --include
/--exclude
arguments and the glob
configuration file.
Like with .gitignore, globs should use forward-slashes as separators on all operative systems (including Windows)!
# this is a comment (starts with a #)
# to include include directories, end patterns with / or /* or /**
dep1/
dep1/*
dep2/**
# files are matched in any directory by default
**/*.test.js
# is the same as
*.test.js
# use a leading / to include a file or directory at a specific place
/dep4/this/specific/directory/**
/dep4/this/specific/file.js
# to exclude a path, prepend it with a !
!/not/this/directory/
!not-me.js
# to use leading exclamation marks without excluding, escape them
\!(*.d).ts
The default globs can be found in the .cleanmodules-default
file. It
only contains inclusions (as exclusions would override custom inclusions) and consists of a large
list of the most common files that are safe to remove.
That said, it's impossible to guarantee that none of the files are needed, and you might need to do custom exclusions depending on what packages you use.
**/*.d.ts
: If you don't use TypeScript. TypeScript declaration files take up a lot of space in yournode_modules
folder, but they are most likely required to build your application. Useful locally even if you don't use TypeScript since they can be parsed by your IDE.
**/*.map.js
: If you are runningclean-modules
locally or need source files in production.clean-modules
removes sourcemap files by default since they take up a lot of space and does not break builds when removed. They can be nice to have though, especially while developing.
The most common issues I found with available tools are:
- They only allow inclusion/exclusion of file names, not file paths. This prevents you from e.g.
excluding subdirectories of a specific folder, like
@types/react-native
. - They include too many, or too few, patterns by default. Lots of them also include patterns like
*.ts
by default, which breaks TypeScript declaration files on build. - They are too slow (only relevant when running on large projects)
- They are abandoned or don't respond to issues.
- ✅ Inclusion/exclusion through file path globs
- ✅ Fast
- ✅ Safe list of files and folders included by default (for production use)
- ✅ Cleans up empty directories
- ✅ Included with Yarn by default
- ✅ Inclusion/exclusion through globs
- ⛔️ Very slow compared to alternatives
- ⛔️ Runs on every install, both locally and in CI
- ⛔️ Small list of files included by default
- ✅ Cleans up empty directories
- ✅ Safe list of files and folders included by default
- ⛔️ Slow, only slightly faster than
yarn clean
- ⛔️ Only allows inclusion/exclusion by file name globs, not file path
- ⛔️ Complains about empty folders that doesn't exist
- ⛔️ Abandoned
- ✅ Fastest option available
- ⛔️ Written in Go and might require separate binary download
- ⛔️ Removes some dangerous files by default (like
.d.ts
files andassets
folder) - ⛔️ Only allows inclusion/exclusion by file name globs, not file path
- ⛔️ Globs are very limited since it uses Go's
filepath.Match
- ⛔️ Does not remove empty folders
- ✅ Fast
- ⛔️ Removes some dangerous files by default (like
.d.ts
files andassets
folder) - ⛔️ Only allows inclusion/exclusion by file name, not file paths or globs
- ⛔️ Does not remove empty folders
- ⛔️ Small list of files included by default