npm及常用命令【持续更新】

283 阅读6分钟

NPM 简介

背景

前端在工程化的路上涌现出了一大堆第三方库,像最基础的JQuery、Moment到更先进的框架Vue、React。这些库会相互依赖。如果没有包管理器的存在,我们想要使用一个库,就必须先把这个库依赖的所有其他的库下载下来,而这些其他的库也有可能依赖另外的库,然后我们又先得把那些库下载下来,如此往复...

这还是在版本没有冲突的情况下,如果依赖的版本冲突了,比如说我要用 a,而 a 依赖 z ver1.0。我又要用 b,而 b 依赖 z ver2.0,那这个时候我就要下载两个版本的 z 并让 ab 分别依赖它们需要的版本...

是不是光听起来就头疼了。

没错,如果现在还让程序员去一个一个下载依赖,那肯定会疯掉的。但是我们是谁,我们是程序员,我们的宗旨是:

能让代码做到的绝不亲手做

于是,npm(node package manager)出现了。

包管理器的功能

包管理器,顾名思义,就是帮助我们管理各种包的相互依赖以及版本问题的管理器。

以后要是用到某个第三方库了,跟包管理器说,它会自动找到这个第三方库所依赖的库并下载,并且自动递归处理这些依赖的库所依赖的库。当然,都是合适的版本。

npm

npm (node package manager)就是最经典的,最基础的包管理器。

配置文件 package.json

随着开发,需要依赖的包会越来越多,node_module里面的文件会越来越多。所以我们在发布项目到服务器的时候,会不把这个文件夹携带过去。但是这样问题来了,服务器怎么知道并恢复需要用到的依赖呢(代码移植)?

这个时候,package.json就来了。这个文件的主要作用就是在开发的时候记录依赖及版本号。然后服务器就可以根据这个文件重新下载文件以恢复依赖及版本号。

当然,配置文件还会记录其他信息:

  • name 包名
  • version 版本
  • description 描述
  • homepage 官网地址
  • author 作者
  • repository 仓库
  • main 入口文件
  • keywords 关键字

这些东西会在创建 npm init 的时候询问之后就会形成 package.json 文件

{
    "name": "...",
    "version": "...",
    "description": "...",
    "main": "...",
    "scripts": {
        "test": "..."
    },
    "repository": {
        "type": "...",
        "url": "..."
    },
    "author": "...",
    "license": "...",
    "bugs": {
        "url": "..."
    },
    "homepage": "...",
    "dependencies": {
        "jquery": "..."
    },
    "devDependencies": {
        "mocha": "..."
    }
}

使用包

CommonJS

const $ = require("jquery");

ES Module

import $ from "jquery";

不管是用哪一种方式使用,查找文件方式都是一致的:

  1. 首先在当前文件夹内寻找 node_module/jquery.js。有,直接返回
  2. 寻找 node_module/jquery/main。有,直接返回
    • main 是指入口文件。在 package.json 文件里面有注明是哪个文件。默认是 index.js
  3. 返回上一层文件夹,如果到了根目录还是没有,报错。否则继续第1步

版本控制

背景

包不是一尘不变的,会持续更新,也就形成了很多版本号。一般来说,版本号的结构是这么组成的:

大版本号.次版本号.修订号

  • 大版本号 有重大改变,一般不会兼容前面的版本了
  • 次版本号 有改变,但一般不至于不兼容前面的版本,比如增加一些API什么的
  • 修订号 有改变,但很小,一般都是修修bug之类的

那比如说,如果 a 要依赖 z ver1.0.0,然后后来 z 更新到 ver2.0.0,那么在恢复依赖的时候,不加版本控制的 a 可能会因为下载了 z 的更高版本而不能正常工作了。

解决方法很简单,就直接指定 z ver1.0.0 就行,其他一概不允许私自升级。

但是问题也很明显,就是不灵活。如果 z 只是更新了小版本 1.1.0,或者只是更新了补丁 1.0.1,那这样子限制就太狠了。在恢复依赖的时候就不得不多下载很多很多版本,即便它们都可以正常工作。

这是一个比较复杂的问题,于是孕育出来了一个版本控制方法。

语义版本

不知道大家有没有发现,有的时候 npm install 之后,package.json 里面会记录的包的版本很奇怪:

{
    ...
    "dependencies": {
        "jquery": "^3.4.1"
    }
    ...
}

你说你 jquery 下载的版本是 3.4.13.4.1 呗,整个 ^ 是怎么回事呢?其实,这个就是npm如何管理版本的方法。

符号语义
>版本号可以比我规定的高
>=版本号可以比我规定的高,或跟我一样
<版本可以比我规定的低
<=版本号可以比我规定的低,或跟我一样
~修订号可以比我规定的高
^次版本号和修订号可以比我规定的高
X占位符

package-lock.json vs package.json

package-lock.json 会记录安装包的确切版本。如果移植工程的时候有这个文件,就会按照这个文件所规定的版本号恢复依赖。

npm脚本

package.json 中,可以定义一些常用的命令,这样就不用每次都输入一些繁琐的命令了:

{
    ...
    "scripts": {
        "命令别名": "命令"
    }
    ...
}

在使用的时候,可以直接 npm run 命令别名,相当于执行了 命令

另外一些常用的命令,可以省略 run,像是 start stop test

命令 可以省略 npx,因为它会自动把命令环境变成 node_module/bin/

npm [run] start 有默认值:node server.js

npm 常用命令【持续更新】

获取源

npm config get registry

设置源

NEW_REGISTRY:新设置的源的地址

npm config set registry NEW_REGISTRY

安装

本地安装(基础款)

PACKAGE_NAME:要下载的包的名字

npm install PACKAGE_NAME ...
或者
npm i PACKAGE_NAME ...
全局安装

在基础款的基础上加上标签--global或者-g

PACKAGE_NAME:要下载的包的名字

npm install --global PACKAGE_NAME ...
或者
npm i -g PACKAGE_NAME ...
精确安装
npm i --save-exact PACKAGE_NAME
npm i -E
安装指定版本号
npm i PACKAGE_NAME@VERSION
恢复依赖(开发环境)
npm install
或者
npm i
恢复依赖(生产环境)
npm install --production
生产环境依赖

下载依赖,并记录依赖为生产环境依赖。即记录在 "dependencies"

  • PACKAGE_NAME:要下载的包的名字
npm i [--save|-S]? PACKAGE_NAME
开发环境依赖

下载依赖,并记录依赖为开发环境依赖。即记录在 "devDependencies"

  • PACKAGE_NAME:要下载的包的名字
npm i [--save-dev|-D] PACKAGE_NAME

操作node_modules

在包名前面加上 npx,npm就会到当前目录的 ./node_modules/bin/ 中找到对应的包并调用

PACKAGE_NAME:要操作的包的名字

npx PACKAGE_NAME

全局配置地址

npm config get prefix

包配置

npm init

查看安装路径

npm root // local
npm root -g // global

查看包信息

npm [view|v|show|info|] PACKAGE_NAME

查询安装包

npm [list|ls|la|ll] [depth=DEPTH_NUMBER]

查看更新

npm outdated

更新

npm [update|up|upgrade]

卸载包

npm [uninstall|remove|rm|r|un|unlink] PACKAGE_NAME

npm配置

// list out configs
npm config ls [-l] [--json]

// get a config
npm config get CONFIG_NAME

// set a config
npm config set CONFIG_NAME=CONFIG_VALUE

// remove a config
npm config delete CONFIG_NAME