包管理工具
www.npmjs.com 无法访问或访问速度慢,可以使用这些平台代替 包搜索平台
npm
安装,源管理,更新,卸载
安装
安装 node 时,会一同安装 npm
源管理
查看源地址:
npm config get registry 或 npm config get
设置源地址:
- 淘宝源:
npm config set registry https://registry.npm.taobao.org - 官方源:
npm config set registry https://registry.npmjs.org/
更新
shell
npm -v
# 清理 npm 缓存数据
npm cache clean --force
npm install -g npm
# 更新到指定版本
npm -g install npm@6.8.0
卸载
依赖安装,更新以及删除与全局依赖管理
依赖安装
shell
# 将依赖安装到项目的dependencies
npm i xxx
# 安装指定版本
npm i xxx@xx
# 将依赖安装到项目的devDependencies
npm i xxx -D
# 安装全局依赖
npm i xxx -g
依赖删除
shell
# 删除全局依赖
npm uninstall xx -g
# 删除依赖
npm uninstall xx
全局依赖管理
全局依赖安装位置: npm root -g
更改全局包位置:
yarn
pnpm
配置 PNPM 全局安装路径
pnpm config set store-dir <global-store-path>
如:
pnpm config set store-dir E:\.pnpm-store\global
配置 PNPM 全局 bin 文件安装路径
pnpm config set global-bin-dir <store-bin-path>
配置 PNPM cache 路径
pnpm config set cache-dir <store-cache-path>
配置 PNPM state 路径 配置当前仅由更新检查器使用的 pnpm-state.json 文件的目录
pnpm config set state-dir <store-state-path>
以上命令行的方式最终会输出到~/.npmrc文件, 所以以上方式可以在~/.npmrc文件中输入
global-bin-dir=E:\.pnpm-store\bin
global-dir=E:\.pnpm-store\global
state-dir=E:\.pnpm-store\state
cache-dir=E:\.pnpm-store\cache
修改完相关目录之后,进行全局依赖安装提示类似如下错误:
pnpm now wants to use the store at " D:\.pnpm-store\2 " to link dependencies. If you want to use the new store location, reinstall your dependencies with
则需要到原的全局目录,删除该目录下的已存在内容
安装全局模块时出现类似如下警告,则使用管理员权限打开 cmd,再重新运行
WARN EXDEV: cross-device link not permitted, link
pnpm exec
在项目范围内执行 shell 命令。
如果您将 Jest 作为项目的依赖项,则无需全局安装 Jest,只需使用 pnpm exec 运行它:
shell
pnpm exec jest
pnpm dlx
从源中获取包而不将其安装为依赖项,热加载,并运行它公开的任何默认命令二进制文件。
例如,若要在任何地方使用 Create-react-app 来初始化一个 react 应用,而不需要 来在另一个项目下安装它,您可以运行:
shell
pnpm dlx create-react-app ./my-app
查看当前项目安装包的实际版本
shell
pnpm list
# 或者
pnpm ls
依赖安装,更新,删除
依赖安装
shell
# 安装所有依赖
pnpm install
# 将依赖安装到项目的dependencies
pnpm add xxx
# 安装指定版本
pnpm add xxx@xxx
# 将依赖安装到项目的devDependencies
pnpm add xxx -D
# 安装全局依赖
pnpm add xxx -g
shell
# 安装所有依赖,且不更新lockfile
pnpm install --frozen-lockfile
shell
# 安装所有依赖,且仅从 store 中离线下载,如果store中没有,则下载失败
pnpm install --offline
shell
# 安装所有依赖,本地存在的包从store下载,不存在的包从npm仓库下载
pnpm install --prefer-offline
如果在 pnpm 的 workspace 中执行pnpm install则表示在在工作空间以及子项目都执行pnpm install, 如果只想表示执行当前项目的pnpm install, 则需要创建.npmrc配置文件, 将recursive-install设置为false
.npmrc
recursive-install=false
依赖更新
shell
# 更新所有依赖
pnpm up
# 更新到指定版本
pnpm up foo@2
依赖删除
shell
# 删除指定依赖
pnpm remove xx
# 删除全局依赖
pnpm remove xx --global
使用 pnpm 构建 Monorepo 项目
monorepo 是什么
monorepo 是把多个项目的所有代码放到一个工作空间进行管理,同一个工作空间的多个子项目之间可以非常方便的共享/共用公共代码
有什么好处?
比如一个项目包含 PC 端和移动 H5 端, 那么其中共用的代码,就可以抽取到一个单独的子项目中,然后 PC 端项目和移动 h5 项目,同时引用这个单独的子项目,减少重复代码,同时也可以避免同样的功能逻辑,有两份不同的实现
可以一边做项目一边抽取独立的组件,独立组件单独发布到 npm 仓库,不断增强自己的抽象能力,也不断积累自己的可复用组件
创建 Monorepo 项目
shell
mkdir test-monorepo
cd test-monorepo
pnpm init
touch pnpm-workspace.yaml
pnpm-workspace.yaml
yaml
packages:
# 告诉pnpm从哪些目录扫描子项目,当前配置,pnpm会从packages目录和example目录扫描子项目
- 'packages/**'
- 'example/**'
# 不包括在 test 文件夹下的 package
- '!**/test/**'
shell
pnpm install vue vite -w
-w参数表示将依赖安装在整个workspace, 此种方式安装的依赖,相当于是工作空间内的全局依赖. 该包会放置在 <root>/node_modules 下
如果是一个开发依赖的话,可以加上 -D 参数,表示这是一个开发依赖,会装到 pacakage.json 中的 devDependencies 中,比如:
shell
pnpm install rollup -wD
shell
pnpm i dayjs -r --filter @test/web
-r --filter 表示将dayjs仅安装在@test/web子项目中,@test/web是package.json中name的值
对于局部依赖,最简单的办法就是
shell
# 进入子项目的根目录
cd packages/http
# 在子项目的根目录直接安装依赖,该依赖就会是局部依赖,只有这个子项目能使用
pnpm install axios
需要注意的是,--filter 参数跟着的是package下的 package.json 的 name 字段,并不是目录名。
关于 --filter 操作其实还是很丰富的,比如执行 pkg1 下的 scripts 脚本:
shell
pnpm build --filter @qftjs/monorepo1
filter 后面除了可以指定具体的包名,还可以跟着匹配规则来指定对匹配上规则的包进行操作,比如:
pnpm build --filter "./packages/**"
此命令会执行所有 package 下的 build 命令。
packages/utils 子项目的package.json文件如下
json
{
"name": "@test/utils", // <-----
"version": "1.0.0",
"description": "",
"main": "index.ts",
"author": "Innei",
"license": "MIT",
"dependencies": {}
}
入口文件为 index.ts, 内容如下
ts
export const add = (a: number, b: number) => a + b
将某个子项目以第三方依赖的方式,添加到该工作空间中的另一个子项目
shell
pnpm i @test/utils -r --filter @test/ui
@test/utils和@test/ui都是该工作空间的子项目,上面这个语句表示:将@test/utils项目以第三方依赖的形式,添加到@test/ui中,此时@test/ui的package.json 就会多出这个@test/utils dependencies的依赖
json
{
"name": "@test/ui",
"version": "1.0.0",
"description": "",
"main": "./index.tsx",
"scripts": {},
"author": "Innei",
"license": "MIT",
"dependencies": {
"@test/utils": "workspace:^1.0.0"
}
}
由于是 workspace 管理的,所有有一个前缀 workspace。
在设置依赖版本的时候推荐用 workspace:*,这样就可以保持依赖的版本是工作空间里最新版本,不需要每次手动更新依赖版本。
shell
pnpm add @monorepo/http@* --filter @monorepo/web
比如 web 需要依赖 http 的功能用于请求,那么这个时候需要互相依赖,为了让依赖实时更新最新版本,才用通配符更新版本
接下来则可以从 package/ui 中直接引入这个包了。
ts
import { add } from '@test/utils'
当 pnpm publish 的时候,会自动将 package.json 中的 workspace 修正为对应的版本号。
常用 monorepo pnpm 命令
- 列出这个包的源码位置,被 monorepo 内部哪些项目引用了。
shell
pnpm why -r
- 取消某个依赖的安装
shell
pnpm remove axios
pnpm remove axios --filter @monorepo/http
只允许 pnpm
当在项目中使用 pnpm 时,如果不希望用户使用 yarn 或者 npm 安装依赖,可以将下面的这个 preinstall 脚本添加到工程根目录下的 package.json中:
json
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
preinstall 脚本会在 install 之前执行,现在,只要有人运行 npm install 或 yarn install,就会调用 only-allow 去限制只允许使用 pnpm 安装依赖。
严格限制 node 版本和 pnpm 版本
json
// package.json
"engines": {
"node": "16.13.0",
"npm": "8.1.0"
}
在根目录下 .npmrc 添加 engine-strict=true
# .npmrc
engine-strict=true
根目录放一个.nvmrc切换 node 版本更方便,nvm use 就可以切换,不需要后面加版本号
# .nvmrc
v16.17.0
限制运行时 node 版本
经常会遇到,有的小伙伴 npm run dev 启动不了项目了。在服务器上运行 npm run build 报语法错误了,本地尝试却是好好的。很多时候都是因为 node 版本不兼容。
在 package.json 中添加 npm scripts 钩子。可以在运行 npm run dev 、 npm run build 之前去执行
json
// package.json
{
"script": {
"predev": "npm run check:node", // 开发时校验
"prebuild": "npm run check:node" // 打包时校验
"check:node": "node ./misc/checkNode",
}
}
校验当前 node 版本与项目要求的 node 版本是否匹配。如果不匹配,打印错误提示信息,终止进程。
js
// misc/checkNode.js
const { engines } = require('../package')
let semver = null
try {
semver = require('semver') // 校验版本号的一个工具
} catch (error) {}
const version = engines.node
if (semver && !semver.satisfies(process.version, version)) {
console.error(`Required node version ${version}, got: ${process.version}.`)
process.exit(1)
}
if (!semver && process.version !== version) {
console.error(`Required node version ${version} and npm version ${engines.npm}, got: ${process.version}.`)
process.exit(1)
}
启动项目
使用 node packages/component (默认执行 index.js 文件)
shell
node packages/components
更好的选择是编写 npm scripts 就像下面这样:
json
"scripts": {
"test": "vitest",
"dev": "pnpm -C play dev",
"docs:dev": "pnpm run -C docs dev",
"docs:build": "pnpm run -C docs build",
"docs:serve": "pnpm run -C docs serve",
},
其中 -C \<path> 表示 在 path 下运行 npm 脚本 而不是在当前工作路径下。例如根目录下执行 npm run docs:dev 便会执行 docs/package.json dev 脚本,同理 build 和 serve 也是一样。