node

Node定义

Node.js是一个基于 V8 JavaScript 引擎的JavaScript运行时的环境

Node 程序是使用 c++/ c/ js 语言编写的
[[前端了解/Node/_resources/node/e49f63c48826b59143b4b3366c92cf75_MD5.jpeg|Open: Pasted image 20250522151116.png]]
![[前端了解/Node/_resources/node/e49f63c48826b59143b4b3366c92cf75_MD5.jpeg]]

应用场景

一: *目前前端开发的库都是以node包的形式进行管理

二: *npm、yarn、pnpm工具成为前端开发使用最多的工具;

三: 越来越多的公司使用Node.js作为web服务器开发、中间件、代理服务器;

四, 大量项目需要借助Node.js完成前后端渲染的同构应用

五, 资深前端工程师需要为项目编写脚本工具(前端工程师编写脚本通常会使用JavaScript,而不是Python或者shel)

六, 很多企业在使用Electron来开发桌面应用程序;

管理node的工具

Node 程序传递参数

  • 正常情况下执行一个node程序,直接跟上我们对应的文件即可:
    node index.js

  • 在某些情况下执行node程序的过程中,我们可能希望给node传递一些参数:
    node index.js env=development coderwhy

  • *在程序中获取到传递的参数:

    • 获取参数其实是在process的内置对象中的;
    • 如果我们直接打印这个内置对象,它里面包含特别的信息:
      √其他的一些信息,比如版本、操作系统等可以自行查看

Node 的输出

[[前端了解/Node/_resources/node/31f26b1a8f5f31430c83ade96744ad0b_MD5.jpeg|Open: Pasted image 20250528223104.png]]
![[前端了解/Node/_resources/node/31f26b1a8f5f31430c83ade96744ad0b_MD5.jpeg]]

Node 的 REPL

REPL是 Read-Eval-Print Loop 的简称,翻译为“读取-求值-输出
循环;

REPL是一个 简单的, 交互式的编程环境

方法

  • 在终端中直接输入node
  • 在控制台中直接使用

[[前端了解/Node/_resources/node/9f0b8de46e04486b4b72bf793ce3f9ce_MD5.jpeg|Open: Pasted image 20250530103657.png]]
![[前端了解/Node/_resources/node/9f0b8de46e04486b4b72bf793ce3f9ce_MD5.jpeg]]

Node 的全局对象

常见的全局对象

[[前端了解/Node/_resources/node/f96f2a2c114478a8e54fb92e91463952_MD5.jpeg|Open: Pasted image 20250530105737.png]]
![[前端了解/Node/_resources/node/f96f2a2c114478a8e54fb92e91463952_MD5.jpeg]]

[[前端了解/Node/_resources/node/2872b99e65ce425d36b0ff9342c0c39a_MD5.jpeg|Open: Pasted image 20250530121231.png]]
![[前端了解/Node/_resources/node/2872b99e65ce425d36b0ff9342c0c39a_MD5.jpeg]]

global是一个全局对象process、.console、setTimeouts等都有被放到globalr中;

  • 新的标准中还有一个globalThis,也是指向全局对象的;
  • 类似于浏览器中的window;

特殊的全局对象

  • 这些全局对象是实际上是模块中的变量, 只是每个模块都有, 看起来*像是全局变量
  • 在命令行交互中式不可以使用的
  • 包括: __dirname, __filename, export, module, require()

__dirname : 获取当前文件所在的路径 ( 不包括后面的文件名)
__filename : 获取当前文件所在的路径和文件名 ( 包括后面的文件名)

global 和window 的区别

  • 在浏览器中,全局变量都是在window上的,比如有document、setInterval、setTimeout、alert、console等等
  • 在Node中,我们也有一个global属性,并且看起来它里面有很多其他对象。
  • 在浏览器中执行的 JavaScript 代码,如果我们在顶级范围内通过var定义的一个属性,默认会被添加到window对象上;
  • 在node中,我们通过var定义一个变量, 它只是在当前模块中有一个变量,不会放到全局中;

模块化

目的 : 模块化开发最终的目的是将程序划分成一个个小的结构

用法 :

  • 这个结构中编写属于自己的逻辑代码,有自己的作用域,定义变量名词时不会影响到其他的结构;
  • 这个结构可以将自己希望暴露的变量、函数、对象等导出给其结构使用;
  • 也可以通过某种方式,导入另外结构中的变量、函数、对象等;

按照这种结构划分开发程序的过程, 就是模块化开发的过程

CommonJS规范

Node中的每一个 js 文件都是一个单独的模块

模块中要导出的内容 : exports
模块中要导入内容 : require

[[前端了解/Node/_resources/node/aa2e22478987faaf12d5d70fd7bec0d4_MD5.jpeg|Open: Pasted image 20250530132649.png]]
![[前端了解/Node/_resources/node/aa2e22478987faaf12d5d70fd7bec0d4_MD5.jpeg]]

[[前端了解/Node/_resources/node/d68f7830be2871a364727e1ff645d1b6_MD5.jpeg|Open: Pasted image 20250530132724.png]]
![[前端了解/Node/_resources/node/d68f7830be2871a364727e1ff645d1b6_MD5.jpeg]]

util变量等于exports 对象

require的实现本质

[[前端了解/Node/_resources/node/a07269c198ed7949679906a92589cbb0_MD5.jpeg|Open: Pasted image 20250530145951.png]]
![[前端了解/Node/_resources/node/a07269c198ed7949679906a92589cbb0_MD5.jpeg]]

[[前端了解/Node/_resources/node/3271cf9d64e405d16db2c3f0bb625090_MD5.jpeg|Open: Pasted image 20250530150003.png]]
![[前端了解/Node/_resources/node/3271cf9d64e405d16db2c3f0bb625090_MD5.jpeg]]

bar变量就是exports对象

module的exports属性本质

[[前端了解/Node/_resources/node/354b7e2f4ebe5454f0f1c9a492d46036_MD5.jpeg|Open: Pasted image 20250530154627.png]]
![[前端了解/Node/_resources/node/354b7e2f4ebe5454f0f1c9a492d46036_MD5.jpeg]]

[[前端了解/Node/_resources/node/af508f1943b037e013561029247060db_MD5.jpeg|Open: Pasted image 20250530155343.png]]
![[前端了解/Node/_resources/node/af508f1943b037e013561029247060db_MD5.jpeg]]
exports可以导出的原因

  • **module对象的exports属性是exports对象的一个引用
  • `module.exports = exports = main中的bar;

require 查找模块细节

require是一个函数, 可以引入一个文件(模块)中导出的对象

书写规则require(X)

require 的查找规则

在nodejs中我们通过require(X),可以引入一个模块中导出的对象。

那么,require的查找规则是怎么样的呢?

导入格式require(X),下面总结几个常见的查找规则:

情况一:X是一个NodeJs核心模块,比如path、http等

直接返回核心模块,并且停止查找。

情况二:X是以./ 或 ../ 或 (根目录) 开头的

第一步:将X当做一个文件在对应的目录下查找;

  1. 如果有后缀名,直接按照后缀名的格式查找对应的文件

  2. 如果没有后缀名,会按照如下的顺序:

    1. 直接查找文件X
    2. 查找X.js文件
    3. 查找X.json文件
    4. 查找X.node文件

第二步:没有对应的文件,将X看作一个目录

  1. 查找目录下面的index文件

    1. 查找X/index.js文件
    2. 查找X/index.json文件
    3. 查找X/index.node文件

如果还没有找到,那么就报错:not found

情况三:X没有路径,也不是一个核心模块

从node_modules目录查找

NodeJs从当前模块的目录开始,并添加/node_modules,并尝试从该位置加载模块

例如,如果在”/home/ry/projects/foo.js”中调用 require(X),则将以下顺序查找:

  • /home/ry/projects/node_mudules
  • /home/ry/node_modules
  • /home/node_modules
  • /node_modules

以上目录找不到,那么就报错:not found

模块的加载过程

  1. 模块在被第一次引入时, 模块中的 JS 代码会被运行一次

  2. 模块被多次引入时, 回缓存, 最终只加载(运行)一次

  • 每个模块对象module 都有一个属性 : loaded
  • false 表示还没有加载, 为true 表示已经加载

循环引入

[[前端了解/Node/_resources/node/5379489ed74605db6eee3fdf4f43edd2_MD5.jpeg|Open: Pasted image 20250530212957.png]]
![[前端了解/Node/_resources/node/5379489ed74605db6eee3fdf4f43edd2_MD5.jpeg]]
采用深度优先算法 main -> aaa -> ccc -> ddd -> eee -> bbb

CommonJS会规范缺点

CommonJS加载模块是同步的

  • 同步 意味着只有等到对应的模块加载完毕当前模块中的内容才能被运行
  • 这个在服务器不会有什么问题,因为服务器加载的s文件都是本地文件,加载速度非常快:

应用于浏览器时:

  • 浏览器加载 js 文件需要先从服务器将文件下载下来,之后再加载运行
  • 那么 *采用同步的就意味着后续的S代码都无法正常运行,即使是一些简单的DOM操作;

AMD, CMD

[[前端了解/Node/_resources/node/3487517d1ebbbc0423bf235834f1a70a_MD5.jpeg|Open: Pasted image 20250530221305.png]]
![[前端了解/Node/_resources/node/3487517d1ebbbc0423bf235834f1a70a_MD5.jpeg]]
[[前端了解/Node/_resources/node/b54379def73193201d802b0313f7f5bd_MD5.jpeg|Open: Pasted image 20250530221657.png]]
![[前端了解/Node/_resources/node/b54379def73193201d802b0313f7f5bd_MD5.jpeg]]

ES Module

采用 ES Module 将自动采用严格模式

不允许在逻辑代码中写 import 导入语法 , 只能写在 js 代码顶

导入和导出方式

1
2
3
4
5
6
7
8
const name = "why"
const age = 18
export {
    name,
    age
} //不是一个对象, 只是一种特殊的语法

import {age, fname, sayHello} from"./foo.js" //导入

导出 /导出 时给标识符起一个别名

1
2
3
4
5
6
export {
    name as fname,
   age,
    sayHello
}
import {age as fage, fname, sayHello} from "./foo.js" //导入

定义时导出

1
2
3
4
5
6
export const name = "why"
export const age = 18

export function sayHello() {
    console.log("sayhello")
}
导入时给整个模块起别名
1
2
3
4
5
6
7
import * as foo from "./foo.js"

const name = "kk"

console.log(name)
console.log(foo.name)
foo.sayHello()
优化写法

规范 : 可以先把要用到的模块放在一个 js 文件里面, 其他js再从这个文件引入

1
export { format, formatData } from "./format.js"

把所有的变量导入进来

1
export * from "./format.js"
default用法
  • 默认导出 export 时可以不需要指定名字;
  • 在导入时不需要使用 { },并且可以自己来指定名字;
  • 它也方便我们和现有的 CommonJS 等规范相互操作;

导出
[[前端了解/Node/_resources/node/57fd5241907251dd268484ec9850f5cb_MD5.jpeg|Open: Pasted image 20250601201850.png]]
![[前端了解/Node/_resources/node/57fd5241907251dd268484ec9850f5cb_MD5.jpeg]]
或者
[[前端了解/Node/_resources/node/937d0952c1f4cdc75bba4c0b510f1982_MD5.jpeg|Open: Pasted image 20250601201925.png]]
![[前端了解/Node/_resources/node/937d0952c1f4cdc75bba4c0b510f1982_MD5.jpeg]]
注意 : 一个模块里面只能有一个默认导出( default export)

导入
[[前端了解/Node/_resources/node/bc35530ac76dd9fe66a85f0ab8da340c_MD5.jpeg|Open: Pasted image 20250601202009.png]]
![[前端了解/Node/_resources/node/bc35530ac76dd9fe66a85f0ab8da340c_MD5.jpeg]]

import函数的使用

不允许在逻辑代码中写 import 导入语法 , 只能写在 js 代码顶层

原因 :

  • 这是因为*ES Module在被S引擎解析*时,就必须知道它的依赖关系
  • 由于这个时候js 代码没有任何的运行,所以无法在进行类似于f判断中根据代码的执行情况
  • 甚至拼接路径的写法也是错误的 : 因为我们必须到运行时能确定path的值;错误写法 import from ("./foo" + ".js")

动态的加载某一个模坎

  • 使用import()函数来动态加载;
    importi函数返回一个Promise,可以通过then获取结果

[[前端了解/Node/_resources/node/5790845b0be6cb9d7ecb7a760fc5631e_MD5.jpeg|Open: Pasted image 20250601205315.png]]
![[前端了解/Node/_resources/node/5790845b0be6cb9d7ecb7a760fc5631e_MD5.jpeg]]

import.meta

import.meta 是一个给 JavaScript 模块暴露特定上下文的元数据属性的对象。

    console.log(import.meta)
[[前端了解/Node/_resources/node/cca6e731888b778c6f697e3b1d213964_MD5.jpeg|Open: Pasted image 20250601210256.png]]
![[前端了解/Node/_resources/node/cca6e731888b778c6f697e3b1d213964_MD5.jpeg]]

ES Module的解析流程

执行流程

  • 阶段一:构建(Construction),根据地址查找js文件,并且下载,将其解析成模块记录(Module Record);
    import * as foo from "./foo.js"

  • 阶段二:实例化(Instantiation),对模块记录进行实例化,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址。
    export { name, age, sayHelo } //此时的变量还没有值

  • 阶段三:运行(Evaluation),运行代码,计算值,并且将值填充到内存地址中;
    //赋上具体值

包管理工具

npm官方文档

npm 的重要文件

  • package.json

package.json属性详情

这是每个 Node.js 项目必备的配置文件,记录了项目的元数据和依赖信息。它包含:

package-lock.json
该文件记录了项目中每个依赖的具体版本,并锁定依赖树的结构。确保在不同机器上安装依赖时,所有的开发环境和生产环境都能一致地获取相同版本的依赖包

package.json 常见属性

[[前端了解/Node/_resources/node/b92cff03fb298122f810093af113483b_MD5.jpeg|Open: Pasted image 20250602163215.png]]
![[前端了解/Node/_resources/node/b92cff03fb298122f810093af113483b_MD5.jpeg]]
[[前端了解/Node/_resources/node/02d8e40c2946b81a4e25df73f739762a_MD5.jpeg|Open: Pasted image 20250602163342.png]]
![[前端了解/Node/_resources/node/02d8e40c2946b81a4e25df73f739762a_MD5.jpeg]]

  • dependenciesdevDependencies:分别列出了项目的生产环境和开发环境依赖
  • 自定义脚本,如构建、测试、启动等命令
  • 配置信息、许可证和作者信息等
main

main属性指定了程序的主入口文件

意思是,如果你的模块被命名为foo,用户安装了这个模块并通过require(“foo”)来使用这个模块,那么require返回的内容就是main属性指定的文件中 module.exports指向的对象。

它应该指向模块根目录下的一个文件。对大对数模块而言,这个属性更多的是让模块有一个主入口文件,然而很多模块并不写这个属性。

scripts

scripts属性是一个对象,里边指定了项目的生命周期个各个环节需要执行的命令。
key是生命周期中的事件,value是要执行的命令。
具体的内容有 install start stop 等,详见 https://docs.npmjs.com/misc/scripts

scripts属性用于配置一些脚本命令,以键值对的形式存在
配置后我们可以通过npm run命令的key来执行这个命令:

对于常用的start、test、stop、restart可以省略掉run直接通过npm start等方式运行

dependencies
  • dependencies属性是指定无论开发环境还是生成环境都需要依赖的包;
  • 通常是我们项目实际开发用到的一些库模块vue、vuex、vue-router、react、.react-dom、axios等等
devDependencies属性

一些包在生成环境是不需要的,比如webpack、babel
这个时候我们会通过npm install webpack-save-dev,将它安装到devDependencies属性中

peerDependencies属性
  • 还有一种项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是以另外一个宿主包为前提的:
  • 比如element-plus是依赖于vue3的,ant design是依赖于react、react-dom;

依赖的版本管理

semver版本规范是 X.Y.Z :

  • X主版本号(major): 当你做了不兼容的API修改(可能不兼容之前的版本
  • Y次版本号(minor): 当你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
  • Z修订号(patch) :当你做了向下兼容的问题修正(没有新功能,修复了之前版本的bug);

^~的区别:

  • x.y.z : 表示一个明确的版本号;
  • ^x.y.z : 表示x是保持不变的,y和z永远安装最新的版本;
  • ~x.y.z : 表示x和y保持不变的,z永远安装最新的版本;

npm 的常见命令

  1. 安装依赖
    安装项目中列出的所有依赖:
    npm install

该命令会根据 package.json 安装所有依赖,并生成或更新 node_modules 文件夹。如果你希望全局安装某个工具,可以使用 -g 参数

1
npm install -g <package-name>
  • 通常使用npm全局安装的包都是一些工具包:yarn、webpack等;
  • 并不是类似于axios、express、koa等库文件;
  • 所以全局安装了之后并不能让我们在所有的项目中使用axios等库;
    原理图
    [[前端了解/Node/_resources/node/de93ee2b9acc3969b0b70e785cc75ea3_MD5.jpeg|Open: Pasted image 20250602205758.png]]
    ![[前端了解/Node/_resources/node/de93ee2b9acc3969b0b70e785cc75ea3_MD5.jpeg]]
    [[前端了解/Node/_resources/node/53fd01f2d3cbf94655e82f9dbb5edafe_MD5.jpeg|Open: Pasted image 20250602210240.png]]
    ![[前端了解/Node/_resources/node/53fd01f2d3cbf94655e82f9dbb5edafe_MD5.jpeg]]
  1. 添加依赖
    用于安装一个新的包,并将其添加到 dependencies 或 devDependencies 中:
1
2
npm install <package-name> --save  # 默认会添加到dependencies
npm install <package-name> --save-dev # 添加到devDependencies
  1. 卸载依赖
    删除一个依赖包,并更新 package.json 和 node_modules
1
npm uninstall <package-name>
  1. 更新依赖
    更新项目中的所有依赖到符合版本范围的最新版本:
    npm update

5.查看包信息
查看已安装包的版本和详细信息:****
npm list

  1. 执行脚本
    在 package.json 文件中定义了脚本后,可以使用 npm run <script-name> 命令来执行它。例如:
1
npm run build

npm发布自己的包

[[前端了解/Node/_resources/node/e52f14a0ae89ac415e7bb49a89352f71_MD5.jpeg|Open: Pasted image 20250603102555.png]]
![[前端了解/Node/_resources/node/e52f14a0ae89ac415e7bb49a89352f71_MD5.jpeg]]

yarn

yarn 是由 Facebook 发起的包管理工具,目的是解决 npm 的一些性能和依赖管理问题。yarn 在安装速度、离线安装和一致性方面做了显著优化。

  • yarn 提供了更高效的依赖安装方式,采用并行安装并且支持缓存,能显著提升安装速度。
  • yarn.lock 文件确保所有团队成员安装的依赖版本一致,避免版本冲突。
  • 支持离线安装,在没有网络的情况下仍然能够安装已经缓存的依赖。

下载 npm install yarn

npm 与 Yarn 的比较

特性 npm Yarn
安装速度 npm 7+ 引入了一些性能优化,但通常速度较慢 更快,支持并行安装和缓存机制
依赖一致性 使用 package-lock.json 来锁定版本 使用 yarn.lock 锁定版本
离线安装 支持缓存,允许在没有网络的情况下安装依赖 支持离线模式,依赖会被缓存
工作空间支持 从 npm 7 开始支持工作空间 原生支持工作空间,适合 monorepo
CLI 功能全面,易用性不断提升 更简洁,但有些命令不兼容 npm
社区支持 全球最大的 JavaScript 包生态 非常活跃,尤其是在 React 社区

[[前端了解/Node/_resources/node/b079442e73df481b3518d0fd71f00ea8_MD5.jpeg|Open: Pasted image 20250602213810.png]]
![[前端了解/Node/_resources/node/b079442e73df481b3518d0fd71f00ea8_MD5.jpeg]]

cnpm

查看npm镜像
npm config get registry

设置npm镜像

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

将cnpm设置为淘宝的镜像

1
2
npm install -g cnpm -registry=https://registry.npm.taobao.org
cnpm config get registry

npx

npx 是 npm5.2.0版本新增的一个工具包,它允许用户在不安装全局包的情况下,运行已安装在本地项目中的包或者远程仓库中的包。

npx 是一个由 npm 提供的工具,用于直接运行 node_modules/.bin 中的可执行文件,而不必在全局安装依赖。npx 实际上是 npm 5.2+ 版本中新增的命令行工具,允许开发者运行任何命令而无需显式安装。

  • npx 可以临时运行安装在项目中的命令(即便这些命令没有全局安装),也可以运行 GitHub 上的命令或者从 npm 注册表中直接运行包。
  • npx 可以用来快速执行脚本,如运行项目中的构建工具、脚本命令等。

局部命令的执行

[[前端了解/Node/_resources/node/b5ed850b7ea893e19c30211f5ccb4c69_MD5.jpeg|Open: Pasted image 20250603091039.png]]
![[前端了解/Node/_resources/node/b5ed850b7ea893e19c30211f5ccb4c69_MD5.jpeg]]

npmyarnpnpmnpx 对比总结

npmyarnpnpmnpx 对比总结

特性 npm yarn pnpm npx
安装方式 使用 npm install 安装依赖 使用 yarn install 安装依赖 使用 pnpm install 安装依赖 临时执行包中的命令,不需要安装全局依赖
安装速度 较慢,依赖树较深时效率较低 快,支持并行安装和缓存 非常快,使用硬链接和共享依赖 运行时自动下载依赖,不需要安装
磁盘空间 使用重复依赖,占用较多磁盘空间 缓存依赖,但依赖安装较多时仍会占用一定磁盘空间 通过硬链接减少重复安装,节省磁盘空间 不占用磁盘空间,仅临时运行命令
锁定依赖版本 使用 package-lock.json 锁定版本 使用 yarn.lock 锁定版本 使用 pnpm-lock.yaml 锁定版本 不锁定版本,运行时临时安装和执行命令
依赖管理 默认安装多份重复依赖(有冗余) 安装时尽量避免冗余依赖 强制封闭依赖,避免隐式依赖 无依赖管理,直接执行命令
兼容性 与大部分工具和社区兼容 npm 兼容,但存在部分差异 npmyarn 不完全兼容,特别是在依赖管理方式上 依赖于 npm,通过 npx 直接执行命令
离线支持 不完全支持离线安装 支持离线安装,缓存安装过的包 完全支持离线安装,依赖缓存共享 不需要离线安装,运行时自动下载依赖
适用场景 适用于大部分 Node.js 项目 适合需要高性能和一致性保证的项目 适合需要优化磁盘空间和性能的大型项目 快速执行单次命令,无需全局安装依赖
社区和支持 最大的社区支持,生态最广泛 被许多大公司采用,尤其适合 Monorepo 管理 生态较小,但专注于性能和空间优化 npm 的一部分,功能简单实用

主要差异总结:

  • npm:广泛使用且成熟,适合大部分项目,但安装速度和磁盘空间管理较差。
  • yarn:性能优于 npm,尤其在并行安装和离线支持方面,适合需要版本一致性的团队协作项目。
  • pnpm:通过硬链接节省磁盘空间,优化了安装速度,特别适合大型项目或多个项目共享依赖的情况。
  • npx:用于临时执行命令或包,不需要全局安装,适用于单次执行而不需要管理依赖的场景。

硬链接和软连接

硬链接(hard link):

  • 硬链接(英语:hard link) 是*电脑文件系统中的多个文件平等地共享同一个文件存储单元;
  • 删除一个文件名字后,还可以用其它名字继续访问该文件;

符号链接(软链接soft link、Symbolic link):

  • 符号链接(软链接、Symbolic link)是一类*特殊的文件;
  • 其*包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用

[[前端了解/Node/_resources/node/54cca17c4865feceebea1a9e017895f1_MD5.jpeg|Open: Pasted image 20250603130622.png]]
![[前端了解/Node/_resources/node/54cca17c4865feceebea1a9e017895f1_MD5.jpeg]]

文件拷贝

会在硬盘中复制一份新的文件数据(改变其中一份, 不会影响另一份)
copy foo.js foo_copy.js
[[前端了解/Node/_resources/node/9d19ae1fbdbcd9a762e142c5cf1ce2e2_MD5.jpeg|Open: Pasted image 20250603132426.png]]
![[前端了解/Node/_resources/node/9d19ae1fbdbcd9a762e142c5cf1ce2e2_MD5.jpeg]]

文件的硬链接

多个文件平等地共享同一个文件存储单元(改变其中一份, 其他文件的内容也会变)
mklink /H foo.js foo_hard.js
[[前端了解/Node/_resources/node/3b67fc58b7a2c415f3432e30712e6715_MD5.jpeg|Open: Pasted image 20250603132740.png]]
![[前端了解/Node/_resources/node/3b67fc58b7a2c415f3432e30712e6715_MD5.jpeg]]

文件的软链接

mklink foo.js foo_hard.js

[[前端了解/Node/_resources/node/eab8bb7351e7d0e0516366e9b9b1867e_MD5.jpeg|Open: Pasted image 20250603133709.png]]
![[前端了解/Node/_resources/node/eab8bb7351e7d0e0516366e9b9b1867e_MD5.jpeg]]

pnpm

  • 磁盘空间优化:通过硬链接共享依赖,显著节省了磁盘空间。
  • 高效的依赖管理:依赖安装速度快,尤其是在多个项目共享依赖时表现优秀。
  • 强制封闭依赖:避免隐式依赖,提高了依 赖管理的可靠性。

pnpm的原理

使用pnpm, 依赖包将被存放在一个统一的位置,因此:

  • 如果对同一依赖包使用相同的版本,那么磁盘上只有这个依赖包的一份文件
  • 如果对同一依赖包需要使用不同的版本,则仅有版本之间不同的文件会被存储起来
  • 所有文件都保存在硬盘上的统一的位置:
  • 当安装软件包时,其包含的所有文件都会硬链接到此位置,而不会占用额外的硬盘空间
  • 可以在项目之间方便地共享相同版本的依赖包

非扁平化的 node_modules 目录

所有文件都会存储在硬盘上的某一位置. 当软件包被安装时, 包里的文件会硬链接到这一位置, 而不会占用额外的磁盘空间 . 允许跨项目地享用同一版本的依赖

[[前端了解/Node/_resources/node/216694d140e0e8643ae60a379b195f29_MD5.jpeg|Open: Pasted image 20250603152432.png]]
![[前端了解/Node/_resources/node/216694d140e0e8643ae60a379b195f29_MD5.jpeg]]

pnpm的store存储

[[前端了解/Node/_resources/node/5992ee0d4fdaca3825d820a342aeb0f5_MD5.jpeg|Open: Pasted image 20250603155958.png]]
![[前端了解/Node/_resources/node/5992ee0d4fdaca3825d820a342aeb0f5_MD5.jpeg]]

webpack

webpack官方文档

webpack 的核心是一个用于现代 JavaScript 应用的静态模块打包器

  • 打包bundler: webpack可以将帮助我们进行打包,所以它是一个打包工具
  • 静态的static : 这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);
  • 模块化module: webpack默认支持各种模块化开发ES Module、CommonJS、AMD等;
  • 现代的modern: 现代前端开发面临各种各样的问题,催生了webpack的出现和发展;

前端开发的流程
[[前端了解/Node/_resources/node/a42138b7fc8da6b36cab5fc1353e9011_MD5.jpeg|Open: Pasted image 20250604105132.png]]
![[前端了解/Node/_resources/node/a42138b7fc8da6b36cab5fc1353e9011_MD5.jpeg]]

path

[[前端了解/Node/_resources/node/f588dfec8ef80c8883c609d36dab60ec_MD5.jpeg|Open: Pasted image 20250604131317.png]]
![[前端了解/Node/_resources/node/f588dfec8ef80c8883c609d36dab60ec_MD5.jpeg]]
[[前端了解/Node/_resources/node/1fe253f3c088785cef56223ff7286e52_MD5.jpeg|Open: Pasted image 20250604131328.png]]
![[前端了解/Node/_resources/node/1fe253f3c088785cef56223ff7286e52_MD5.jpeg]]

[[前端了解/Node/_resources/node/4d7bbf25139209bf647f3e62c551541d_MD5.jpeg|Open: Pasted image 20250604131334.png]]
![[前端了解/Node/_resources/node/4d7bbf25139209bf647f3e62c551541d_MD5.jpeg]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const path = require("path")

const filepath = "C:/abc/cba/nba.txt"

console.log(path.extname(filepath)) // ".txt"

console.log(path.basename(filepath)) //"nba.txt"

console.log(path.dirname(filepath)) // "C:/abc/cba"

const path1 = "/a/d/s"
const path2 = "../why/ksj/mae.txt"

console.log(path.join(path1, path2)) //"\a\d\why\ksj\mae.txt"

console.log(path.resolve("./acd/s", "./ehdy/sd", "../sda.txt"))
// "C:\Users\sai_8\Desktop\1\code\path\acd\s\ehdy\sda.txt"

console.log(path.resolve("as/sd", "./dsf", "/df.txt"))
// "C:\df.txt"

console.log(path.resolve("./sd/ads", "/dsf/sad", "./as.txt"))
// "C:\dsf\sad\as.txt"

webpack的安装

1
2
npm install webpack webpack-cli-g #全局安装
npm instal1 webpack webpack-cli-D #局部安装

webpack 和 webpack-cli的关系

  • 执行webpack命令,会执行node modules下的 .bin 目录下的webpack;
  • webpack 在执行时是依赖webpack-cli的,如果没有安装就会报错:
  • webpack-cli中代码执行时,才是真正利用webpack进行编译和打包的过程;
  • 所以在安装 webpack时,我们需要同时安装 webpack-cli(第三方的脚手架事实上是没有使用webpack-cli的,而是类似于自己的 vue-service-cli 的东西)

webpack的默认打包

  • 在目录下直接执行webpack命令
    • 生成一个dist 文件夹, 里面存放一个main.js 的文件, 就是打包之后的文件

-运行webpack 时, webpack 会查找当前目录下的 src/index.js 作为入口
如果当前项目中没有存在 src/index.js文件, 就会报错

通过配置指定出入口

1
npx webpack --entry ./src/main.js --output-path ./build

配置文件

在根目录下创建一个 webpack.config.js 文件,来作为webpack 的配置文件

[[前端了解/Node/_resources/node/097f3c1fd505f887c84cb2bbdabc1eb6_MD5.jpeg|Open: Pasted image 20250604155437.png]]
![[前端了解/Node/_resources/node/097f3c1fd505f887c84cb2bbdabc1eb6_MD5.jpeg]]

*如果配置文件名不是 webpack.config.js的名字 *

  • 可以通过 --config 来指定对应的配置文件
1
webpack --config 修改名称后的配置文件

loader的使用

  • loader 可以用于对模块的源代码进行转换

loader配置方式

webpack.config.js 文件中写明配置信息

module.rules 允许配置多个 loader
module.rules的配置 如下:

  • rules 属性对应的值是一个数组:[Rule]
  • 数组中存放的是一个个的Rule , Rule 是一个对象,对象中可以设置多个属性:
    • test属性:用于对resource (资源)进行匹配的,通常会设置成正表达式
    • use属性 :对应的值时一个数组:[UseEntry]
    • UseEntry是一个对像,可以通过对象的属性来设置一些其他属性
      loader:必须有一个loader属性,对应的值是一个字符串:
      
options : 可选的属性,值是一个字符串或者对象,值会被传入到 loader中;
query: 目前已经使用options来替代;

传递字符串(如:use:[‘style-loader’])是loader属性的简写方式(如:use:[{loader:’style-loader’}]);

  • loader属性:Rule.use:[{loader}]的简写。

因为loader的执行顺序事从右向左的(从下到上, 从后到前), 所以需要将 style-loader 写道css-loader 的前面

下载

1
2
npm install css-loader -D
npm install style-loader -D

[[前端了解/Node/_resources/node/48318a757d2ecc7795830fb554028204_MD5.jpeg|Open: Pasted image 20250604215809.png]]
![[前端了解/Node/_resources/node/48318a757d2ecc7795830fb554028204_MD5.jpeg]]

简写

1
 loader: "css-loader",
1
use: ["style-loader", "css-loader"]