- npm i 【npm install】
安装
- npm install npm -g
npm的三个部分
- npm 官网 www.npmjs.com 网站直接查询一个模块的相关信息
- npm registry https://registry.npmjs.org/ 模块查询下载的服务
- npm cli 命令行下载工具
npm registry 【注册表】
- npm i [email protected]
- 淘宝 NPM 镜像
例如:
npm i [email protected] --registry=https://registry.npm.taobao.org
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install [email protected]
团队搭建私有 registry
- cnpmjs.org
- 阿里云的 regsitry Aliyun Registry
初始化
- npm init
npm init --yes
安装
- npm install
运行时依赖、本地开发依赖
- --save、--save-dev 安装到 dependencies【运行时依赖的模块】 和 devDependencies【本地开发时依赖的模块】
- 简写
npm i xx -S
和npm i xx -D
npm help install
~ npm help install
# 项目中已有 package.json,可以直接 npm intall 安装所有依赖项
npm install (with no args, in package dir)
# scope 通常用于管理私有模块,以 @ 开头,没有 @ 则反之
# npm install some-pkg
# npm install @scott/some-pkg
npm install [<@scope>/]
# 可以安装特定 tag 的模块,默认是 latest,如:
# npm install lodash@latest
npm install [<@scope>/]@
# npm install [email protected]
# npm install @scott/[email protected]
npm install [<@scope>/]@
# 安装一个某个范围内的版本
# npm install lodash@">=2.0.0 <3.0.0"
# npm install @scott/som-pkg@">=2.0.0 <3.0.0"
npm install [<@scope>/]@
# npm install git+ssh://[email protected]:tj/commander.js.git
npm install :/
# 以 git 仓库地址来安装
# npm install https://github.com/petkaantonov/bluebird.git
npm install
# 安装本地的 tar 包
# npm install /Users/black/Downloads/request-2.88.1.tar.gz
npm install
# 以 tar 包地址来安装
# npm install https://github.com/caolan/async/tarball/v2.3.0
# npm install https://github.com/koajs/koa/archive/2.5.3.tar.gz
npm install
# 从本地文件夹安装
# npm install ../scott/some-module
npm install
# 卸载也很简单
npm uninstall some-pkg -S
# 或者简写,加上 -S 是把卸载也同步到 package.json 中
npm un some-pkg -S
npm semver version
- package.json
"dependencies": {
"bluebird": "^3.5.2",
"lodash": "^4.17.11"
}
- node_modules
npm tree -L 2
.
├── node_modules
│ ├── bluebird
│ └── lodash
├── package-lock.json
└── package.json
版本管理
Semantic Versioning 2.0.0
semver.org
版本号比如 v4.5.1,v 是 version 的缩写,4.5.1 被.
分开成三端,这三端分别是:major
minor
patch
,也就是 主版本号.次版本号.修订号major: breaking changes (做了不兼容的 API 修改)
minor: feature add(向下兼容的功能性新增)
patch: bug fix, docs(向下兼容的问题修正)
node_modules
- 目录是递归安装的,它是按照依赖关系进行文件夹的嵌套
~ tree -L 4
.
├── connect-mongo
│ ├── node_modules
│ │ └── mongodb
│ │ ├── node_modules
├── mongoose
│ ├── node_modules
│ │ ├── mongodb
│ │ │ └── node_modules
│ │ └── sliced
├── async
├── grunt
│ ├── node_modules
│ │ ├── async
│ │ └── which
└── underscore
npm3 时代里面策略改成了平铺结构
➜ node_modules tree -L 1
.
├── ajv
├── asn1
├── assert-plus
├── asynckit
├── aws-sign2
├── aws4
├── bcrypt-pbkdf
├── bluebird
├── caseless
├── co
├── combined-stream
├── delayed-stream
├── fast-deep-equal
├── fast-json-stable-stringify
├── forever-agent
├── form-data
├── uuid
└── ...省略剩下 20 个
npm shrinkwrap 锁包
- package-lock文件 【npm5以后的新特性】
- 在一个 package.json 里的 dependencies 里面,包的依赖版本可以这样写:
"lodash": "~3.9.0",
"lodash": "^3.9.0",
"lodash": ">3.9.0",
"lodash": ">=1.0.0-rc.2",
"lodash": "*"
// ... 更多写法不再列举
-
~
意思是,选择一个最近的小版本依赖包,比如~3.9.0
可以匹配到所有的 3.9.x 版本,但是不会匹配到 3.10.0 -
^
则是匹配最新的大版本,比如^3.9.0
可以匹配到所有的 3.x.x,但是不会匹配到 4.0.0 npm init --yes && npm i lodash async -S
npm scripts
- 在 package.json 里的 scripts 里配置的各种任务,都可以这样直接调用:
npm start
npm run dev
npm run egg:prod
"scripts": {
"build": "npm run build:prod",
"clean:dist": "rimraf ./dist",
"build:prod": "cross-env NODE_ENV=production webpack"
}
# 如下命令行均可执行
➜ npm run clean:dist
➜ npm run build:prod
➜ npm run build
"scripts": {
// 通过 && 分隔,如果 clean:dist 任务失败,则不会执行后面的构建任务
"build:task1": "npm run clean:dist && npm run build:prod"
// 通过 ; 分隔,无论 clean:dist 是否成功,运行后都继续执行后面的构建任务
"build:task2": "npm run clean:dist;npm run build:prod"
// 通过 || 分隔,只有当 clean:dist 失败,才会继续执行后面的构建任务
"build:task3": "npm run clean:dist;npm run build:prod"
"clean:dist": "rimraf ./dist",
"build:prod": "cross-env NODE_ENV=production webpack",
// 对一个命令传配置参数,可以通过 -- --prod
// 比如 npm run compile:prod 相当于执行 node ./r.js --prod
"compile:prod": "npm run compile -- --prod",
"compile": "node ./r.js",
}
npx
- npx 是 npm 自带的非常酷炫的功能,直接执行依赖包里的二进制文件
# 先安装一个 cowsay
➜ npm install cowsay -D
# 包里的二进制文件会被放到 node_modules/.bin 目录下
➜ ll node_modules/.bin/
total 0
lrwxr-xr-x 1 16:34 cowsay -> ../cowsay/cli.js
lrwxr-xr-x 1 16:34 cowthink -> ../cowsay/cli.js
# 直接通过 npx 来调用 cowsay 里的二进制文件
➜ npx cowthink Node 好玩么
_____________
( Node 好玩么 )
-------------
o ^__^
o (oo)\_______
(__)\ )\/\
||----w |
|| ||
➜ npx cowsay 爽爆了
_____________
< Node 爽爆了 >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
实现一个 Node LTS 查看工具
项目初始化
➜ cd ltsn
# 通过 touch 新建一个 markdown 的文件,用来描述包功能
➜ touch README.md
# 通过 touch 新建一个 git 忽略文件
➜ touch .gitignore
.gitignore
.DS_Store
npm-debug.log
node_modules
yarn-error.log
.vscode
.eslintrc.json
npm init 生成 package.json
- npm init:
➜ ltsn npm init
Press ^C at any time to quit.
# 回车确认或者输入另外一个名字作为包名
package name: (ltsn)
# 版本就从 1.0.0 开始
version: (1.0.0)
# 简单的描述
description: CommandLine Tool for Node LTS
# 包的入口文件地址,通过 index.js 暴露内部函数
entry point: (index.js) index.js
# 测试脚本,可以先留空,大家根据实际情况取舍
test command:
# 包的 github 仓库地址
git repository: [email protected]:4liang/ltsn.git
# 一些功能关键词描述
keywords: Node LTS
# 作者自己
author: 4liang
# 开源的协议,默认是 ISC,我个人喜欢 MIT
license: (ISC) MIT
# 检查信息无误,输入 yes 回车即可
About to write to /Users/4liang/juejin/ltsn/package.json:
{
"name": "ltsn",
"version": "1.0.0",
"description": "CommandLine Tool for Node LTS",
"main": "lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "[email protected]:4liang/ltsn.git"
},
"keywords": [
"Node", "LTS"
],
"author": "4liang",
"license": "MIT",
"bugs": { "url": "https://github.com/4liang/ltsn/issues" },
"homepage": "https://github.com/4liang/ltsn#readme"
}
Is this OK? (yes) yes
# 输入 ls 查看当前包内文件
➜ ls
package.json README.md
脚手架
npm i yo generator-nm -g
目录 /lib
exports.query = require('./lib/query')
exports.update = require('./lib/update')
/lib/update.js
可以用来放数据源的获取和更新,而 /lib/query.js
里面可以放对数据的二次加工格式化之类,首先是 /lib/update.js
获取 Node LTS 数据:
const axios = require('axios')
const color = require('cli-color')
const terminalLink = require('terminal-link')
const compareVersions = require('compare-versions')
module.exports = async (v) => {
// 拿到所有的 Node 版本
const { data } = await axios
.get('https://nodejs.org/dist/index.json')
// 把目标版本的 LTS 都挑选出来
return data.filter(node => {
const cp = v
? (compareVersions(node.version, 'v' + v + '.0.0') >= 0)
: true
return node.lts && cp
}).map(it => {
// 踢出去 file 这个字段,其他的全部返回
const { files, ...rest } = it
return { ...rest }
})
}
然后是 /lib/query.js:
const Table = require('cli-table')
function query(dists) {
const keys = Object.keys(dists[0])
// 建立表头
const table = new Table({
head: keys
})
// 拼接出表格的每一行
return dists
.reduce((res, item) => {
table.push(
Object.values(item)
)
return res
}, table)
.toString()
}
module.exports = query
最后,再增加一个 bin 文件夹,在它里面增加一个 ltsn 脚本文件,在里面写入:
#!/usr/bin/env node
const pkg = require('../package')
// 从顶层 index.js 里面拿到 lib 下面模块暴露的方法
const query = require('..').query
const update = require('..').update
// 输出结果到命令行窗口
function printResult(v) {
update(v).then(dists => {
const results = query(dists, v)
console.log(results)
process.exit()
})
}
function printVersion() {
console.log('ltsn ' + pkg.version)
process.exit()
}
// 一些命令的帮助提示
function printHelp(code) {
const lines = [
'',
' Usage:',
' ltsn [8]',
'',
' Options:',
' -v, --version print the version of vc',
' -h, --help display this message',
'',
' Examples:',
' $ ltsn 8',
''
]
console.log(lines.join('\n'))
process.exit(code || 0)
}
// 包的入口函数,里面对参数做剪裁处理,拿到入参并给予
// 不同入参的处理逻辑
function main(argv) {
if (!argv) {
printHelp(1)
}
const getArg = function() {
let args = argv.shift()
args = args.split('=')
if (args.length > 1) {
argv.unshift(args.slice(1).join('='))
}
return args[0]
}
let arg
while (argv.length) {
arg = getArg()
switch(arg) {
case '-v':
case '-V':
case '--version':
printVersion()
break
case '-h':
case '-H':
case '--help':
printHelp()
break
default:
printResult(arg)
break
}
}
}
// 启动程序就开始执行主函数
main(process.argv.slice(2))
module.exports = main
#!/usr/bin/env node
加上 #!
这里是定义当前脚本的执行环境是用 Node 执行,安装包以后我们希望它可以像一个二进制一样来执行,那么可以到 package.json 来配置下执行路径,在 package.json 里面增加一个配置属性:
"bin": {
"ltsn": "bin/ltsn"
},
然后对于用到的模块,我们在包目录下,执行:
npm i axios cli-color cli-table compare-versions -S
这样安装后,package-lock.json 也自动创建了, 整个的目录结果如下:
~ tree -L 2
.
├── README.md
├── bin
│ └── ltsn
├── index.js
├── lib
│ ├── query.js
│ └── update.js
├── node_modules
├── package-lock.json
└── package.json
再把 README.md 文档内容完善一下,我们的代码就准备好了。
npm install 本地包进行测试
等到代码写完,就可以本地测试了,本地测试最简单的办法,就是通过 npm link
安装下:
~ npm link
npm WARN [email protected] No repository field.
audited 145 packages in 2.103s
found 0 vulnerabilities
/Users/4liang/.nvm/versions/node/v10.11.0/bin/ltsn -> /Users/4liang/.nvm/versions/node/v10.11.0/lib/node_modules/ltsn/bin/ltsn
/Users/4liang/.nvm/versions/node/v10.11.0/lib/node_modules/ltsn -> /Users/4liang/juejin/ltsn
然后边调试代码边测试,测试完毕后,可以直接在本地指定目录来全局安装,首先卸载掉之前可能测试安装过的全局包:
npm uninstall ltsn -g
然后可以在命令行窗口用绝对路径,或者直接进入到包目录下,执行全局安装动作:
npm i ./ -g
# npm i /Users/4liang/juejin/ltsn -g
npm publish 发布包
到 npmjs.com 注册好一个账号且邮箱验证完
npm login
npm publish
npm install 线上包进行验证
~ npm uninstall ltsn -g
removed 1 package in 0.262s
~ npm i ltsn -g
/Users/black/.nvm/versions/node/v10.13.0/bin/ltsn -> /Users/black/.nvm/versions/node/v10.13.0/lib/node_modules/ltsn/bin/ltsn
+ [email protected]
added 28 packages from 17 contributors in 5.33s