253

Is there a way to get npm to unbuild all the modules under node_modules? Something like npm rebuild that removes all build artifacts but doesn't rebuild them?

swaplink
  • 43
  • 2
  • 8
Dave Causey
  • 13,098
  • 7
  • 30
  • 26
  • Could you elaborate on why you need to do this? – Joe Friedl Jul 05 '12 at 20:08
  • 4
    Thought you'd never ask. I've been checking my node_modules directory into git as recommended in http://www.mikealrogers.com/posts/nodemodules-in-git.html. When I add a new module or update a current one, I end up with build artifacts in git that shouldn't be there and have to clean them up. I was thinking if I could clean them first the process would go a little more smoothly. – Dave Causey Jul 05 '12 at 20:24
  • 1
    One quick note: now that NPM supports `shrinkwrap` (see http://npmjs.org/doc/shrinkwrap.html), you can lock the versions of ALL your dependencies (instead of just the top level ones). – Michelle Tilley Jul 05 '12 at 22:39
  • Thanks for `shrinkwrap`, this would help me solving some issues ! – Adrien Schuler Jul 06 '12 at 10:32
  • @BrandonTilley That's an improvement. However, you're still at the mercy of the online availability of npm. Perhaps a better solution would something like **npmbox** or **Sinopia**. – VitalyB Apr 20 '14 at 15:42
  • 2
    Not having this feature sucks for cross platform development as well. We develop on Mac and run CI on Linux, and need to remove the node_modules directory and completely re-install each time we do a build on Linux, which wastes a ton of time. – JBCP Aug 15 '14 at 16:45
  • 7
    @JBCP you're doing it wrong. What you should be doing is installing modules in `packages.json` (using `npm --save`) and putting the `node_modules` directory in `.gitignore` (if using **git**). CI should not pull your node_modules, but execute `npm install`. Finally, if downloading from npm registry takes too long, use something like [sinopia](https://www.npmjs.com/package/sinopia) to cache it. – Bojan Markovic Jul 01 '15 at 07:28
  • 1
    @BojanMarkovic - You are correct, this is how our projects are setup now. My comment above was from about a year ago. There are (were) a few projects that recommended committing node_modules into Git, but that is definitely not correct. – JBCP Jul 02 '15 at 16:52

11 Answers11

201

You can just delete the node_module directory

rm -rf node_modules/
Charles
  • 11,367
  • 10
  • 77
  • 114
164

There is actually special command for this job

npm ci

It will delete node_modules directory and will install packages with respect your package-lock.json file

More info: https://docs.npmjs.com/cli/ci.html

FDisk
  • 8,493
  • 2
  • 47
  • 52
  • 11
    Actually if you working with other team members and they updated some dependencies you should always do `npm ci` and not just `npm i`. The main reason that `npm i` also updates the lock file and this is probably that you don't want todo. – FDisk Oct 22 '20 at 06:18
  • The OP didn't specify that they were building a fresh project, so just be careful with this when you are the one doing the updating of dependencies as the only way to update the package-lock file would be to run `npm i`. Its a little misleading because it's called "clean install" but thats not necessarily what it does. Would be better named like rebase or something. If you rely on your project version to be in package.json as well, package-lock doesn't get updated either until you do an `npm i`, though thats not as big of a deal. – Kris Boyd Aug 17 '23 at 16:34
95

I added this to my package.json:

"build": "npm build",
"clean": "rm -rf node_modules", 
"reinstall": "npm run clean && npm install", 
"rebuild": "npm run clean && npm install && npm run build",

Seems to work well.

AdanCabanas
  • 167
  • 14
Lucas
  • 2,514
  • 4
  • 27
  • 37
28

Try https://github.com/voidcosmos/npkill

npx npkill

it will find all node_modules and let you remove them.

npkill

jeckep
  • 2,972
  • 1
  • 14
  • 10
9

You can take advantage of the 'npm cache' command which downloads the package tarball and unpacks it into the npm cache directory.

The source can then be copied in.

Using ideas gleaned from https://groups.google.com/forum/?fromgroups=#!topic/npm-/mwLuZZkHkfU I came up with the following node script. No warranties, YMMV, etcetera.

var fs = require('fs'),
path = require('path'),
exec = require('child_process').exec,
util = require('util');

var packageFileName = 'package.json';
var modulesDirName = 'node_modules';
var cacheDirectory = process.cwd();
var npmCacheAddMask = 'npm cache add %s@%s; echo %s';
var sourceDirMask = '%s/%s/%s/package';
var targetDirMask = '%s/node_modules/%s';

function deleteFolder(folder) {
    if (fs.existsSync(folder)) {
        var files = fs.readdirSync(folder);
        files.forEach(function(file) {
            file = folder + "/" + file;
            if (fs.lstatSync(file).isDirectory()) {
                deleteFolder(file);
            } else {
                fs.unlinkSync(file);
            }
        });
        fs.rmdirSync(folder);
    }
}

function downloadSource(folder) {
    var packageFile = path.join(folder, packageFileName);
    if (fs.existsSync(packageFile)) {
        var data = fs.readFileSync(packageFile);
        var package = JSON.parse(data);

        function getVersion(data) {
            var version = data.match(/-([^-]+)\.tgz/);
            return version[1];
        }

        var callback = function(error, stdout, stderr) {
            var dependency = stdout.trim();
            var version = getVersion(stderr);
            var sourceDir = util.format(sourceDirMask, cacheDirectory, dependency, version);
            var targetDir = util.format(targetDirMask, folder, dependency);
            var modulesDir = folder + '/' + modulesDirName;

            if (!fs.existsSync(modulesDir)) {
                fs.mkdirSync(modulesDir);
            }

            fs.renameSync(sourceDir, targetDir);
            deleteFolder(cacheDirectory + '/' + dependency);
            downloadSource(targetDir);
        };

        for (dependency in package.dependencies) {
            var version = package.dependencies[dependency];
            exec(util.format(npmCacheAddMask, dependency, version, dependency), callback);
        }
    }
}

if (!fs.existsSync(path.join(process.cwd(), packageFileName))) {
    console.log(util.format("Unable to find file '%s'.", packageFileName));
    process.exit();
}

deleteFolder(path.join(process.cwd(), modulesDirName));
process.env.npm_config_cache = cacheDirectory;
downloadSource(process.cwd());
theGecko
  • 1,033
  • 12
  • 22
  • 12
    I find it very strange that such a basic functionality, that is actually recommended by npm, requires a hack to achieve. What does everyone else do? Just ignore the recommendation and use `npm install`? – VitalyB Apr 20 '14 at 08:47
7

npm ci works for this scenario, but only when your package.json and package-lock.json are in sync, which might not always be the case if you have been working on either one to resolve conflicts quickly or are updating on the directory level by removing directories/symbolic links. A comprehensive answer to the question would be this..

  1. Edit the package.json with what ever you want and remove what you dont need.
  2. Generate the package-lock.json like this, npm install --package-lock-only
  3. Run npm ci. This should remove all artifacts and shouldn't rebuild them.
General Grievance
  • 4,555
  • 31
  • 31
  • 45
AvidJoe
  • 596
  • 5
  • 19
6

In a word no.

In two, not yet.

There is, however, an open issue for a --no-build flag to npm install to perform an installation without building, which could be used to do what you're asking.

See this open issue.

qubyte
  • 17,558
  • 3
  • 30
  • 32
5

For windows environment:

"scripts": {
    "clean": "rmdir /s /q node_modules",
    ...
}
Daniel De León
  • 13,196
  • 5
  • 87
  • 72
5

I have added few lines inside package.json:

"scripts": {
  ...
  "clean": "rmdir /s /q node_modules",
  "reinstall": "npm run clean && npm install",
  "rebuild": "npm run clean && npm install && rmdir /s /q dist && npm run build --prod",
  ...
}

If you want to clean only you can use this rimraf node_modules.

404
  • 8,022
  • 2
  • 27
  • 47
Amitesh Singh
  • 162
  • 2
  • 7
1

npm ci

As mentioned by FDisk You can use npm ci to remove node modules folder and re-install npm packages from scratch.

npm prune

Alternatively, you can also use npm prune to remove extraneous packages installed inside your node_modules folder that aren't defined inside the package.json


References:

Gangula
  • 5,193
  • 4
  • 30
  • 59
1

I have done this in my package.json

"scripts": {
"clean": "rm -rf ./node_modules package-lock.json .cache dist && npm i",
}
MKS
  • 11
  • 4