Bootstrap

Vue进阶(十):NPM 管理 node.js 依赖

一、前言

是 的模块依赖管理工具。作为开发者使用的工具,主要解决开发 时会遇到的问题。如同 对于 开发者和 对于 开发者的重要性, 对与 的开发者和社区重要性不言而喻。本文包括五部分:

  • 配置;

  • 命令;

  • 命令;

  • 其它 npm 命令。

二、package.json

命令运行时会读取当前目录的 文件,该文件基于 规范。在这个文件里可以定义应用名称( )、应用描述( )、关键字( )、版本号( )、应用配置项( )、主页( )、作者( )、资源仓库地址( )、提交地址( ),授权方式( )、目录( )、应用入口文件( )、命令行文件( )、应用依赖模块( )、开发环境依赖模块( )、运行引擎( )和脚本( )等应用配置信息。

对于开发者而言,开发和发布模块都依赖于对 所包含意义的正确理解。下面用一个例子来说明:

{
    "name": "test",
    "version": "0.1.0",
    "description": "A testing package",
    "author": "A messed author ",
    "dependencies": {
        "express": "1.x.x",
        "ejs": "0.4.2",
        "redis": ">= 0.6.7"
    },
    "devDependencies": {
        "vows": "0.5.x"
    },
    "main": "index",
    "bin": {
        "test": "./bin/test.js"
    },
    "scripts": {
        "start": "node server.js",
        "test": "vows test/*.js",
        "preinstall": "./configure",
        "install": "make && make install"
    },
    "engines": {
        "node": "0.4.x"
    }
}

这个例子定义了应用入口文件( )为 ,当其他应用通过 引用了我们的模块时,这个 的值 文件被调用。脚本( )使用 表定义了几个不同的命令。

里的定义的 会在 时被调用,同样的 调用时对应的 里定义的命令被调用。在有些 模块需要编译的话,可以定义预编译和编译的命令。本例中还定义了应用依赖模块( )和开发环境依赖模块( )。应用依赖模块会在安装时安装到当前模块的 目录下。开发环境依赖模块主要是在开发环境中用到的依赖模块,用命令 或加上参数 将安装到当前模块的 目录下。

大家也注意到 里的版本号有些是 有些是 ,这有什么区别? 使用于语义化的版本识别来进行版本管理。并不是所有的模块都会提供向后兼容性,有时候某些模块因为某些原因导致不向后兼容。所以需要定义一些规则来保证模块能够在某些特定的版本中可用,并且保证能用最新的版本,因为那些版本总是修改了一些 或提升了性能等。我们来看一下版本定义的字段:

0.4.2

  • 主版本( 0 )

  • 副版本( 4 )

  • 补丁版本( 2 )

在上面 的定义里我们确信模块在所有的 及以上和以下版本里都能运行。依赖模块 在所有大于或等于0.6.7的版本上都能运行,依赖模块 只能确保运行在0.4.2版本里,依赖模块 确保能够兼容大于或等于1.0.0并且小于2.0.0。

三、npm 配置

拥有很多默认配置。可以使用这些默认配置,也可以修改这些默认配置,甚至可以在环境变量或命令行下修改这些配置。配置的权重是如下顺序定义的:

  • 命令行,使用为前缀的参数。比如 ,设定变量 的值为 , 后不带值的参数,设定 的值为 。

  • 环境变量,所有 为前缀的环境变量。比如 ,设定变量 foo 为 “ bar "。

  • 用户定义。所有的变量存储在 文件里的变量。

  • 全局。所有 文件里的变量。 变量可通过 获取,一般默认是 。

  • 内置配置。通过安装时运行 所定义的变量。可通过命令 设置。

使用配置能给我们带来很大的灵活性。比如使用 时,对默认的资源库地址 不是很满意,可以使用下面的命令来更改资源库地址:

npm --registry "an other registry" install express

或者下面的命令

env npm_config_registry="an other registry" 
npm install express 

或是对 默认的 编辑器不满意,直接命令 。 的配置可通过命令 获取。这个命令是获取修改后的配置,要获取包括默认配置的全部配置加上 参数。

值得注意的是,开发者通过 的方式修改 这个属性值,一定要明白这个修改这个值所带来的负面效应。一旦设置了 这个值,当你要 一个模块,会把模块发布到修改后的资源库里,而不是原始默认的资源库。其他的资源库是原始默认的资源库的一个复制品,定时从默认的资源库取资源。一般来说,没有把其新加的模块同步到默认的资源库的能力。这样会导致发生你的模块在修改后的资源库里能够找到,而在其它的资源库里找不到的事情。

四、npm install 命令

是下载文件夹里的依赖。

安装模块只需要 命令带来了很大的方便。安装模块的路径分两种:

  • 全局路径,也就是带上参数 的安装模式。这个命令会把模块安装在 下,可通过命令 查看全局模块的安装目录。 里定义的会安装到 目录下,如果模块带有 会安装到 目录下。

  • 本地路径,不带 参数。从当前目录一直查找到根目录下有没有 目录,有的话,模块安装到这个目录下的 目录里,如果没有找到则把模块安装到当前目录 目录下。 定义的 会安装到 目录下, 则不会安装。

那么,我们需要选择什么样的安装方式呢?全局模式可以让你不用担心找不到模块,但是,如果不需要还是尽量避免全局模式。

如果我们只是 一个模块,我们不需要使用全局模式。

如果我们需要在命令行中调用,我们需要使用全局模式。因为这个安装把 里 下的定义安装到 目录下。

有些模块我们既需要在命令行中调用又想 ,比如 。那么我们可以使用全局模式安装,然后使用下一节要讲的命 把它链接到本地的 目录下。

不要担心 里 中定义的命令会不会因为不是全局安装而不能运行。比如在例子里定义的 的 。在调用 时 会 目录放到环境变量 $PATH 的最前面。

五、npm link 命令

对开发者而言,这算是最有价值的命令。假设我们开发了一个模块叫 test ,然后我们在 test-example 里引用这个模块 ,每次 test 模块的变动我们都需要反映到 test-example 模块里。不要担心,有了 命令一切变的非常容易。

首先我们需要把 test 链接到全局模式下:

`cd ~/work/node/test` # 进入test模块目录
`npm link`  #创建链接到`$PREFIX/lib/node_modules`

那么 test 的模块将被链接到 下,就像我的机器上 指到 ,那么 将会链接到 下。执行脚本 被链接到 上。

接下来我们需要把 test 引用到 test-example 项目中来:

`cd ~/work/node/test-example` # 进入test-example模块目录
`npm link test` # 把全局模式的模块链接到本地

命令会去 目录下查找名叫 test 的模块,找到这个模块后把 的目录链接到 这个目录上来。

现在任何 test 模块上的改动都会直接映射到 test-example 上来。再比如假设我们开发很多应用,每个应用都用到 :

`npm install coffee-script -g` # 全局模式下安装coffee-script
`cd ~/work/node/test` # 进入开发目录
`npm link coffee-script` # 把全局模式的coffee-script模块链接到本地的node_modules下
`cd ../test-example` # 进入另外的一个开发目录
`npm link coffee-script` # 把全局模式的coffee-script模块链接到本地
`npm update coffee-script -g` # 更新全局模式的coffee-script,所有link过去的项目同时更新了。

就像你看到, 在开发时一个模块被多个模块引用时的应用场景非常有用。 用户会想,我这儿没有 下的 工具怎么办?别担心只要你的 支持 就可用到这个特性。

六、其它 npm 命令

命令里还有很多有用的命令。

  • ,更新当前的 资源库。

  • ,编辑当前模块的所有依赖模块。

  • ,打开 模块的文档。

  • ,查看 是否有新版本。

  • ,可以要求依赖模块是从 资源库安装的,而不是从 安装。因为作者的 资源库总是最新的版本, 上的是模块作者发布上去的稳定版本。

甚至可以用 来编程。

var npm = require('npm');
npm.load({}, function (err) {
    if (err) return commandFailed(err);
    npm.on("log", function (message) {
        if (arg) console.log(message)
    })
    var requirements = JSON.parse(fs.readFileSync('config/requirements.json'));
    npm.commands.install(requirements, function (err, data) {
        if (err) return commandFailed(err);
    });
});

做为 开发者工具, 已经为我们想到很多的应用场景。这也是 社区一致推荐它为开发者模块依赖管理工具。

七、拓展阅读