从零到一搭建私有NPM服务器

配图来着 Freepik

其实,我们每天都在使用 npmyarnhttps://www.npmjs.com 平台下载一些第三方的包,它们都属于开源的,任何人都可以免费下载并使用。

假设公司或者团队里面,想把一些可复用的模块抽离并形成 NPM 包,因涉及公司业务或其他原因,不能发布到 NPM 平台上。这时候我们可以在公司内部建立一个类似 https://www.npmjs.com 的私有的 NPM 平台,怎么做呢?

下面,我们从零到一搭建个人的 NPM 私有服务器。

一、选择

选择 Verdaccio 作为我们私有 NPM 仓库的平台,主要原因是免费、零配置,开箱即用。

当然,公司应该选择其他更加可靠、稳定付费平台了,本文适合个人玩耍~

二、NPM 平台搭建

安装、启动都非常简单~

# install
$ npm i -g verdaccio

# run
$ verdaccio

Verdaccio 跑起来之后,可以看到仓库地址就是:http://localhost:4873/

这是基于默认配置,暂时不作修改,配置文件在 /Users/frankie/.config/verdaccio/config.yaml

frankie@MacBook-Pro Verdaccio % 🐶 verdaccio

 warn --- config file  - /Users/frankie/.config/verdaccio/config.yaml
 warn --- Plugin successfully loaded: verdaccio-htpasswd
 warn --- Plugin successfully loaded: verdaccio-audit
 warn --- http address - http://localhost:4873/ - verdaccio/5.1.1
 http --- 127.0.0.1 requested 'GET /'
 http --- 304, user: null(127.0.0.1), req: 'GET /', bytes: 0/0
 http --- 127.0.0.1 requested 'GET /-/verdaccio/packages'
 http --- 304, user: null(127.0.0.1), req: 'GET /-/verdaccio/packages', bytes: 0/0

目前没有发包上来,就长这样...

我们修改以下 npmyarn 的镜像源 http://localhost:4873/

# 添加私有源(我使用了 nrm 来管理 npm 源)
$ nrm add frankie-loc http://localhost:4873/
# 切换源
$ nrm use frankie-loc
# or
# npm set registry http://localhost:4873/

# 注册用户,对应你 NPM 账号密码(若没有,用邮箱注册一个即可)
$ npm adduser
# 查看当前用户是否是注册用户
$ npm who am i

关于 nrm 安装使用,看这里

三、发包

3.1 创建 NPM 项目

我们来创建一个最简单的 NPM 包项目,目录如下:

privative-npm
    ├── .gitignore                // 相应目录,发布时会忽略上传
    ├── .npmignore                // 同理,会忽略上传
    ├── index.js                  // 作为入口
    ├── package.json              // 包描述文件
    └── README.md                 // 项目说明

一个 NPM 包,其中 nameversion 是必需的,其他都可以省略,而且 name 不能与平台上已有包重名。

// package.json
{
  "name": "privative-npm", // 必需,不能有大写字母、空格、下划线
  "version": "1.0.0", // 必需,请严格遵循语义化
  "description": "Test only, not published to NPM.",
  "author": "Frankie <1426203851@qq.com>",
  "license": "MIT",
  "type": "module",
  "main": "./index.js"
}

由于演示而已,我们就只导出一个方法吧。注意,若在 node 下运行此包,我们使用了 ESM,因此需要在 package.json 设置 "type": "module"

// index.js
export default function log(str) {
  console.log(str)
}
3.2 发布 NPM 包

在发包之前,你需要去 NPM 平台官网注册一个账号。很简单省略...

完了之后,登录你的 NPM 账号:

# add
$ npm set registry http://localhost:4873/

# switch registry
$ npm config set registry http://localhost:4873/

# login npm account
$ npm adduser
# 登录过用 login,第一次则用 adduser,它包括了登录操作。
$ npm login

登录成功,长这样:

frankie@MacBook-Pro privative-npm % 🐶 npm login

Username: xxx
Password: 
Email: (this IS public) 1426203851@qq.com
Logged in as xxx on http://localhost:4873/.

在跟目录下,执行命令 npm publish 即可。或可在 package.json 脚本命令中定义。(后者更合适)

frankie@MacBook-Pro privative-npm % 🐶 npm publish

npm notice 
npm notice 📦  privative-npm@1.0.0
npm notice === Tarball Contents === 
npm notice 54B  index.js    
npm notice 212B package.json
npm notice 36B  README.md   
npm notice === Tarball Details === 
npm notice name:          privative-npm                           
npm notice version:       1.0.0                                   
npm notice package size:  416 B                                   
npm notice unpacked size: 302 B                                   
npm notice shasum:        887836aa4a154902faf31b13e60b8adcdd07b924
npm notice integrity:     sha512-fyzitNqmif188[...]hFY+zmcIW6qTg==
npm notice total files:   3                                       
npm notice 
+ privative-npm@1.0.0

看到已经上传成功了,刷新页面就能看到:

3.3 更新包

如果我们要更新包,其中版本号 version 一定要修改,否则会更新失败,如下:

frankie@MacBook-Pro privative-npm % 🐶 npm publish

...
npm ERR! code EPUBLISHCONFLICT
npm ERR! publish fail Cannot publish over existing version.
npm ERR! publish fail Update the 'version' field in package.json and try again.
npm ERR! publish fail 
npm ERR! publish fail To automatically increment version numbers, see:
npm ERR! publish fail     npm help version

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/frankie/.npm/_logs/2021-07-14T06_16_31_553Z-debug.log

这里我就只改个版本号吧,更新包的命令仍然是 npm publish,上传成功后,刷新页面可以看到新版本了。

另外,假设你开发了一个 NPM 包,然后要发布到 NPM 开源供其他开发者使用,一定要按照语义化版本规律进行更新。如果像本文在本地或个人服务器搭建着玩,就爱咋咋地!

3.4 撤销包

需要注意的是,在 NPM 平台撤销包,是有非常严格限制的,不是随意就能撤销已发布到平台的包的,详情可看:NPM Unpublish Policy

# 撤销包的某个版本
$ npm unpublish [<@scope>/]<pkg>@<version>

# 撤销包
$ npm unpublish [<@scope>/]<pkg>

如果你的目的是鼓励用户升级,或者您不想再维护软件包,请考虑改用 deprecate 命令。

$ npm deprecate <pkg>[@<version>] <message>

我们在安装一些依赖包的时候,不是经常看得到类似的东西吗,就是 deprecate 搞的鬼~

npm WARN deprecated core-js@1.2.7: core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues.

四、使用包

我们将 NPM 发布到私有或公开的 NPM 平台后,都可以通过 npmyarn 等包管理工具去安装到我们的项目中。

由于我们上面示例,是将 privative-npm 包发布到我们私有的 NPM 服务器下,因此需要将 npm 镜像源切换至 http://localhost:4873/ 即可:

# use npm
$ npm config set registry http://localhost:4873/

# use yarn
$ yarn config set registry http://localhost:4873/

随便创建一个项目,并安装 privative-npm 依赖包,在 node 环境运行一下 index.js 可以看到打印出 OK!,那说明成功了!

五、其他

假设我们在使用 http://localhost:4873/ 镜像源,去安装 reactvue 等包,它是怎么处理的呢?

首先,我们了解一下正常使用 NPM 安装、共享、发包的流程:

图片源自“十三月”

当我们使用 npmyarn 去安装一个模块(包)时,先检查 node_modules 目录是否已经缓存了该模块,如果没有便会向 NPM 平台查询。

NPM 提供了一个模块信息查询服务,通过访问:

registry.npmjs.org/packaename/version

就可以查到某个发布在 NPM 平台上模块的具体信息,以及下载地址。然后下载并解压到本地完成安装。

如果我们启用了私有 NPM 服务器,流程又有什么变化呢?

图片源自“十三月”

当我们启动 Verdaccio 时,可以看到配置文件是在用户根目录下的:/Users/frankie/.config/verdaccio/config.yaml

#
# 配置文件(这里我删除了一些默认注解)
# 更多请看: https://github.com/verdaccio/verdaccio/blob/master/packages/config/src/conf/default.yaml
#

# 上传的所有包存放目录
storage: ./storage
# 插件目录
plugins: ./plugins

# web 服务,即我们可以通过 web 查看我们上传的包。
web:
  title: Verdaccio
  # 一些关于 web 页面的配置项,我删掉了

# 验证信息
auth:
  htpasswd:
    # 用户信息存储目录
    file: ./htpasswd

# 公有仓库配置
uplinks:
  npmjs:
    # 默认
    # url: https://registry.npmjs.org/
    # 我们可以改成淘宝镜像源
    url: https://registry.npm.taobao.org/

packages:
  '@*/*':
    # scoped packages
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    # 代理。当我们安装一些私有服务器上没有的包时,它就会往这里找,即上面的 uplinks 配置
    proxy: npmjs

  '**':
    # 三种角色:所有人、匿名用户、认证(登录)用户
    # "$all", "$anonymous", "$authenticated"

    # 可访问包角色
    access: $all

    # 可发包、撤包角色
    publish: $authenticated
    unpublish: $authenticated

    # if package is not available locally, proxy requests to 'npmjs' registry
    proxy: npmjs

# 服务连接活跃时间
server:
  keepAliveTimeout: 60

middlewares:
  audit:
    enabled: true

六、参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容