1. 常见的script脚本及实现过程
在package.json中,scripts字段定义了一系列可以通过npm/yarn/pnpm运行的命令。这些脚本可以自动化开发流程。
常用脚本命令:
-
start: 通常用于启动开发服务器
"scripts": { "start": "react-scripts start" }实现过程:启动Webpack开发服务器,监听文件变化,热更新
-
build: 构建生产环境代码
"build": "react-scripts build"实现过程:
- 清理构建目录
- 转译代码(Babel)
- 打包资源(Webpack)
- 代码压缩优化
- 生成hash文件名
- 输出到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时:
- 先执行prebuild
- 然后执行build
- 最后执行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账号
- 访问npm官网点击"Sign Up"
- 填写用户名、邮箱、密码
- 验证邮箱
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 更新已发布的包
- 修改代码后更新版本号:
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
- 重新发布:
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当时的一些问题:
- 安装速度慢:npm是顺序安装,Yarn并行安装
- 不确定性:npm的node_modules结构不固定
- 网络问题:npm安装失败需要从头开始
- 离线模式:Yarn可以缓存包实现离线安装
主要特点
- 确定性:通过yarn.lock锁定依赖版本
- 扁平化安装:减少嵌套层级
- 网络优化:队列请求、失败重试
- 并行安装:提高速度
安装
npm install -g yarn
常用命令
yarn init # 初始化项目
yarn add [package] # 添加依赖
yarn remove [package] # 移除依赖
yarn install # 安装依赖
yarn upgrade # 升级依赖
yarn why [package] # 查看为什么安装某个包
官网
4. cnpm介绍
为什么出现?
cnpm由阿里巴巴推出,主要解决国内开发者访问npm registry速度慢的问题。
主要特点
- 国内镜像:使用淘宝npm镜像,下载速度快
- 兼容npm:命令与npm基本一致
- 私有registry支持:方便企业内使用
安装
npm install -g cnpm --registry=https://registry.npmmirror.com
常用命令
cnpm install [package]
cnpm publish
cnpm sync [package] # 同步npm包到cnpm
官网
5. npx介绍
为什么出现?
npx随npm 5.2.0版本发布,解决了以下问题:
- 临时安装使用命令行工具而不全局安装
- 直接运行项目本地安装的CLI工具
- 无需手动配置PATH
主要特点
- 临时安装执行:用完即删
- 本地优先:自动查找本地node_modules/.bin
- 远程执行:可以直接运行未安装的包
安装
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的以下问题:
- 磁盘空间浪费:多个项目重复安装相同依赖
- 安装速度慢:大量的文件复制操作
- 幽灵依赖:可以访问未声明的依赖(扁平化结构导致)
核心原理
- 内容寻址存储:所有依赖版本全局存储一次
- 硬链接:项目中的依赖链接到全局存储
- 符号链接:构建正确的依赖树结构
- 非扁平化node_modules:精确控制可访问的依赖
安装
npm install -g pnpm
常用命令
pnpm install # 安装依赖
pnpm add [pkg] # 添加依赖
pnpm update # 更新依赖
pnpm remove [pkg] # 移除依赖
官网
硬链接 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 # 软链接
这种结构确保:
- 只能访问显式声明的依赖
- 避免版本冲突
- 节省磁盘空间
pnpm的优势
- 节省磁盘空间:相同依赖只存储一次
- 安装速度快:避免大量文件复制
- 严格依赖:防止访问未声明的包
- 确定性:精确的依赖树结构
- 支持monorepo:高效处理多包项目
示例:幽灵依赖问题
在npm/yarn的扁平化结构中:
// package.json
{
"dependencies": {
"express": "^4.18.1"
}
}
// index.js
const lodash = require('lodash'); // 可以访问,尽管没有声明依赖
在pnpm中,上述代码会报错,因为lodash不是显式声明的依赖。