利用 verdaccio 搭建私有npm平台及在内网中使用
verdaccio
的安装使用方法,其官网上有更详情的内容。
这里我给大家重点介绍一下使用 docker
来安装,还有一些个性化的配置,以及邮件通知的配置方法。
安装
首先拉取 verdaccio
的镜像:
1
| docker pull verdaccio/verdaccio
|
利用 docker-compose.yml
来启动容器:
1 2 3 4 5 6 7 8 9 10 11 12 13
| version: "3" services: verdaccio: image: verdaccio/verdaccio:latest container_name: npm-verdaccio restart: always ports: - 4873:4873 volumes: - ./data/verdaccio/conf:/verdaccio/conf - ./data/verdaccio/storage:/verdaccio/storage - ./data/verdaccio/plugins:/verdaccio/plugins tty: true
|
在上面的配置中,我们将环境配置、库文件、插件目录都挂载到了本地当前对应的目录中,方便后面修改和数据的持久化。
运行启动容器:
之后,会看到挂载的目录会生成对应的文件,下面我们来修改配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| uplinks: npmjs: url: https://registry.npm.taobao.org
storage: ../storage
web: enable: true title: npm私有库 logo: /verdaccio/conf/logo.svg primary_color: "#de0000" favicon: /verdaccio/conf/favicon.ico pkgManagers: - pnpm - npm showInfo: false showSettings: false showThemeSwitch: false showFooter: false scriptsBodyAfter: - "<style></style>"
|
内网
如果你的 verdaccio
是搭建在内网的,还需要将外网的第三方包下载安装转移到内网。
这个工作首先需要在可以连接互联网的设备上同样使用 docker
安装 verdaccio
环境。
安装成功后,默认会在本地启一个 4873 的 http
服务。
本地还要安装 node
环境,通过 node
的 npm init
创建本地项目,通过当前项目的根目录文件 .npmrc
,如果没有可自行创建,内容为:
1
| registry=http://localhost:4873
|
这样,在本地安装安装的项目,将会从私有平台 4873
上下载获取第三方包,verdaccio
通过其设置的上游链接,去互联网上下载后,会缓存放置在 storage
目录中。
这样操作之后,在 verdaccio
的 storage
目录中就会存在我们需要的第三方包,我们可以将其转移到内网环境中。
1
| sudo tar --exclude=storage/@sg --exclude=storage/@wgl --exclude=storage/.verdaccio-db.json -zcvf storage.tar storage
|
上面的压缩命令,我们排除了本地测试的自定义包,和 verdaccio
的版本数据文件,是为了覆盖时不要把内网 verdaccio
里的私有数据覆盖了,只允许覆盖第三方包。
解压覆盖到内网 verdaccio
的 storage
目录后,重启内网的 docker
容器即可。
通知
verdaccio
给我们提供了 publish
的通知功能,当有新包被推送时,可以及时通知相关引用使用者,下面是一个比较好的通知配置:
1 2 3 4 5
| notify: method: POST headers: [{ "Content-Type": "application/json" }] endpoint: http://172.17.0.1:5000/send_email content: '{"subject":"{{ publishedPackage }}已推送","sendMail":"`{{#each versions}} {\"enable\":\"{{ sendMail.enable }}\",\"msg\":\"{{sendMail.msg}}\",\"to\":\"{{sendMail.to}}\"}{{/each}}`","message":"User:{{ publisher.name }}<br/>Package:{{ publishedPackage }}`{{#each versions}} <br/> Author:{{author.name}}<br/>Email:{{author.email}}<br/>Integrity:{{dist.integrity}}<br/>Tarball:{{dist.tarball}}{{/each}}`","notify":true,"message_format":"text"}'
|
这里的 endpoint
是接口地址,我们可以使用 express
框架来建立一个发送邮件的服务。
index.js
的服务文件内容如下:
点击查看完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| const express = require("express"); const nodemailer = require("nodemailer"); const bodyParser = require("body-parser");
const app = express(); const PORT = 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const baseFormat = (obj) => { for (let key in obj) { if (typeof obj[key] === "string") { obj[key] = obj[key].replaceAll("`", "").trim(); } } return obj; };
const emailConfig = { defaultTo: ["webape@qq.com"], from: "webape@qq.com", host: "smtp.qq.com", port: 465, user: "webape@qq.com", pass: "******", };
app.post("/send_email", (req, res) => { const body = baseFormat(req.body); const { sendMail, subject, message } = body; console.log("body", body);
const sendMailObj = baseFormat(JSON.parse(sendMail));
if (["true", ""].indexOf(sendMailObj.enable) > -1) { const defaultTo = emailConfig.defaultTo; const mailOptions = { from: emailConfig.from, to: sendMailObj.to ? sendMailObj.to.split(",").map((item) => item.trim()) : defaultTo, subject: subject, html: message.replaceAll("`", "") + (sendMailObj.msg ? '<div style="background-color:red;color:#fff">' + sendMailObj.msg + "</div>" : ""), };
const transporter = nodemailer.createTransport({ host: emailConfig.host, port: emailConfig.port, auth: { user: emailConfig.user, pass: emailConfig.pass, }, });
transporter.sendMail(mailOptions, (error, info) => { if (error) { console.log(error); res.status(500).send("邮件发送失败"); } else { console.log("Email sent: " + info.response); res.send("邮件发送成功"); } }); } });
app.listen(PORT, "172.17.0.1", () => { console.log(`Server is running on http://172.17.0.1:${PORT}`); });
|
可以看到上面的服务是绑定在 ip:172.17.0.1 上的,这个是 docker
的网关地址,使 docker
内部可以访问外部宿主机的 http
服务。
我们可以在和 verdaccio
同一服务器中后台启动该服务:
1 2 3 4
| # 在后台执行程序 nohup node index.js & # 将该进程与当前 shell 分离,避免关闭当前 shell 连接后进程关闭 disown
|
由于 verdaccio
的通知是读取的项目的 package.json
的数据在我们的项目的 package.json
文件中,我们可以添加以下内容来配合邮件通知的发送行为和内容:
1 2 3 4 5
| "sendMail":{ "enable":true, "msg":"提示信息", "to":["webape@qq.com"] },
|
配置说明:
- 当
package.json
中没有定义 sendMail
对象时,默认会向内置的默认用户发送通知邮件。
- 当
sendMail.enable
为 true
时,表示发送邮件,false
时表示不发送邮件,默认为 true
。
- 用户可以通过
sendMail.msg
来在邮件中指定提示信息,例如,“此版本为测试版本,请勿使用”。
- 用户可以通过指定
to
来限定邮件的发送范围,为空数组时,默认会向内置的默认用户发送。
注意
私有库绑定域名后,用什么域名第一次访问,则默认就是哪个域名。
我们一般还会配合绑定域名使用成功一个可以对外提供服务的站点,需要注意的时,绑定域名后,第一次访问后,再次访问需要使用该域名才能访问。
私有库需要 npm adduser
添加用户后输入邮箱后半天没有反应,应该是 htpasswd
文件写权限问题。
可以给其 775
的权限。
使用 pnpm
时的缓存问题。
因为 pnpm
本身也会创建本地的存储库,当想在外网缓存外部库转到内网中时,.nprc
配置 registry=[地址],执行 pnpm store prune
,pnpm store path
查看缓存库位置删除,删除 node_modules
和 pnpm-lock.yaml
,后执行 pnpm install
。