一、为什么要隔离依赖?

1.1 不小心把私有包传出去的坑

之前我接触过一个电商团队,他们做了一套内部用的订单优惠计算工具包,本来只在公司内部的项目里用,结果有个刚入职的开发同学发包时,忘了切本地的npm registry,直接把这个包传到了公共npm平台。还好那时候这个团队名气小,公共npm的审核没那么严,虽然后来及时把包删掉了,但还是折腾了三天,很多依赖这个包的项目要改依赖源,而且还留下了潜在的泄露风险——如果是涉及用户敏感数据的加密包,后果不堪设想。

1.2 用@scope来隔离的好处

npm里有个叫@scope的机制,就是包名前面带@和组织名,比如@company/calc-discount。这个机制的核心作用就是把包归类到特定的组织下,公共npm平台根本不会接收带@组织名的包(除非是大厂主动注册的),这样就能从发布的源头,把公司的私有包和公共的第三方包彻底分开,不会出现混传的情况,完全不用担心误传到外部平台。

二、动手搭Verdaccio的@scope隔离环境

2.1 先装Verdaccio

我们要搭一个本地的私有npm registry,用Verdaccio就足够了,操作非常简单,技术栈统一用Node.js 18.x + npm 8.x + Verdaccio 5.x,所有示例都基于这个栈。安装和启动的命令如下:

# 全局安装verdaccio,适用于所有Node.js项目
npm install -g verdaccio
# 启动verdaccio,默认端口4873,直接跑就能用,不用额外配置服务器
verdaccio

启动后打开浏览器输入http://localhost:4873,就能看到Verdaccio的管理界面,接下来我们要配置@scope的规则。

2.2 配置Verdaccio开启作用域

Verdaccio的配置文件在用户目录的.config/verdaccio/config.yaml里,我们只需要修改核心部分,其他默认配置不用动:

# 私有作用域名称,所有带这个前缀的包都属于公司私有
scopes:
  - company
# 依赖配置:匹配所有@company开头的私有包
packages:
  '@company/*':
    access: $all # 公司所有开发人员都能访问这个私有包
    publish: $authenticated # 只有登录过的内部人员才能发布私有包
    proxy: npmjs # 公共依赖如果没在私有库,自动从公共npm拉,不用本地存

这个配置的核心是,所有名字带@company/的包,只会往我们搭的Verdaccio里发,绝对不会跑到公共npm,从发布规则上就卡死了误传的可能。

2.3 创建带@scope的测试包

接下来我们创建一个属于@company的测试包,就叫@company/calc-discount,专门用来算订单折扣,是公司内部用的工具:

// package.json,注意name字段带@company前缀
{
  "name": "@company/calc-discount",
  "version": "1.0.0",
  "description": "公司内部专属的订单折扣计算工具,绝不外传",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "公司技术部",
  "license": "ISC"
}

然后写核心的计算逻辑,存为index.js:

// 专属折扣计算函数,只在内部项目里用
function calcDiscount(price, discountRate) {
  // 加了参数校验,避免非法值传入,也是内部才有的逻辑
  if (discountRate < 0 || discountRate > 1) {
    throw new Error('折扣率必须在0到1之间,不能乱填');
  }
  return price * discountRate;
}
// 导出函数,其他项目才能用
module.exports = calcDiscount;

三、实际用的时候的操作

3.1 发布私有包到 Verdaccio

创建好包之后,我们要把它发布到刚才搭的Verdaccio里,步骤很简单:

# 进入测试包的目录
cd /path/to/your/calc-discount
# 先登录Verdaccio,地址是我们启动的本地服务地址:http://localhost:4873
# 按照提示输入用户名和密码(第一次注册账号即可)
npm adduser --registry http://localhost:4873
# 发布包,指定到我们的私有registry,这样就不会传到公共npm
npm publish --registry http://localhost:4873

发布完成后,打开Verdaccio的管理界面,就能在私有包列表里看到@company/calc-discount,说明已经成功发布,而且这个包不会出现在公共npm上。

3.2 安装依赖时怎么区分公共和私有

平时项目里装依赖时,我们可以给项目设置一个.npmrc文件,指定默认的registry,这样不用每次手动加--registry参数,也能区分私有和公共依赖:

# 进入你的项目目录,创建.npmrc文件,设置默认registry
echo 'registry=http://localhost:4873' >> .npmrc
# 安装公司内部的私有包,直接用包名就可以,自动从Verdaccio拉
npm install @company/calc-discount
# 安装公共第三方包,比如lodash,Verdaccio配置了自动代理,会从公共npm拉,不会影响私有包
npm install lodash

这样做的好处是,只要项目里有这个.npmrc配置,所有私有包都会从内部Verdaccio拉,公共包自动从外部拉,避免了开发时切错registry的问题。

四、场景、优缺点和注意事项

4.1 适合的应用场景

这个方案非常适合有内部依赖管理需求的中小团队,比如:开发了只在内部用的业务工具包、订单权限校验的核心组件、不想公开的SDK、内部的UI组件库(不想放到公共npm),这些私有依赖都可以用@scope隔离后放到Verdaccio里,和公共依赖彻底分开,不会混传。

4.2 这个方案的优缺点

优点很明显:第一,从发布源头隔离,完全避免私有包误传,不用事后删包擦屁股;第二,配置简单,都是npm原生的能力,不用额外的复杂工具;第三,权限控制灵活,可以设置只有内部人能发布,外部人只能看不能改;第四,成本低,只要一台普通的服务器就能搭Verdaccio,不用花钱买商业服务。 缺点也存在:第一,需要自己维护Verdaccio服务器,要做备份、更新,大团队还要考虑高可用;第二,新入职的开发同学需要先知道@scope的规则,不然可能搞错包的发布路径;第三,私有依赖的拉取需要连内部服务器,断网时就用不了。

4.3 要注意的细节

有几个细节一定要记牢:第一,绝对不要把@scope的包改成不带@的名字,不然npm会默认往公共npm发;第二,所有团队成员的.npmrc都要配对,或者在CI/CD流程里自动配置,避免有人忘改;第三,Verdaccio的publish权限一定要设成$authenticated,禁止匿名发布,不然有人可以往里面传恶意包;第四,定期清理不用的私有包,节省服务器空间;第五,如果需要公共依赖的镜像,可以在Verdaccio里配置proxy,自动同步常用的公共包,不用每次都从公共npm拉。

五、总结

用@scope作用域结合Verdaccio管理私有依赖,是目前中小团队里最实用、成本最低的私有依赖隔离方案,完全从发布流程上卡住了私有包误传的可能,避免了很多依赖泄露带来的风险。整个流程不用复杂的学习成本,只要按照步骤配置,就能快速搭建起自己的私有依赖管理体系,适合所有不同基础的开发者,不管是前端还是后端,只要会用npm就能上手。