3

Editor's note: The question's original title was "Use npm install to install node modules stored on a local directory", which made the desire to transparently redefine the installation source less obvious. Therefore, some existing answers suggest solutions based on modifying the installation process.

I know this is a simple thing, but I'm quite new to anything in this area so after searching around and constantly finding answers that weren't really what I want I figured I'd just ask directly.

I currently have a process that is run in directory FOO that calls npm install. Directory FOO contains a package.json and a npm-shrinkwrap.json file to specify the modules (bluebird, extend, and mysql in this case but it doesn't really matter) and versions. This all works perfectly fine.

But now instead of reaching out to the internet to get the modules I want to have them stored in local directory BAR and have the process in foo use npm to install them from there. I can not store them permanently in FOO but I can in BAR for reasons outside my control. I know this is relatively simple but I can't seem to get the right set of commands down. Thanks for the help.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Jedi Wolf
  • 331
  • 3
  • 13
  • I'd like to know this too. I have a jenkins job and I don't want to download all my npm dependencies from the internet every time. I want them in one local place. Still haven't found a good way to do it. – matmo Apr 15 '16 at 21:01

3 Answers3

2

Note: This answer originally suggested only redefining the cache location. While that works in principle, npm still tries to contact the network for each package, causing excessive delays.

I assume your intent is to transparently change the installation source: in other words: you don't want to change your package, you simply want to call npm install as before, but have the packages be installed from your custom filesystem location, offline (without the need for an Internet connection).

There are two pieces to the puzzle:

  • Redefine npm's cache filesystem location (where previously downloaded packages are cached) to point to your custom location:

    • Note that cached packages are stored in a specific way: the package.json file is stored in subfolder package, and the zipped package as a whole as package.tgz. It's easiest to copy packages from your existing cache to your custom location, or to simply install additionally needed ones while you have an Internet connection, which caches them automatically.

    • For transparent use (npm install can be called as usual):

      • By setting the configuration item globally:
        • npm config set cache '/path/to/BAR'
        • Note that this will take effect for all npm operations, persistently.
      • Via an environment variable (which can be scoped to a script or even a single command):
        • export npm_config_cache='/path/to/BAR'
        • npm_config_cache='path/to/BAR' npm install
    • Ad-hoc use, via a command-line option:
      • npm install --cache /path/to/BAR
  • Force npm to use cached packages:

    • Currently, that requires a workaround via the cache-min configuration item.
    • The trick is to set cache-min to a very high value, so that all packages in the cache are considered fresh and served from there:
      • For transparent use (npm install can be called as usual):
        • By setting the configuration item globally:
          • npm config set cache-min 9999999999
          • Note that this will take effect for all npm operations, persistently.
        • Via an environment variable (which can be scoped to a script or even a single command):
          • export npm_config_cache_min=9999999999
          • npm_config_cache_min=9999999999 npm install
      • Ad-hoc use, via a command-line option:
        • npm install --cache-min 9999999999

Assuming you've set cache-min globally or through an environment variable, running npm install should now serve the packages straight from your custom cache location.

Caveats:

  • This assumes that all packages your npm install needs are available in your custom location; trying to install a package that isn't in the cache will obviously fail without an Internet connection.

  • Conversely, if you do have Internet access but want to prevent npm from using it to fetch packages - which it still will attempt if a package is not found in the cache - you must change the registry configuration item to something invalid so as to force the online installation attempt to fail; e.g.:

    • export npm_config_registry=http://example.org
    • Note that the URL must exist to avoid delays while npm tries to connect to it; while you could set the value to something syntactically invalid (e.g., none), npm will then issue a warning on every use.

Sample bash script:

#!/usr/bin/env bash

# Set environment variables that set npm configuration items to:
#  - redefine the location of the cache folder
#  - make npm look in the cache only (assuming the packages are there)
# Note that by doing this inside a script the changes will only take effect
# in the script and NOT persist.
export npm_config_cache='/path/to/BAR' npm_config_cache_min=9999999999

# Now cd to your package and invoke `npm install` as usual.
cd '/path/to/project'
npm install
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • This seems to be what I am looking for (sorry if the question wasn't super clear). Does appear to be a little more complex then I figured it was. If I redefine the cache for this would that effect npm used somewhere else? (So I do this, then later someone is doing something in a third directory where they need to do a quick one time npm install to do whatever. Would they have an issue or would the cache change only take effect for this script, assuming I put it in the script?) – Jedi Wolf Apr 16 '16 at 19:36
  • 1
    @JediWolf: If you change the npm configuration items _globally_ (with `npm config set ...`, then, yes, all future `npm` operations are affected. If that's undesired, use either the command-line parameters or use environment variables _inside a script_ - please see my update. – mklement0 Apr 16 '16 at 19:53
  • I set this all up and it seems to work, but if I set the cache directory to something that doesn't exist npm still installs the files. So does it just go to the internet if it cant find the files in the cache directory, or am I doing something wrong? – Jedi Wolf Apr 18 '16 at 16:14
  • 1
    @JediWolf. Yes, `npm` will still go online if the cache doesn't contain the package - in the absence of bona fide offline installation feature, this is how it works. I've updated the answer with a workaround. – mklement0 Apr 18 '16 at 16:37
  • Ok thanks again, sorry I keep thinking of things I didn't fully specify in my original question. I was trying to use the incorrect directory as a simple check to make sure its working (if it failed with the wrong directory but worked with the right one and such). Would there be a simple way to make sure its working (getting files from local directory?) I don't necessarily need to cut off internet access for npm, just was making sure I had done everything correctly. – Jedi Wolf Apr 18 '16 at 17:08
  • @JediWolf: Just disconnect from the Internet (disconnect from Wifi temporarily or pull the Ethernet plug) and run the installation. Assuming all packages are in the cache, it should succeed. – mklement0 Apr 18 '16 at 17:16
1

You might want to try npm link. You could:

  1. download the dependency
  2. run npm link from the dependency's directory
  3. run npm link mycrazydependency from you project

Detail here: https://docs.npmjs.com/cli/link

mklement0
  • 382,024
  • 64
  • 607
  • 775
linuxdan
  • 4,476
  • 4
  • 30
  • 41
  • I think the OP's intent is to _transparently_ change the installation source, without having to modify the package. – mklement0 Apr 16 '16 at 13:41
0

If a shrink wrap file is present then package.json is ignored. What you need to do is change the URL they are being retrieved from using a find and replace operation like sed .... However I'm not sure changing the URL to a file:/// syntax is valid but give it a go.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
danday74
  • 52,471
  • 49
  • 232
  • 283