Nodejs包管理

包的基本结构

  • package.json(包管理配置文件)

  • index.js(包的入口文件)

  • README.md(包的说明文档)

包管理配置文件

{
  "name": "total_webpack",//!!!包名
  "version": "1.0.0",//!!!包的版本号
  "description": "",//描述说明
  "main": "index.js",//!!!入口文件
  "scripts": {//自定义脚本命令(便捷命令书写)
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack serve --open"
  },
  "author": "",//作者名
  "license": "ISC",//开源协议
  "dependencies": {//!!!依赖节点(这里放的是部署上线/开发运行都需要的包)
    "css-loader": "^6.7.1",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.5.0",
    "less": "^4.1.2",
    "less-loader": "^10.2.0",
    "style-loader": "^3.3.1",
    "url-loader": "^4.1.1",
    "webpack": "^5.72.1",
    "webpack-dev-server": "^4.9.0"
  },
  "devDependencies": {//!!!开发依赖节点(只在开发环境使用的包:比如webpack的打包工具,部署上线就不需要了)
    "webpack-cli": "^4.9.2"
  }
}

模块化的概念

好比一台车的零件来源世界各地,将一个个函数,js文件分别管理,对其暴露所需接口,开发者可以按需使用里面的方法。

模块作用域

//1.js
module.exports.x = 11;

//2.js
module.exports.x = 6;

//index.js
let x = require("./1");
let y = require("./2");

console.log(x, y);//11	6
  • 每个模块module都是独立的作用域,这样的优点是不会导致全局污染

  • require()方法用于加载模块

  • module.exports导出的是一个对象,对象包含我们导出的属性,如果我们也直接导出一个对象,将会覆盖之前添加的属性

    //1.js
    let x = 11;
    module.exports.x = x;
    module.exports = {
      xx: 666,
    };
    
    //index.js
    let x = require("./1");
    console.log(x);//{ xx: 666 } x属性被覆盖
    
    

module.exports与exports的使用注意

  • 对于同一个模块module下,module.exports与exports只能二选一,不建议混用易造成混乱
  • exports = module.exports exports是module里exports属性的一个引用,一旦对module.exports做出修改
  • require()方法得到的永远是module.exports指向的对象

image-20220512184941745

require是如何获取到暴露的接口方法的

以const HtmlWebpackPlugin = require(“html-webpack-plugin”);为例,我们会通过html-webpack-plugin找到对应的包目录,再找里面的package.json文件里的main属性(上面记录了这个包的入口文件),如index.js,这样我们就会找同级目录下的index.js文件,里面会有写好的module去暴露我们能使用的方法

在讲深一点包设计的层面,入口文件index也会require引入自身lib里的各种模块(意味着里面的模块也是做了module暴露处理,就像联通的管子)去处理各种方法,最终汇总成一个对象集中暴露------很像数据结构的树

image-20220512192501391

image-20220512193046832

image-20220512193006631

模块的加载机制

  • 优先从缓存中加载

    模块在第一次加载后会被缓存。这也意味着多次调用require不会导致模块的代码被执行多次。
    注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。

require("./1");
require("./1");
require("./1");//依旧只执行一次
  • 内置模块的加载优先级是最高的:自己写的模块fs(不加路径标识符)和node自带的fs,他只会返回node的模块

  • 自定义模块的加载机制:应对内置模块的加载优先级问题,需要加上./或者…/开头的路径标识符,否则node会把它当作内置模块或者第三方模块进行加载

    image-20220512195252865

  • 第三方模块加载机制

image-20220512195447575

  • 目录作为模块(一般包目录名就是模块名,而且符合基本包结构的都是这么找)

image-20220512195559363