包管理工具-2

188 阅读6分钟

1. 常见的script脚本及实现过程

在package.json中,scripts字段定义了一系列可以通过npm/yarn/pnpm运行的命令。这些脚本可以自动化开发流程。

常用脚本命令:

  • start: 通常用于启动开发服务器

    "scripts": {
      "start": "react-scripts start"
    }
    

    实现过程:启动Webpack开发服务器,监听文件变化,热更新

  • build: 构建生产环境代码

    "build": "react-scripts build"
    

    实现过程:

    1. 清理构建目录
    2. 转译代码(Babel)
    3. 打包资源(Webpack)
    4. 代码压缩优化
    5. 生成hash文件名
    6. 输出到build目录
  • test: 运行测试

    "test": "jest"
    

    实现过程:启动Jest测试框架,查找并运行测试文件

  • lint: 代码检查

    "lint": "eslint src"
    

    实现过程:运行ESLint检查src目录下的代码规范

  • prepublish: 在包发布前自动执行

  • postinstall: 在包安装后自动执行

脚本执行流程示例(以build为例):

"scripts": {
  "prebuild": "echo '准备构建...'",
  "build": "webpack --config webpack.prod.js",
  "postbuild": "echo '构建完成!'"
}

运行npm run build时:

  1. 先执行prebuild
  2. 然后执行build
  3. 最后执行postbuild

2. 通过npm发布自己的包

2.1 创建并配置package.json

初始化项目:

mkdir my-package
cd my-package
npm init

示例package.json配置:

{
  "name": "my-awesome-package",
  "version": "1.0.0",
  "description": "一个很棒的npm包",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["demo", "example"],
  "author": "Your Name",
  "license": "MIT",
  "files": ["index.js", "lib/"]
}

重要字段说明:

  • name: 包名(必须唯一)
  • version: 遵循语义化版本规范
  • main: 入口文件
  • files: 包含在发布包中的文件(默认包含所有文件)

2.2 注册npm账号

  1. 访问npm官网点击"Sign Up"
  2. 填写用户名、邮箱、密码
  3. 验证邮箱

2.3 登录npm

npm login

输入用户名、密码和邮箱

2.4 发布包

npm publish

如果是首次发布且包名包含scope(如@username/package),需要:

npm publish --access public

2.5 下载发布的包

npm install my-awesome-package

2.6 更新已发布的包

  1. 修改代码后更新版本号:
npm version patch  # 1.0.0 → 1.0.1
npm version minor  # 1.0.1 → 1.1.0
npm version major  # 1.1.0 → 2.0.0
  1. 重新发布:
npm publish

2.7 删除发布的包

24小时内可以删除:

npm unpublish my-awesome-package --force

超过24小时只能废弃:

npm deprecate my-awesome-package "此包已废弃,请使用new-package代替"

2.8 让包过期

npm deprecate my-awesome-package@1.0.0 "这个版本有安全问题,请升级到1.0.1"

3. Yarn介绍

为什么出现?

Yarn由Facebook、Google、Exponent和Tilde于2016年推出,解决了npm当时的一些问题:

  1. 安装速度慢:npm是顺序安装,Yarn并行安装
  2. 不确定性:npm的node_modules结构不固定
  3. 网络问题:npm安装失败需要从头开始
  4. 离线模式:Yarn可以缓存包实现离线安装

主要特点

  1. 确定性:通过yarn.lock锁定依赖版本
  2. 扁平化安装:减少嵌套层级
  3. 网络优化:队列请求、失败重试
  4. 并行安装:提高速度

安装

npm install -g yarn

常用命令

yarn init          # 初始化项目
yarn add [package] # 添加依赖
yarn remove [package] # 移除依赖
yarn install       # 安装依赖
yarn upgrade       # 升级依赖
yarn why [package] # 查看为什么安装某个包

官网

yarnpkg.com/

4. cnpm介绍

为什么出现?

cnpm由阿里巴巴推出,主要解决国内开发者访问npm registry速度慢的问题。

主要特点

  1. 国内镜像:使用淘宝npm镜像,下载速度快
  2. 兼容npm:命令与npm基本一致
  3. 私有registry支持:方便企业内使用

安装

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

常用命令

cnpm install [package]
cnpm publish
cnpm sync [package]  # 同步npm包到cnpm

官网

npmmirror.com/

5. npx介绍

为什么出现?

npx随npm 5.2.0版本发布,解决了以下问题:

  1. 临时安装使用命令行工具而不全局安装
  2. 直接运行项目本地安装的CLI工具
  3. 无需手动配置PATH

主要特点

  1. 临时安装执行:用完即删
  2. 本地优先:自动查找本地node_modules/.bin
  3. 远程执行:可以直接运行未安装的包

安装

npx随npm自动安装,无需单独安装

常用命令

npx create-react-app my-app  # 临时安装并执行
npx eslint .                # 运行本地安装的eslint
npx -p node@14 node -v      # 指定node版本运行

官网

npx是npm的一部分,参考npm文档:docs.npmjs.com/cli/v7/comm…

6. pnpm介绍

为什么出现?

pnpm解决了npm/yarn的以下问题:

  1. 磁盘空间浪费:多个项目重复安装相同依赖
  2. 安装速度慢:大量的文件复制操作
  3. 幽灵依赖:可以访问未声明的依赖(扁平化结构导致)

核心原理

  1. 内容寻址存储:所有依赖版本全局存储一次
  2. 硬链接:项目中的依赖链接到全局存储
  3. 符号链接:构建正确的依赖树结构
  4. 非扁平化node_modules:精确控制可访问的依赖

安装

npm install -g pnpm

常用命令

pnpm install     # 安装依赖
pnpm add [pkg]   # 添加依赖
pnpm update      # 更新依赖
pnpm remove [pkg] # 移除依赖

官网

pnpm.io/

硬链接 vs 软链接 vs 拷贝

硬链接 (Hard Link)

  • 定义:指向文件数据的另一个名称(同一inode)
  • 特点
    • 删除原文件不影响硬链接访问
    • 不占用额外磁盘空间
    • 不能跨文件系统
  • pnpm应用:所有项目共享全局存储的依赖文件
# 创建硬链接
ln file.txt hardlink.txt

软链接 (Symbolic Link)

  • 定义:指向另一个文件路径的快捷方式
  • 特点
    • 占用少量空间存储路径信息
    • 原文件删除后链接失效
    • 可以跨文件系统
  • pnpm应用:构建正确的依赖树结构
# 创建软链接
ln -s file.txt symlink.txt

拷贝 (Copy)

  • 定义:创建文件的完整副本
  • 特点
    • 完全独立的新文件
    • 占用双倍空间
    • 修改不影响原文件
  • npm/yarn应用:传统安装方式

pnpm的node_modules结构

pnpm创建非扁平的node_modules,例如:

node_modules/
├── .pnpm/          # 所有依赖的硬链接
│   ├── lodash@4.17.21/
│   └── express@4.18.1/
├── express -> .pnpm/express@4.18.1/node_modules/express  # 软链接
└── lodash -> .pnpm/lodash@4.17.21/node_modules/lodash    # 软链接

这种结构确保:

  1. 只能访问显式声明的依赖
  2. 避免版本冲突
  3. 节省磁盘空间

pnpm的优势

  1. 节省磁盘空间:相同依赖只存储一次
  2. 安装速度快:避免大量文件复制
  3. 严格依赖:防止访问未声明的包
  4. 确定性:精确的依赖树结构
  5. 支持monorepo:高效处理多包项目

示例:幽灵依赖问题

在npm/yarn的扁平化结构中:

// package.json
{
  "dependencies": {
    "express": "^4.18.1"
  }
}

// index.js
const lodash = require('lodash'); // 可以访问,尽管没有声明依赖

在pnpm中,上述代码会报错,因为lodash不是显式声明的依赖。