Node.js使得在服务器端使用JavaScript编写应用程序成为可能。它是基于V8Javascript运行时并且使用C++编写的,所以它的速度很快。最初,它旨在作为应用程序的服务器环境,但是开发人员使用它创建工具来帮助他们进行本地任务自动化。从那时起,一个全新的基于Node的工具生态系统(如Grunt,Gulp和Webpack)彻底改变了前端开发的面貌。
为了在Node.js中使用这些工具(或者包),我们需要能够以有效的方式安装和管理它们。这就是我们即将要讨论的:npm--Node的包管理器。它负责安装你需要使用的包,并且提供一个有用的界面让你与它们交互。
在本文中,我将介绍使用npm的基础知识。我将向你演示如何在本地和全局模式下安装包,以及删除,更新和安装某个版本的包。我还会告诉你如何使用package.json
处理项目的依赖。如果你更喜欢看视频,请注册SitePoint Premium观看我们的免费录屏:什么是npm以及如何使用?。
在开始使用npm之前,首先需要在电脑中安装Node.js。
安装Node.js
去Node.js 下载页面获取你需要的版本。可以获得Windows和Mac环境的安装包和预编译的Linux二进制文件以及源代码。对于Linux环境,你还可以通过包管理器来安装Node,如这里所述。
本教程我们将使用v6.10.3稳定版本。在编写本文时,这是Node的当前长期支持(LTS)版本。
提示: 你也可以考虑使用版本管理器来安装Node。这将消除下面提出的权限问题。
我们来看一下Node的安装位置以及版本。
$ which node
/usr/bin/node
$ node --version
v6.10.3
使用Node的REPL(交互式解释器)检查安装是否成功。
$ node
> console.log('Node is running');
Node is running
> .help
.break Sometimes you get stuck, this gets you out
.clear Alias for .break
.exit Exit the repl
.help Show repl options
.load Load JS from a file into the REPL session
.save Save all evaluated commands in this REPL session to a file
> .exit
Node.js已经安装成功,现在我们可以把注意力集中在npm上,npm已经集成在上述安装的Node.js中。
$ which npm
/usr/bin/npm
$ npm --version
3.10.10
Node包模块
npm可以以本地或全局模式安装包。在本地模式下,将包安装在父工作目录中的node_modules
文件夹中。该位置由当前用户所拥有。安装在{prefix}/lib/node_modules/
中的全局包由user根目录所拥有({prefix}
通常是/usr/
或 /usr/local
)。这意味着你将不得不使用sudo全局安装包,这可能会在解决第三方依赖时导致权限错误,也可能导致安全问题。下面让我们更改一下:
更改全局包的位置
让我们看看运行npm config list
输出了什么:
$ npm config list
; cli configs
user-agent = "npm/3.10.10 node/v6.10.3 linux x64"
; userconfig /home/sitepoint/.npmrc
prefix = "/home/sitepoint/.node_modules_global"
; node bin location = /usr/bin/nodejs
; cwd = /home/sitepoint
; HOME = /home/sitepoint
; "npm config ls -l" to show all defaults.
输出给了我们有关npm的安装信息。现在,重要的是获取当前的全局位置。
$ npm config get prefix
/usr
为了在主目录中安装全局包,我们需要更改这个前缀。为此,你可以在主文件夹中创建一个新目录。
$ cd ~ && mkdir .node_modules_global
$ npm config set prefix=$HOME/.node_modules_global
通过这个简单的配置更改,我们将这个新目录位置设置为全局Node包安装的位置。这个更改同时会在我们的主目录中创建了一个.npmrc文件。
$ npm config get prefix
/home/sitepoint/.node_modules_global
$ cat .npmrc
prefix=/home/sitepoint/.node_modules_global
我们仍然将npm安装在由user根目录所有的位置。但是要注意我们已经在配置中改变了全局包安装的位置。我们需要再次安装npm,但是这一次是安装在新用户所在的位置。当然,安装的将是npm的最新版本。
$ npm install npm --global
└─┬ npm@5.0.2
├── abbrev@1.1.0
├── ansi-regex@2.1.1
....
├── wrappy@1.0.2
└── write-file-atomic@2.1.0
最后,我们需要添加.node_modules_global/bin
到$PATH环境变量中,以便可以从命令行运行全局包。为了做到这一点,你可以把下面这一行添加到.profile
,.bash_profile
或者.bashrc
文件中并重新启动终端。
export PATH="$HOME/.node_modules_global/bin:$PATH"
现在我们可以找到npm的所在目录.node_modules_global/bin
并且使用合适的npm版本。
$ which npm
/home/sitepoint/.node_modules_global/bin/npm
$ npm --version
5.0.2
在全局模式下安装包
目前我们只有一个安装在全局的包-那就是npm包本身。下面我们来安装UglifyJS包(一个JavaScript的压缩工具)。我们使用--global标记,也可以缩写为-g。
$ npm install uglify-js --global
/home/sitepoint/.node_modules_global/bin/uglifyjs -> /home/sitepoint/.node_modules_global/lib/node_modules/uglify-js/bin/uglifyjs
+ uglify-js@3.0.15
added 4 packages in 5.836s
从输出可以看出,还安装了其他包, 这些包都是UglifyJS包的依赖项。
列出全局安装包
我们可以使用npm list
命令列出全局包。
$ npm list --global
home/sitepoint/.node_modules_global/lib
├─┬ npm@5.0.2
│ ├── abbrev@1.1.0
│ ├── ansi-regex@2.1.1
│ ├── ansicolors@0.3.2
│ ├── ansistyles@0.1.3
....................
└─┬ uglify-js@3.0.15
├─┬ commander@2.9.0
│ └── graceful-readlink@1.0.1
└── source-map@0.5.6
然而,输出十分冗长。我们可以使用--depth=0
选项进行优化。
$ npm list -g --depth=0
/home/sitepoint/.node_modules_global/lib
├── npm@5.0.2
└── uglify-js@3.0.15
我们发现这要更友好 -- 只显示我们安装的包及其版本号。
我们可以在命令行中使用任何全局安装包。例如:下面的命令展现了如何使用Uglify 包将example.js
压缩到example.min.js
:
$ uglifyjs example.js -o example.min.js
在本地模式下安装包
当你在本地安装包时,通常会使用package.json文件进行安装。下面让我们创建这样的一个文件。
$ npm init
package name: (project)
version: (1.0.0)
description: Demo of package.json
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
按Enter
接受默认值,然后键入yes
确认。这样将会在项目的根目录下创建一个package.json
文件。内容如下:
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
提示:你可以使用
npm init --y
命令以更快的方式生成package.json文件
除了main
和scripts
外,其他字段应该是一目了然的。main
字段是你程序的主入口,scripts
字段允许你指定在包的生命周期中的不同时间运行的脚本命令。我们暂时不讨论这些东西,但是如果你想了解更多相关信息,请参阅《npm中的package.json文档》和《使用npm作为构建工具》。
现在让我们来安装underscore包。
$ npm install underscore
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN project@1.0.0 No description
npm WARN project@1.0.0 No repository field.
+ underscore@1.8.3
added 1 package in 0.344s
注意这里创建了一个文件,我们稍后会讲到它。
打开package.json文件我们会看到dependencies
字段已经添加到了文件中:
{
...
"dependencies": {
"underscore": "^1.8.3"
}
}
使用package.json管理依赖
如你所见,underscore v1.8.3安装到了我们的项目中。版本号前面的(^)符号表示安装时,npm将安装最高版本的包,npm还可以找到主版本可以匹配的唯一位置(除非存在package-lock.json
文件)。在我们的例子中,这是V2.0.0版本以下的所有版本。版本控制依赖(major.minor.patch)的这种方法被称为语义化版本控制。你可以在《语义化版本控制:为什么你应该使用它?》文章中了解更多相关知识。
还要注意,underscore被保存为dependencies字段的属性。这是最新版本npm的默认设置,用于运行应用程序所需的包(如underscore)。也可以通过指定--save-dev
标志将包保存为devDependency。devDependencies是用于开发目的的包,例如运行测试或解析代码。
你也可以给package.json文件添加private: true
以防止意外发布私有仓库并且阻止所有运行npm install
时生成的警告。
其实使用package.json
指定项目依赖的最大好处是可移植性。例如,当你克隆别人的代码时,你只需要在根目录运行npm i
即可,然后npm将解析并获取所有运行该应用程序必需的包。稍后我们再来看这个。
在结束此部分内容之前,我们快速检查一下underscore是否正在工作。在项目根目录下创建名为test.js的文件并写入下列内容:
const _ = require('underscore');
console.log(_.range(5));
使用node test.js
运行文件,你应该看到[0, 1, 2, 3, 4]输出到了屏幕。
卸载本地安装包
npm是一个包管理器,所以它肯定可以卸载一个包。我们假设当前的underscore包导致了兼容性问题。我们可以卸载这个包并安装旧版本,如下所示:
$ npm uninstall underscore
removed 2 packages in 0.107s
$ npm list
project@1.0.0 /home/sitepoint/project
└── (empty)
安装特定版本的包
我们通过使用@符号加一个版本号来安装特定版本的underscore包。
$ npm install underscore@1.8.2
+ underscore@1.8.2
added 1 package in 1.574s
$ npm list
project@1.0.0 /home/sitepoint/project
└── underscore@1.8.2
更新包
让我们检查一下underscore包是否存在新版本:
$ npm outdated
Package Current Wanted Latest Location
underscore 1.8.2 1.8.3 1.8.3 project
Current
列告诉我们当前安装的版本。Latest
列告诉我们包的最新版本。 Wanted
列告诉我们在不破坏现有的代码的前提下可以升级到的最新版本的包。
还记得之前的package-lock.json
文件吗?它是在npm v5中引入的,目的是确保安装在计算机上的所有项目的依赖保持不变。当npm修改node_modules文件夹或package.json文件时它会自动生成。
如果你喜欢,你可以继续尝试。删除node_modules
文件夹,然后重新运行npm i
。最新版本的npm将安装underscore v1.8.2(因为这是package-lock.json文件中指定的)。根据语义化版本控制的规范,v1 .8.3将向下兼容早期版本。在过去,不一致的包版本对开发人员来说很头痛的事情。这个问题通常通过使用必须手动创建的npm-shrinkwrap.json
文件来解决。
现在,我们假设最新版本的underscore修复了我们之前提到的兼容性错误,我们希望将包更新为该版本。
$ npm update underscore
+ underscore@1.8.3
updated 1 package in 0.236s
$ npm list
project@1.0.0 /home/sitepoint/project
└── underscore@1.8.3
提示:为了使上述命令工作正常,underscore必须被列为package.json的依赖项。如果我们有更多的过时模块,我们也可以执行
npm update
。
搜索包
在本教程中我们已经多次使用了mkdir
命令。是否存在一个包做相同的事情呢?让我们使用npm search
命令看一下。
$ npm search mkdir
NAME | DESCRIPTION | AUTHOR | DATE | VERSION
mkdir | Directory crea… | =joehewitt | 2012-04-17 | 0.0.2
fs-extra | fs-extra conta… | =jprichardson… | 2017-05-04 | 3.0.1
mkdirp | Recursively mkdir,… | =substack | 2015-05-14 | 0.5.1
...
这里有一个mkdirp
包,我们来安装它。
$ npm install mkdirp
+ mkdirp@0.5.1
added 2 packages in 3.357s
创建mkdir.js
文件并复制粘贴此代码:
const mkdirp = require('mkdirp');
mkdirp('foo', function (err) {
if (err) console.error(err)
else console.log('Directory created!')
});
从终端运行这个文件:
$ node mkdir.js
Directory created!
重新安装项目依赖
我们先安装一个包:
$ npm install request
+ request@2.81.0
added 54 packages in 15.92s
检查package.json
文件。
"dependencies": {
"mkdirp": "^0.5.1",
"request": "^2.81.0",
"underscore": "^1.8.2"
},
注意依赖项列表会自动更新。在以前的npm版本中,你将不得不执行npm install request --save
以保存package.json
中的依赖关系。如果你想安装一个包而不在package.json中保存它,只需使用--no-save
参数。
假设你将项目源代码克隆到了另一台计算机,现在需要安装依赖项。我们先删除node_modules
文件夹然后执行npm install
。
$ rm -R node-modules
$ npm list
project@1.0.0 /home/sitepoint/project
├── UNMET DEPENDENCY mkdirp@^0.5.1
├── UNMET DEPENDENCY request@^2.81.0
└── UNMET DEPENDENCY underscore@^1.8.2
npm ERR! missing: mkdirp@^0.5.1, required by project@1.0.0
npm ERR! missing: request@^2.81.0, required by project@1.0.0
npm ERR! missing: underscore@^1.8.2, required by project@1.0.0
$ npm install
added 57 packages in 1.595s
注意观察node_modules
文件夹,你会发现它已经被重新创建。像这样,你就可以轻松地与他人共享你的代码,而不会导致你的项目和源依赖仓库膨胀。
管理缓存
当npm安装一个包时,其实它保存了一个副本。所以下次你安装这个包的时候就不需要再连接网络。这些副本缓存在你的主路径下的.npm
目录中。
$ ls ~/.npm
anonymous-cli-metrics.json _cacache _locks npm registry.npmjs.org
这个目录会随着时间的推移而变得乱七八糟,所以有时候要清理它。
$ npm cache clean
如果你要清理系统上的多个Node项目,还可以从工作区清除所有node_module
文件夹。
find . -name "node_modules" -type d -exec rm -rf '{}' +
别名
可能你已经注意到,运行npm命令有多种方式。以下是一些常用的npm别名的简要列表:
npm i <package>
- 安装本地包npm i -g <package>
- 安装全局包npm un <package>
- 卸载本地包npm up
- npm更新包npm t
- 运行测试npm ls
- 列出已安装的模块npm ll
或npm la
- 在列出模块时打印附加包信息
你也可以一次安装多个软件包:
$ npm i express momemt lodash mongoose body-parser webpack
如果想要学习所有常见的npm命令,执行npm help
获取完整的命令列表。你也可以在我的《10个技巧,使你成为npm忍者》文章中学到更多相关知识。
版本管理器
有几种有用的工具可以让你在同一台机器上管理多个版本的Node.js。其中一个就是n
,另一个是nvm
(Node 版本管理器)。如果这是你感兴趣的内容,可以看看我们的教程:《使用nvm安装多个版本的Node.js》。
总结
在本教程中,我介绍了使用npm的基础知识,演示了如何从下载页面安装Node.js,如何更改全局包的位置(所以我们可以避免使用sudo)以及如何在本地和全局模式下安装包。我还介绍了删除,更新和安装某个版本的包,以及管理项目的依赖。如果你想了解有关最新版本中的新功能的更多信息,可以访问npm Github发行页面。
随着版本5的发行,npm正在向前端开发的世界迈进。根据其首席运营官的介绍,npm用户基础正在发生变化,其中大多数开发者使用它们并没有使用它来编写Node。相反,它正在成为人们在前端开发中整合JavaScript的工具(你可以使用它来安装任何东西)并且它正在成为编写现代JavaScript的组成部分。你在你的项目中使用npm了吗?如果没有,现在是开始使用它的好时机。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。