包的管理

在某目录下安装包时,不会安装到全局的包里面,只会安装到执行命令的位置。所以不需要担心本地Nodejs环境混乱的问题。

在安装包的时候,一般只有工具性质的包,才有全局安装的必要性,因为它们提供了好用的终端命令。判断某个包是否需要全局安装可以参考官方的使用说明。

初始化项目

1
npm init -y

执行该命令后会在该目录下出现一个package.json的文件,该文件会记录你安装的包名版本号

  1. 该命令只能在英文名目录下运行,不能包括中文空格的目录名。
  2. 在运行npm install 命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json中。

dependencies记录下载的包

package.json下有个dependencies属性记录着该项目所需要用到的包名及版本。

dependencies记录的包又称核心依赖包

一次性下载项目所需要的全部包

在上述说到package中有记录到该项目所需要的用到的包,如果该项目用的包非常多,如果一次次安装肯定是非常麻烦的,那么用什么办法一次性全部下载全部的包呢?用以下命令可以实现一次性下载项目所需要的包。

1
npm install

或者简便一点npm iiinstall的简写

该命令是读取package下的``dependencies`属性记录的包信息,然后去下载所需要的包。

一次性安装多个包

npm i 包名 包名 ...,以空格区分开包

1
npm install jquery moment

缺失直接运行报错

在运行某项目时缺失某个依赖包,则会报以下错误

1
ErrorCannot find module '包名'

卸载包

1
npm uninstall 包名

devDependencies节点

如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。

devDependencies记录的包又称开发依赖包,只会在开发阶段用到。

与之对应的,如果某些包在开发项目上线之后都需要用到,则建议把这些包记录到dependencies节点中。

  • 安装指定的包,并记录到devDependencies节点中。
1
npm i 包名 -D
  • 上诉命令是简写形式,等价于下面完整的写法
1
2
3
npm install 包名 --save-dev
// 或者,一般属性和包名互换位置不影响安装
npm install --save-dev 包名

解决包下载慢的问题

查看当前镜像源

1
npm config get registry

更换淘宝镜像源

1
npm config set registry=https://registry.npm.taobao.org/

查看是否更换成功

1
npm config get registry

出现以下镜像地址则说明更换淘宝镜像成功。

镜像源切换工具nrm

1
2
3
4
5
# 通过 npm 包管理器,将nrm安装为全局可用的工具
npm i nrm -g
# 查看所有可用的镜像源
nrm ls
# 将下包的镜像源切换为 taobao 镜像

镜像源

1
2
3
4
5
6
7
npm ------ https://registry.npmjs.org/
yarn ----- https://registry.yarnpkg.com/
cnpm ----- http://r.cnpmjs.org/
taobao --- https://registry.npm.taobao.org/
nj ------- https://registry.nodejitsu.com/
npmMirror- https://skimdb.npmjs.com/registry/
edunpm --- http://registry.enpmjs.org/

切换源

1
nrm use taobao

i5ting_toc

这是一个.mdHTML的模块

1
2
3
4
5
# 将 i5ting_toc 安装为全局包,-g 可以放在包名前面或者后边,不影响下载
npm install -g i5ting_toc
# 调用i5ting_toc,轻松将 md 转换 HTML的功能
i5ting_toc -f 要转换的md文件路径 -o
# -f 表示文件路径 -o转换完使用默认浏览器打开

发布npm包

  1. npm注册账号
  2. 在终端切换npm官方源(此处我使用了nrm工具,安装方式npm i nrm -g)
1
nrm use npm
  1. 输入npm login开始登录

注意:在运行npm login命令之前,必须先把下包的服务器地址切换为npm的官方服务器。否则会导致发布包失败!

tips:Enter one-time password from your authenticator app:在邮箱拿到验证码输入

删除已发布的包

1
npm unpublish 包名 --force
  1. npm unpublish命令只能删除72小时以内发布的包
  2. npm unpublish删除的包,在24小时内不允许重复发布
  3. 发布包的时候要慎重,尽量不要往npm上发布没有意义的包!

模块的优先级

内置模块 > 第三方模块

一般模块在第一次使用的时候会加载到缓存中,下次使用直接调用缓存,提高使用效率。

加载第三方模块

内置模块和第三方模块

使用require()加载自定义模块时,必须指定以**./../开头的路径标识符,在加载自定义模块时,如果没有指定./../**这样的路径标识符,则NodeJs会把它当作内置模块或第三方模块进行加载。

扩展名加载顺序

在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:

  1. 按照确切的文件名进行加载
  2. 补全.js扩展名进行加载
  3. 补全.json扩展名进行加载
  4. 补全.node扩展名进行加载
  5. 加载失败,终端报错

找不到modules文件夹

如果传递给require()的模块标识符不是一个内置模块,也设有以**./../**开头,则Node.js会从当前模块的父目录开始,尝试从/node modules文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录(即盘符)。
例如,假设在C:\Users\test\project\foo.js文件里调用了require(tools),则Node.js会按以下顺序查找:

  1. C:\Users\test\project\node_modules\tools
  2. C:\Users\test\node_modules\tools
  3. C:\Users\node_modules\tools
  4. C:\node_modules\tools

目录作为模块

当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式:

  1. 在被加载的目录下查找一个叫做package.json的文件,并寻找main属性,作为require()加载的入口
  2. 如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件。
  3. 如果以上两步都失败了,则Node.js会在终端打印错误消息,报告模块的缺失:Error:Cannot find module'xxx'

自定义npm包

包结构如下

1
2
3
4
5
6
7
8
├─ lilbai-tool           
├─ src
├─ data.js
└─ htmlReplace.js
├─ index.js
├─ package.json
└─ README.md
└─ test.js

index.js

在index.js中要引入其他js文件,并且选择性暴露出引入对象和对象属性,在对象前加上...对象名

1
2
3
4
5
6
7
8
9
10

const data = require("./src/data")
const html = require("./src/htmlReplace")

//拆分模块 1. 将方法拆分到各个js文件中 2. 在index.js导入各方法,暴露出对象,并且对象前加...
//...functionname,展开运算符,表示包含data内的所有属性
module.exports={
...data,
...html
}

data.js

在其他的js文件也要暴露出对象,不然在index.js方法中找不到其他方法暴露的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function data (str){

const dt = new Date(str)

const y = addZero(dt.getFullYear())
const m = addZero(dt.getMonth()+1)
const d = addZero(dt.getDate())

const hh = addZero(dt.getHours())
const mm = addZero(dt.getMinutes())
const ss = addZero(dt.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}

function addZero(n){
return n>9? n:'0'+ n
}
//在个js文件也需暴露对象,不然index.JS找不到暴露的对象
module.exports={
data
}

htmlReplace.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//防止用户输入奇怪的东西或者跑bug
function htmlReplace(str){
//replace(/被字符串/i或者g,替换后字符串),i不区分大小写,g全局匹配,m多行匹配
return str.replace(/< | >| &| "/g,function(param){
switch (param){
case '<':
return '<'
case '&gt;' :
return '>'
case '&quot;' :
return '"'
case '&amp;':
return '&'
}
})
}

module.exports ={
htmlReplace
}