Skip to content

NPM

元信息

  • 目标:理解包管理如何从浏览器内的 script 标签走向 Node 环境的 npm——掌握 CommonJS 包规范、package.json 与依赖管理,会用 npm init/install 组织项目依赖
  • 关键概念:NPM、CommonJS、package.json、dependencies、node_modules、require
  • 关联阶段:cp3
  • 常见误区:以为 require 是 JS 语言语句(是 Node 运行环境提供的函数);以为 npm 只能在服务端项目用(它管理的包也可供构建工具消费);以为依赖信息记在脑子里就行(package.json 是依赖的单一事实源,npm i 按它还原)

问题

  • 页面用 <script> 标记手工引入第三方库(如从 CDN 下载),下载、版本、更新的管理全靠人工,项目一大便不可维护
  • require.js 及 amd等虽然初步解决了模块化编码的规范和共享问题,但仍然受限于浏览器环境,不能利用 node.js 在服务端环境下的强大能力,如存取文件系统、自动化构建等

如何把"包的自动管理"与"服务端能力"结合起来呢?

CommonJS包规范 与 NPM (Node Package Manager)

  • CommonJS是类似于AMD的软件包编写规范,但面向非浏览器环境
  • NPM则是一个基于命令行的包管理工具,它能够识别和管理基于CommonJS规范编写的代码库,并且提供了仓库、下载、安装、引用等一系列的功能
  • NPM默认被集成在node.js环境中,从而为基于node.js编程提供了极大的便利

CommonJS包规范

代码库的作者在编写代码时,应当遵行如下原则:

  • 一个文件就是一个模块,拥有单独的作用域;
  • 普通方式定义的变量、函数、对象都属于该模块内;
  • 通过require语句来加载模块;
  • 通过exportsmodule.exports来定义和暴露模块中的函数或类;

http://www.commonjs.org/

npm 包结构

代码库的作者在打包和发布代码库时,应当遵行如下文件布局:

  • package.json:包描述文件
  • bin:存放可执行二进制文件的目录
  • lib:存放js代码的目录
  • doc:存放文档的目录
  • test:存放单元测试用例代码的目录

使用 NPM Node Package Manager

进入项目根目录,执行下列命令来初始化 npm

bash
npm init -y

初始化后,项目根目录下会新建一个名为 package.json 的 json 文件。里面包含了当前项目的信息以及所依赖的其它代码包的信息

npm 配置文件 package.json

jsonc
{
  "name": "mylib",   // 当前项目名称(中间不能有空格且必须小写),如果你要将当前项目发布为一个共享的npm包,则该名称不可以与已在npm中心仓库注册的名称相同
  "version": "1.0.0",   // 版本号
  "description": "",    // 描述
  "main": "index.js",   // 入口文件或主函数
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],  // 方便其它人搜索到本包的关键字
  "author": "", // 作者
  "license": "ISC",
  "dependencies": {}, // npm i --save package 将添加至此
  "devDependencies":{} // npm i --save-dev package 将添加至此,这里的依赖不会发布到Node的生产环境下
}

上面是初始化之后的 package.json 文件(// 注释仅作说明,真实文件中不可有注释)

依赖包的管理

如果你使用npm install package-name安装了软件包

  • package.json中的 dependencies 的属性会出现相应的列表
  • 同时项目根目录下会创建一个node_modules的目录,下载的软件包会被存放至此

你可以自行编辑package.json增加或修改依赖包的信息,然后执行下述命令,则自动更新当前的包文件

bash
npm i

基于 npm 的编程

// main.js

javascript
const cheerio = require('cheerio')
const $ = cheerio.load('<h2 class="title">Hello world</h2>')

$('h2.title').text('Hello there!')
$('h2').addClass('welcome')
$.html()

cheerio是一个提供类似jquery功能的node库。 然后执行:

bash
npm install cheerio
node main.js
// output: <html><head></head><body><h2 class="title welcome">Hello there!</h2></body></html>

node 执行过程

  • 基于 require('cheerio'), node执行引擎将在当前项目的node_modules下查找cheerio的npm包,并装载
  • 如查找失败,则依次向上级目录的node_modules继续查找(直至根目录);仍找不到再查 NODE_PATH 环境变量指定的路径,否则报错退出。注意:npm 全局安装目录不在查找路径中——所以项目依赖必须本地安装,全局安装只用于命令行工具
  • 根据CommonJS规范,将cheerio暴露的名称赋给本地名称,即cheerio
  • 调用cheerio的各API,模拟类似jquery的操作

为什么上述代码中不直接使用jquery而要引入cheerio?

require : 语句还是函数?

javascript
const cheerio = require('cheerio')

这里的require并不是js内置的语句,而是一个特殊的函数,它是由node.js支持和引入的,所引入的第三方包必须符合commonjs规范

javascript
import cheerio from 'cheerio';

这是 ES6 语言原生的模块语法(ES modules)。TypeScript 等超集语言采用同样的写法(编译时转译回 JS);node.js V13.2.0 之后的版本开始提供支持;在最新的现代浏览器中则内置支持(需 type="module"

http://caibaojian.com/es6/module.htmlhttp://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.htmlhttps://cloud.tencent.com/developer/article/1589084https://juejin.cn/post/6844903983987834888

参考