Node.js模块系统与npm包管理实战指南

作者:夜航船

时间:2026-10-25

浏览:113

本文深入解析Node.js模块系统,涵盖require加载机制、模块分类及缓存原理。详细讲解exports与module.exports的区别,以及package.json配置方法。同时提供npm常用命令、全局安装及cnpm国内镜像配置指南,帮助开发者高效管理项目依赖。

文章目录

在前文对Node.js有了初步了解的基础上,本节继续深入探讨其核心机制,整理并分享关于模块与包管理器的关键知识点,如有疏漏欢迎指正。

require函数

该函数的核心功能是在当前模块中加载并引入另一个指定模块。

基本语法格式为:require("模块名称")。

模块分类

Node.js中的模块主要划分为以下三大类别:

1. 自定义模块:指开发者在项目中自行编写的、具备特定业务功能的模块文件。

  • 若子模块未显式暴露任何数据,require返回的是一个空对象,而非undefined。
  • 引用自定义模块时,路径前必须添加 ./ 前缀(例如:require("./01.js")),这是因为Node.js默认优先在 node_modules 目录中查找,而非当前目录。

2. 第三方模块:由外部程序员或公司开发的模块,使用前需通过NPM包管理器进行安装。

3. 系统模块:Node.js内置的核心模块,无需额外安装即可直接引用(如 fs、http、url 等)。

第三方模块

使用第三方模块前必须先执行安装操作,以下以 jQuery 为例进行演示。

1. 安装第三方模块

安装前的目录状态如下所示。

require函数

执行安装命令【npm install jquery】进行安装,具体过程如下所示。

require函数

安装成功后,程序目录会自动生成 node_modules 文件夹,结构如下所示。

require函数

2. 引入第三方模块

安装完成后,在代码中直接通过 require 引入即可使用,示例如下。

 var jquery = require("jquery");
 console.log(jquery.toString());

3. 示例测试

在命令行环境中测试引用第三方模块,结果如下所示。

require函数

注意:上述示例报错是因为 jQuery 专为浏览器端设计,不支持在服务器端直接调用,此处仅作为调用语法的演示。

系统模块

系统模块是Node.js内置的功能模块,无需安装即可直接使用。以下以文件操作模块为例进行说明。

首先创建一个测试文件 test.txt,其内容如下所示。

require函数

接着利用Node.js内置的 fs 模块进行文件读取调用,代码示例如下。

 var fs =require("fs");
 fs.readFile("test.txt",function(err,data){
     console.log(data.toString());
 });

实际运行测试的结果如下所示。

require函数

require注意事项

  • 若引入的模块文件存在语法或逻辑错误,程序将抛出异常报错。
  • 若指定的模块路径不存在,同样会引发错误。
  • 若模块被重复引用,系统仅加载一次。这是因为首次加载后会将模块存入缓存区,后续引用时直接读取缓存,不再重复执行加载逻辑。

关于 require 加载模块的具体流程,可参考下图所示。

require函数

exports导出对象

该对象的作用是将模块内部需要共享给外部的数据或函数暴露给引用者。

使用语法为:exports.属性名 或 exports.函数名。

1. exports示例

以下示例展示了如何将用户名变量和 sayHi 方法公开导出至引用处。

 var username="小六公子";
 function sayHi(){
     console.log("hi,小六子");
 }
 exports.username=username;
 exports.sayHi=sayHi;

2. exports注意事项

使用 exports 时需注意以下关键点。

exports 实际上是 module.exports 的引用,两者指向同一内存地址,可通过比较验证。

require函数

exports 是一个对象,允许为其添加属性和方法,但不能直接修改 exports 指向的内存地址。如下所示的操作是错误的。

 exports.sayHi=sayHi;
 exports=sayHi;//此语法是错误的,不能修改指向

module模块对象

在 module 对象中,最核心的部分是 exports 对象,具体结构如下所示。

  • module.exports 才是真正暴露给外部的对象,exports 仅是对它的引用。
  • 赋值语法:module.exports.属性=值;
  • 方法赋值语法:module.exports.方法=函数;。
  • 直接导出语法:module.exports=对象或函数;//直接导出对象。

module 对象还包含其他重要属性:

  • module.id:模块的唯一标识ID,即对象的绝对路径。
  • module.parent:模块的父模块对象。
  • module.filename:模块的文件名及完整路径。
  • module.children:子模块列表,类型为数组。
  • module.paths:查找模块的路径列表,类型为数组。

关于 module 对象的详细信息可参考下图所示。

require函数

package.json包描述文件

NPM(Node Package Manager)是基于Node.js的包管理工具。在Node.js项目中,JS的基本单位是单个文件,但复杂模块往往由多个子模块组成。为便于管理,可将多个子模块组成的集合称为“包”,并将所有子模块置于同一目录中。包必须有一个入口文件,其导出对象即为包的导出对象。默认入口文件为 index.js,也可通过新建 package.json 文件并设置 main 属性来指定入口。

1. 什么是package.json ?

package.json 是Node.js项目的包描述文件,以JSON格式描述项目元数据。以之前安装的 jQuery 为例,其对应的 package.json 内容如下所示。

{
  "_from": "jquery",
  "_id": "jquery@3.6.0",
  "_inBundle": false,
  "_integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==",
  "_location": "/jquery",
  "_phantomChildren": {},
  "_requested": {
    "type": "tag",
    "registry": true,
    "raw": "jquery",
    "name": "jquery",
    "escapedName": "jquery",
    "rawSpec": "",
    "saveSpec": null,
    "fetchSpec": "latest"
  },
  "_requiredBy": [
    "#USER",
    "/"
  ],
  "_resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
  "_shasum": "c72a09f15c1bdce142f49dbf1170bdf8adac2470",
  "_spec": "jquery",
  "_where": "D:\\MyProject\\DemoNodeJs",
  "author": {
    "name": "OpenJS Foundation and other contributors",
    "url": "https://github.com/jquery/jquery/blob/3.6.0/AUTHORS.txt"
  },
  "bugs": {
    "url": "https://github.com/jquery/jquery/issues"
  },
  "bundleDependencies": false,
  "commitplease": {
    "nohook": true,
    "components": [
      "Docs",
      "Tests",
      "Build",
      "Support",
      "Release",
      "Core",
      "Ajax",
      "Attributes",
      "Callbacks",
      "CSS",
      "Data",
      "Deferred",
      "Deprecated",
      "Dimensions",
      "Effects",
      "Event",
      "Manipulation",
      "Offset",
      "Queue",
      "Selector",
      "Serialize",
      "Traversing",
      "Wrap"
    ],
    "markerPattern": "^((clos|fix|resolv)(e[sd]|ing))|^(refs?)",
    "ticketPattern": "^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])"
  },
  "deprecated": false,
  "description": "JavaScript library for DOM operations",
  "devDependencies": {
    "@babel/core": "7.3.3",
    "@babel/plugin-transform-for-of": "7.2.0",
    "commitplease": "3.2.0",
    "core-js": "2.6.5",
    "eslint-config-jquery": "3.0.0",
    "grunt": "1.3.0",
    "grunt-babel": "8.0.0",
    "grunt-cli": "1.3.2",
    "grunt-compare-size": "0.4.2",
    "grunt-contrib-uglify": "3.4.0",
    "grunt-contrib-watch": "1.1.0",
    "grunt-eslint": "22.0.0",
    "grunt-git-authors": "3.2.0",
    "grunt-jsonlint": "1.1.0",
    "grunt-karma": "4.0.0",
    "grunt-newer": "1.3.0",
    "grunt-npmcopy": "0.2.0",
    "gzip-js": "0.3.2",
    "husky": "1.3.1",
    "insight": "0.10.1",
    "jsdom": "13.2.0",
    "karma": "5.2.3",
    "karma-browserstack-launcher": "1.4.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-firefox-launcher": "1.1.0",
    "karma-ie-launcher": "1.0.0",
    "karma-jsdom-launcher": "8.0.2",
    "karma-qunit": "3.0.0",
    "load-grunt-tasks": "5.1.0",
    "native-promise-only": "0.8.1",
    "promises-aplus-tests": "2.1.2",
    "q": "1.5.1",
    "qunit": "2.9.2",
    "raw-body": "2.3.3",
    "requirejs": "2.3.6",
    "sinon": "2.3.7",
    "sizzle": "2.3.6",
    "strip-json-comments": "2.0.1",
    "testswarm": "1.1.2",
    "uglify-js": "3.4.7"
  },
  "homepage": "https://jquery.com",
  "husky": {
    "hooks": {
      "commit-msg": "commitplease .git/COMMIT_EDITMSG",
      "pre-commit": "grunt lint:newer qunit_fixture"
    }
  },
  "keywords": [
    "jquery",
    "javascript",
    "browser",
    "library"
  ],
  "license": "MIT",
  "main": "dist/jquery.js",
  "name": "jquery",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jquery/jquery.git"
  },
  "scripts": {
    "build": "npm install && grunt",
    "jenkins": "npm run test:browserless",
    "start": "grunt watch",
    "test": "npm run test:slim && npm run test:no-deprecated && npm run test:no-sizzle && grunt && grunt test:slow && grunt karma:main && grunt karma:amd",
    "test:amd": "grunt && grunt karma:amd",
    "test:browser": "grunt && grunt karma:main",
    "test:browserless": "grunt && grunt test:slow",
    "test:no-deprecated": "grunt test:prepare && grunt custom:-deprecated && grunt karma:main",
    "test:no-sizzle": "grunt test:prepare && grunt custom:-sizzle && grunt karma:main",
    "test:slim": "grunt test:prepare && grunt custom:slim && grunt karma:main"
  },
  "title": "jQuery",
  "version": "3.6.0"
}

2. 如何创建package.json文件?

在Node.js中,可通过交互式向导创建。在命令行中切换至项目目录,输入命令【npm init】即可启动创建向导。具体过程如下所示。

require函数

根据向导提示依次填写相关信息,经过上述7步操作即可创建包文件。创建成功后,程序目录下会出现该文件,结构如下所示。

{
  "name": "demonode",
  "version": "1.0.0",
  "description": "node示例",
  "main": "index.js",
  "dependencies": {
    "jquery": "^3.6.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "小六公子",
  "license": "MIT"
}

注意:若希望生成默认配置的 package.json 文件,可使用命令【npm init -y】一键完成。

NPM基础

1. 常用npm命令

常用的 npm 命令汇总如下。

  1. 安装命令:通过命令【npm install 包名称】安装指定的第三方包。
  2. 缩写安装命令:通过命令【npm i 包名称】安装指定的第三方包。
  3. 指定版本安装:通过命令【npm i 包名称@version】安装指定版本的第三方包,默认安装最新版本。
  4. 全局安装:通过命令【npm i 包名称 -g】进行全局安装,使其适用于所有项目。默认全局安装目录为【C:\Users\登录账号\AppData\Roaming\npm\node_modules】。
  5. 安装同时写入依赖列表:通过命令【npm i 包名称 --save】在安装的同时将包信息写入包描述文件中的 dependencies 列表。
  6. 安装同时写入开发时依赖列表:通过命令【npm i 包名称 --save-dev】在安装的同时将包信息写入包描述文件中的 devDependencies 列表。
  7. 查找包:通过命令【npm search 包名称】进行查找。
  8. 预览包:通过命令【npm view 包名称】预览包的具体内容。
  9. 卸载包:通过命令【npm uninstall 包名称】卸载已安装的包。
  10. 更新包:通过命令【npm update 包名称】更新包。

2. npm 示例

以下以npm的安装和查找操作为例进行演示。

require函数

cnpm基础

1. 什么是cnpm ?

由于npm命令默认从国外服务器下载和安装,速度可能较慢。为满足国内应用需求,cnpm应运而生。cnpm是淘宝提供的与npm服务器保持同步更新的软件包镜像。

目前cnpm的官方网址为【https://npmmirror.com/package/cnpm】,关于cnpm的简介如下所示。

require函数

2. 使用cnpm

若需使用cnpm,可通过注册命令进行配置,具体操作如下。

 npm install -g cnpm --registry=https://registry.npmmirror.com

require函数

cnpm命令的使用方式与npm一致,只需在命令前加上 c 前缀即可。示例如下所示。

require函数

控制台输出

1. 控制台常见输出

在Node.js作为服务器端运行环境时,控制台输出是常见的调试手段,具体形式如下。

  • 在Node.js中,控制台输出主要包含以下几种方式:
  • console.log(),用法与浏览器环境一致。
  • console.dir(),用于输出对象的目录信息。
  • console.error(),用于输出错误信息。
  • console.time(标识符) 与 console.timeEnd(标识符) 配合使用,用于计算某段程序的执行时间。
  • console.assert(条件表达式,输出内容);当条件表达式为假时,输出指定内容。

2. 控制台输出示例

以下展示了控制台输出的常用语法示例。

console.log("我是小六子");
console.dir("我是小六子呀");
console.error("小六子出错了");
console.time("t1");
for(var i=0;i<99999;i++){
    //
}
console.timeEnd("t1");

示例运行的截图结果如下所示。

require函数

Node.js作用域

1. 什么是作用域?

作用域规定了变量和函数的可用范围,分为全局作用域和局部作用域(函数作用域)。在Node.js中,一个文件即代表一个模块,模块中使用 var 定义的变量为局部变量,仅能在该模块内使用。这是因为模块在被调用时,Node.js会将其编译为一个函数。

2. 全局变量

若需将数据共享给其他模块,可通过以下两种方法实现:

  • 通过 exports.属性或函数 的方式导出。
  • 声明为全局变量。

全局变量通过【global.属性或函数=值】的方式定义和使用,具体示例如下。

 var username="小六公子";
 function sayHi(){
     console.log("hi,小六子");
 }
 global.username=username;
 global.sayHi=sayHi;

调用全局变量的方法如下所示。

 var obj =require("./demo01-1.js");
 console.log(username);
 sayHi();

注意:global关键字在调用时可以省略,使用方式与 exports 几乎一致。

以上即为Node.js基础入门之模块与npm包管理器使用详解的详细内容,更多关于Node.js模块和npm的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章