阅读视图

发现新文章,点击刷新页面。

断网也能装包? 我在物理隔离内网搭了一套完整的私有npm仓库

image.png

引言

你有没有想过这样一种场景,你所有的开发电脑全部都是内网的完全的物理隔离,而且这台电脑上没有安装前端开的的环境,但是你的项目又是不同的技术栈,比如说vue2、vue3、react等,同时你使用包管理器可能有npm、yarn、pnpm、bun等,而且你还需要在内网环境中开发桌面端类似于electron、tauri等,同时你的构建还需要二进制的依赖等,并且你还使用vue3开发了一些业务组件库之类的,解决这类问题,那这种你可能又两种选择:

  • 方案一:全部改成npm,把node_modules跟着项目走;
  • 方案二:使用verdaccio搭建完整的私服npm源,支持不同的技术栈和包管理器

那就引发出来一类场景:我们怎么在一台纯物理隔离的纯净电脑上搭建出支持不同技术栈的前端私有npm源!

下面我们将开启verdaccio使用,希望你读完这篇文章之后能对verdaccio有一定的了解和认识。

准备

由于我们是全新的环境,以windows环境为例,我们首选需要安装的是node, 但是我们的项目又涉及不同的vue版本等,所有的开发环境需要多个node版本,鉴于遮掩这样的情况我们需要node版本的管理工具,常见的用nvmfnmvolta等,这里以使用nvm为例进行安装(可以自己自行选择),下面以nvm进行操作。

换句话说下面的操作可以让我们在一个纯净的内网机器下把前端开发前置环境搭建起来!

NVM 安装部署

下面示例进行windows和linux的nvm的安装。

Windows环境安装

下载nvm-windows

在github上搜索nvm-windows, 进入项目,点击右侧的Releases的,下载 nvm-setup.exenvm-noinstall.zip

Github地址:github.com/coreybutler…

下载node js

访问 nodejs.org/dist/ 下载需要的版本

Windows版本列表:

https://nodejs.org/dist/v12.22.12/node-v12.22.12-win-x64.zip
https://nodejs.org/dist/v14.21.3/node-v14.21.3-win-x64.zip
https://nodejs.org/dist/v16.20.2/node-v16.20.2-win-x64.zip
https://nodejs.org/dist/v18.19.0/node-v18.19.0-win-x64.zip
https://nodejs.org/dist/v20.11.0/node-v20.11.0-win-x64.zip
安装nvm-windows
  • 点击 nvm-setup.exe 进行安装
  • 解压 nvm-noinstall.zip 到指定目录

安装目录以:C:\nvm为例, 后续操作都是再这个目录下进行,如需更换做相应的替换即可

安装时记住两个路径:

  • nvm安装路径:C:\nvm
  • node js符号链接路径:C:\Program Files\nodejs
手动添加node js版本

将下载的 node js 手动压缩包解压到 nvm 安装目录下:

操作步骤:

# 1. 解压 node-v12.22.12-win-x64.zip
# 2. 将解压后的文件夹重命名为 v12.22.12
# 3. 将 v12.22.12 文件夹移动到 C:\nvm\ 目录下
# 4. 重复以上步骤处理其他版本
# 目录结构应该是这样
C:\nvm\
  ├─ v12.22.12\
  │   ├─ node.exe
  │   ├─ npm
  │   └─ ...
  ├─ v14.21.3\
  ├─ v16.20.2\
  ├─ v18.19.0\
  └─ v20.11.0\
修改settings.txt

编辑 C:\nvm\settings.txt,进行下面的修改,修改对应的rootpath:

root: C:\nvm
path: C:\Program Files\nodejs
arch: 64
proxy: none
配置环境变量

确保以下环境变量已设置:

NVM_HOME = C:\nvm
NVM_SYMLINK = C:\Program Files\nodejs

Path 中添加:
%NVM_HOME%
%NVM_SYMLINK%

Linux环境安装

下载nvm

在github上搜索nvm, 进入项目,点击右侧的Releases的,下载对应版本的,解压即可。

Github地址: github.com/nvm-sh/nvm

下载node js

访问 nodejs.org/dist/ 下载需要的版本

Linux版本列表:

https://nodejs.org/dist/v12.22.12/node-v12.22.12-linux-x64.tar.gz
https://nodejs.org/dist/v14.21.3/node-v14.21.3-linux-x64.tar.gz

...

下载linux上需要的node安装包时需要注意架构版本arm和x64是有区别的,留意一下即可

安装nvm

步骤:

# 以某个版本为例
wget https://github.com/nvm-sh/nvm/archive/refs/tags/v0.39.0.tar.gz
tar -xzf v0.39.0.tar.gz
mv nvm-0.39.0 .nvm
配置环境变量

编辑 ~/.bashrc~/.zshrc

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

生效配置:

source ~/.bashrc  # 或 source ~/.zshrc
手动添加node js版本
# 创建版本目录
mkdir -p ~/.nvm/versions/node

# 解压并移动 Node.js
tar -xzf node-v12.22.12-linux-x64.tar.gz
mv node-v12.22.12-linux-x64 ~/.nvm/versions/node/v12.22.12

# 重复以上步骤处理其他版本

目录结构:

~/.nvm/versions/node/
  ├─ v12.22.12/
  ├─ v14.21.3/
  ├─ v16.20.2/
  ├─ v18.19.0/
  └─ v20.11.0/

NVM验证和使用

验证安装

# 重新加载环境
source ~/.bashrc

# 验证NVM
nvm --version

# 查看已安装的Node.js版本
nvm list

# 使用特定版本
nvm use 18.17.1

# 验证Node.js和npm
node --version
npm --version

# 测试npm基本功能
npm config list

使用操作

# 切换Node.js版本
nvm use 16.20.2    # 切换到16版本
nvm use 18.17.1    # 切换到18版本
nvm use 20.5.1     # 切换到20版本

# 设置默认版本
nvm alias default 18.17.1

# 查看当前使用的版本
nvm current

# 查看所有可用版本
nvm list

# 在特定版本下运行命令
nvm exec 16.20.2 node --version

# 显示可用命令
nvm --help

# 卸载指定版本(删除文件夹)
nvm uninstall 12.22.12

因为我们时离线安装,所有nvm install version其实不可用的,上述步骤就是手动的实现这个命令。

NVM常见问题

Linux找不到nvm命令

# 手动加载NVM
source ~/.nvm/nvm.sh

# 或者重新加载bashrc
source ~/.bashrc

切换版本后 node 命令无效

# Windows: 重新打开命令行窗口
# Linux/Mac: 检查 PATH 环境变量
echo $PATH

# 手动设置PATH
export PATH="$NVM_DIR/versions/node/v18.17.1/bin:$PATH"

npm 全局包丢失

这个是个比较常见的问题:

  • 每个node版本有独立的全局包目录
  • 切换版本后需要重新安装全局包

node版本无法切换

# 检查版本目录是否正确
ls -la ~/.nvm/versions/node/

# 手动设置PATH
export PATH="$NVM_DIR/versions/node/v18.17.1/bin:$PATH"

权限问题

# 修复NVM目录权限
chmod -R 755 ~/.nvm
chmod +x ~/.nvm/nvm.sh

NVM卸载

windows卸载

把安装目录和环境变量删除即可

linux卸载

如果需要完全卸载:

# 删除NVM目录
rm -rf ~/.nvm

# 从.bashrc中移除NVM配置
sed -i '/# NVM配置/,/# 加载nvm bash补全/d' ~/.bashrc

# 重新加载shell配置
source ~/.bashrc

上面的操作我们相当于再内网机器上安装了node和node的版本管理器,这是第一步也是前置准备工作,下面将进入到verdaccio搭建的正式环节。

Verdaccio 安装部署

首先想一个问题,我们的verdaccio是通过npm全局安装的,verdaccio是发布到npm js的,但是我的内网环境是访问不了npm js的?我需要怎么做呢?

下面以windows系统为例,详细说明我们要做的事情:

  • 第一步:可以上网的机器安装verdaccio
  • 第二部:利用verdaccio缓存需要的依赖,包括项目依赖和全局依赖(pnpm等)
  • 第三步:把verdaccio本身以及缓存的依赖全部平移到内部机器
  • 第四步:根据需求动态的更新verdaccio的storage中的依赖和config.yaml
  • 第五步:把更新的storage依赖和config.yaml传输到内部机器下做合并

重复上述步骤便能实现大多数场景的依赖私有化部署(但是某些特殊情况下可能不适用,后续单独说明)。

Windows环境安装部署

Verdaccio安装

我们上面已经安装了node,那我们直接使用npm再上网机上面直接全局安装

# 如果担心有问题,可以使用管理员权限安装
npm install -g verdaccio

# 其他包管理器的安装方式
yarn global add verdaccio
pnpm install -g verdaccio

等待安装完成即可。

安装完成之后执行:

verdaccio --version  # 验证是否安装成功

之后进行启动,启动之后的启动信息要注意查看,这是有用的:

C:\Users\LMX>verdaccio
info --- config file  - C:\Users\LMX\AppData\Roaming\verdaccio\config.yaml
info --- plugin @verdaccio/local-storage successfully loaded (storage)
info --- using htpasswd file: C:\Users\LMX\AppData\Roaming\verdaccio\htpasswd
info --- plugin verdaccio-htpasswd successfully loaded (authentication)
info --- plugin verdaccio-audit successfully loaded (middleware)
info --- plugin @verdaccio/ui-theme successfully loaded (theme)
warn --- http address - http://localhost:4873/ - verdaccio/6.2.1

如果不侧重私有包的管理的话,我们要关注两个地方:

  • C:\Users\LMX\AppData\Roaming\verdaccio\ (配置文件和storage所在路径)
  • http://localhost:4873/ (可视化地址,我们后续会让所有的依赖再这个地址简单显示)
注册安装源

verdaccio安装完成之后,后续一个比较重要的动作就是注册各个包管理器的registry,以便verdaccio可以正常的缓存依赖。

为所有的项目设置全局的注册中心:

npm set config registry http://localhost:4873 # 注册地址就是上面的verdaccio的访问地址

yarn config set registry http://localhost:4873

也可以为某个依赖单独注册:

npm install lodash --registry http://localhost:4873

其他常用的命令:

# 终端窗口打开项目的根目录
npm set registry http://localhost:4873/ --location project

# 单次依赖安装指定注册中心,以lodash为例
npm install lodash --registry http://localhost:4873

上面的命令其实就相当于再你的项目.npmrc下增加了注册中心, 你也可以直接修改.npmrc

registry=http://localhost:4873/

但是现在好多vue3的项目都是monorepo多包管理的,那我们肯定离不开pnpm,其实这里有扩展出来一点知识点,

纯内网机制下的pnpm全局安装,这是其实用两种实现思路。

  • 思路一: 借助verdaccio缓存pnpm依赖
  • 思路二: 借助npm的pack命令打包pnpm

思路二后续章节展开说明,先按照思路一进行实践。

按照上述步骤启动verdaccio,并指定pnpm的注册源:

verdaccio
npm  install  pnpm  --registry http://localhost:4873

这时verdaccio的窗口会显示pnpm的被缓存安装的信息:

C:\Users\LMX>verdaccio
warn --- This is a deprecated method, please use runServer instead
info --- config file  - C:\Users\LMX\AppData\Roaming\verdaccio\config.yaml
info --- plugin @verdaccio/local-storage successfully loaded (storage)
info --- using htpasswd file: C:\Users\LMX\AppData\Roaming\verdaccio\htpasswd
info --- plugin verdaccio-htpasswd successfully loaded (authentication)
info --- plugin verdaccio-audit successfully loaded (middleware)
info --- plugin @verdaccio/ui-theme successfully loaded (theme)
warn --- http address - http://localhost:4873/ - verdaccio/6.2.1
info <-- 127.0.0.1 requested 'GET /pnpm'
http <-- 200, user: null(127.0.0.1), req: 'GET /pnpm', bytes: 0/0
info --- making request: 'GET https://registry.npmjs.org/pnpm'
http --- 200, req: 'GET https://registry.npmjs.org/pnpm' (streaming)
http --- 200, req: 'GET https://registry.npmjs.org/pnpm', bytes: 0/5275788
http <-- 200, user: null(127.0.0.1), req: 'GET /pnpm', bytes: 0/779825
info <-- 127.0.0.1 requested 'POST /-/npm/v1/security/advisories/bulk'
http <-- 200, user: null(127.0.0.1), req: 'POST /-/npm/v1/security/advisories/bulk', bytes: 40/0
info <-- 127.0.0.1 requested 'GET /pnpm/-/pnpm-10.32.1.tgz'
http <-- 200, user: null(127.0.0.1), req: 'GET /pnpm/-/pnpm-10.32.1.tgz', bytes: 0/0
info --- making request: 'GET https://registry.npmjs.org/pnpm/-/pnpm-10.32.1.tgz'
http <-- 200, user: null(127.0.0.1), req: 'POST /-/npm/v1/security/advisories/bulk', bytes: 40/2
http <-- 200, user: null(127.0.0.1), req: 'GET /pnpm/-/pnpm-10.32.1.tgz', bytes: 0/4524746

之后去verdaccio的storage目录查看是否被正常的缓存了。

正常pnpm文件夹下有两个文件:

package.json
pnpm-10.32.1.tgz

正常的话,tgz的包是有大小的,当是ok的时候要注意了,当然也不可能只有pnpm这个一个依赖,它是依赖树,这里只是举例说明。

注意点:

我们使用verdaccio做依赖缓存时可能会遇到,依赖没有缓存到的情况,确实存在这种情况,一般的处理思路如下:

  • 清空缓存再次进行安装
  • 重启verdaccio再次进行安装
  • 条件允许的话删除整个verdaccio缓存再次安装

相关命令如下:

npm  cache clean --force
pnpm  store  prune
配置文件

上面配置完注册源了,我们需要来了解一下俩个文件config.yaml.verdaccio-db.json, 这两个文件对我们后续操作有帮助,需要了解它。

config.yaml

这个文件是和storage再同级目录的,文件的配置内容如下,我们需要了解其中的一些配置项:

# 缓存依赖的存储位置
storage: ./storage

# 监听所有网卡(让其他机器能访问)
listen: 0.0.0.0:4873

web:
  title: Verdaccio
auth:
  htpasswd:
    file: ./htpasswd

# 内网机器的一定要关闭uplinks
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
    cache: true

packages:
  "@*/*":
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs
  "**":
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs #  内网机绝对不能有这行
server:
  keepAliveTimeout: 60
middlewares:
  audit:
    enabled: true
log:
  type: stdout
  format: pretty
  level: http
i18n:
  web: en-US

cache属性官方的表述: 设置cache为false可以帮助节省你的硬盘空间。 这将避免存储tarballs,但是它将保留元数据在文件夹里。

其实官方的解释有点晦涩,其实可以这样理解:

  • cache: true(默认值); 从上游拉取的tarball会缓存到storage目录下,下次请求直接从本地返回
  • cache: false; tarball不会写入磁盘,但是包的元数据(package.json、版本列表等)依然会被缓存,每次请求tarball都会请求上游。

在解释一下tarball是啥? 答:是依赖包的tgz文件。

这个配置设置不当也是导致缓存不能进行的一个重要原因。

更近一步说明:

⚠️ 关键点:内网机:物理隔离环境下,一定要去掉 proxy: npmjs,否则每次装包都会卡在尝试连接外网。

⚠️ 关键点:外网机:可以上网的机器,不要去掉proxy但是cache不设置或者设置为true

.verdaccio-db.json

我们怎么理解.verdaccio-db.json

官方给的说法是:

微型数据库用于存储用户发布的私有包。 该数据库基于JSON文件,其中包含已发布的私有包列表以及用于令牌签名的秘密令牌。 首次启动应用程序时会自动创建。

文件的内容如下:

{ "list": [], "secret": "KzZPQifqvCrV7HBMyVPb1C9+FdWteKqe" }

我这里放出了secret(令牌密钥), 正常来说这个是不能暴漏的,只做演示用。

启动verdaccio,访问: http://localhost:4873, 我们会发现什么也没有,那是因为我们的list: []是空的。

只用我们发部私服npm包时(发布私服包verdaccio才主动写入数据库文件),list才会更新。

但是我们想要verdaccio承担私用npm的方式,所有我们想要我们已经缓存的包放追加到list中,因此我们需要编写一个js文件sync-verdaccio-db.js来更新它:

主要实现的思路是访问:http://localhost:4873/-/all,获取所有的依赖数据。

const fs = require("fs");
const path = require("path");
const http = require("http");

const VERDACCIO_URL = "http://localhost:4873";
// 根据实际路径调整
const DB_PATH = path.join(__dirname, "storage", ".verdaccio-db.json");

/**
 * 获取所有包名(从/-/all)
 * @returns
 */
function fetchPackages() {
  return new Promise((resolve, reject) => {
    http
      .get(`${VERDACCIO_URL}/-/all`, (res) => {
        let data = "";
        res.on("data", (chunk) => (data += chunk));
        res.on("end", () => {
          try {
            const json = JSON.parse(data);
            resolve(Object.keys(json)); // 返回包名数组
          } catch (e) {
            reject(e);
          }
        });
      })
      .on("error", reject);
  });
}

/**
 * 更新数据库文件
 * @param {*} packages
 */
function updateDb(packages) {
  let db;
  try {
    db = JSON.parse(fs.readFileSync(DB_PATH, "utf8"));
  } catch (e) {
    // 文件不存在或损坏,创建一个新的
    db = {
      list: [],
      secret: require("crypto").randomBytes(16).toString("hex"),
    };
  }
  // 去重并排序(可选)
  db.list = [...new Set(packages)].sort();
  fs.writeFileSync(DB_PATH, JSON.stringify(db, null, 2));
  console.log(
    `[${new Date().toISOString()}] Database updated with ${db.list.length} packages.`,
  );
}

/**
 * 主函数
 */
async function main() {
  try {
    const packages = await fetchPackages();
    updateDb(packages);
  } catch (err) {
    console.error("Sync failed:", err.message);
  }
}

main();

注意: 我们上面的做法只是想让安装了哪些依赖都显示出来,依赖是有依赖树的,这个默认都理解,不做过多解释!

先启动verdaccio, 再storage的同级目录使用node执行sync-verdaccio-db.js文件即可,如下:

node  .sync-verdaccio-db.js

⚠️ 完成之后重启verdaccio,再浏览器中打开http://localhost:4873 , 可以查看缓存的依赖了。

创建用户

verdaccio的用户注册和登录之类的也加单说明一下,可以后续会用的上,但不是当前文章的侧重点。

使用npm 8或更低版本时, adduser或login都可以同时创建用户并登录。

npm adduser --registry http://localhost:4873

在 npm@9 之后的版本,这两个命令分开工作:

npm login --registry http://localhost:4873
npm adduser --registry http://localhost:4873

默认情况下,两个命令都依赖于web登录,添加 --auth-type=legacy 可以使用之前的登录方式。

内网部署

上述操作完成之后,下一步需要做的就是怎么把verdaccio整体部署到内网机器了,只要把verdaccio移入到内网机器,启动起来,后续只需要 更新storage和.verdaccio-db.json就可以实现依赖的更新了。

其实也有两种思路:

  • 思路一: 使用npm的pack打包verdaccio, 之后再内网机器使用npm全局安装
  • 思路二: 把上网机器上的安装的verdaccio直接复制到内网机(个人推荐最可靠方式)

思路一感觉上规范,但是可能遇到意想不到的问题,思路二在windows环境成功率更高,先介绍思路二,在说明思路一。

上面已经全局安装了,我们需要查看全局安装路径

npm  config  get  prefix

输出结果如下:

C:\Users\LMX>npm  config  get  prefix

C:\nvm4w\nodejs  # 这个路径是你自己的,每个人的安装路径都不一样

进入到安装目录复制相关文件到内网机器下npm的相同目录

需要复制的文件包括(verdaccio、verdaccio.cmd、verdaccio.ps1和node_modules/verdaccio文件夹):

image-20251126155020273.png

image-20251126155420136.png

最后内网机器验证verdaccio是否成功

verdaccio --version

verdaccio安装成功之后,启动verdaccio即可,在将上述保存的storage和config.yaml复制到内网机器下verdaccio缓存目录

思路一的方式虽然有点野路子,但是是在windows下尝试成功概率比较高的方式。

稍微解释一下为啥思路一的简单粗暴:

我们安装依赖的时候不是单个的依赖,却是复杂的依赖树,我们直接拷贝node_modules/verdaccio 相当于跳过了复杂依赖树的查找和安装过程,这种操作相当于是一个环境依赖平移的过程。

下面在来说明一下看似正规的思路一:

思路一要想成功需要很重要的一点,不光要npm pack verdaccio,而且要npm pack每一个verdaccio需要的子依赖,极其繁琐,容易出错。

那我们是否可以直接打包node_modules/verdaccio,类似于方案二的思想呢?那其实有回到思路二,这里先不做过多的说明, 其实本质上就是思路二脚本化和标准化的一个过程。

但是我们可以通过思路一和思路二想到一个更优的实践方式:

用 verdaccio 来引导 verdaccio

先用思路二在内网机上部署完verdaccio,在外网启动verdaccio,让它缓存verdaccio自身及其所有依赖,然后把存储数据一起复制到内网机verdaccio的缓存下。 其他内网机直接通过已安装的verdaccio的内网机安装verdaccio即可。

上面所有的安装都是以windows进行举例说明的,那当我们的开发环境是linux的时候,我们需要怎么做呢?

通常来说前端大部分的开发环境是都是windows的,所有windows部分才是我们最关心的!

正好借此说明一下不通过verdaccio缓存pnpm, 通过打包的方式平移pnpm

Linux环境安装部署

linux环境简短说明,大家了解即可,不是本篇文章的侧重点。

Verdaccio安装

# 安装 Verdaccio 和 pnpm
npm install -g verdaccio pnpm

# 验证安装
verdaccio --version
pnpm --version

确认安装结构

PREFIX=$(npm config get prefix)

# 查看可执行文件类型(确认是否为软链接)
ls -la $PREFIX/bin/ | grep -E "verdaccio|pnpm"
# 示例输出:
# lrwxrwxrwx ... verdaccio -> ../lib/node_modules/verdaccio/bin/verdaccio
# lrwxrwxrwx ... pnpm -> ../lib/node_modules/pnpm/bin/pnpm.cjs

# 查看模块目录
ls $PREFIX/lib/node_modules/ | grep -E "verdaccio|pnpm"

启动verdaccio并下载项目依赖

# 后台启动 Verdaccio
verdaccio &

# 配置 pnpm 使用 Verdaccio
pnpm config set registry http://localhost:4873/

# 安装所有项目依赖(会自动缓存到 Verdaccio)
cd /path/to/project1
pnpm install

cd /path/to/project2
pnpm install

# 重复所有项目...

# 完成后停止 Verdaccio
pkill -f verdaccio

打包所有文件

PREFIX=$(npm config get prefix)
mkdir -p ~/verdaccio-offline-package
cd ~/verdaccio-offline-package

# 打包完整模块目录(含所有子依赖,这是关键)
tar -czf verdaccio-full.tar.gz -C $PREFIX/lib/node_modules verdaccio
tar -czf pnpm-full.tar.gz -C $PREFIX/lib/node_modules pnpm

# 记录软链接目标路径(供内网还原使用)
VERDACCIO_LINK=$(readlink $PREFIX/bin/verdaccio)
PNPM_LINK=$(readlink $PREFIX/bin/pnpm)
PNPX_LINK=$(readlink $PREFIX/bin/pnpx 2>/dev/null || echo "")

cat > link-targets.txt << EOF
VERDACCIO_LINK=$VERDACCIO_LINK
PNPM_LINK=$PNPM_LINK
PNPX_LINK=$PNPX_LINK
EOF

echo "软链接信息已记录:"
cat link-targets.txt

# 打包 verdaccio 配置和依赖缓存
tar -czf verdaccio-data.tar.gz -C ~ .config/verdaccio

# 查看打包结果
ls -lh
# 应该看到:
# verdaccio-full.tar.gz    # Verdaccio 完整模块
# pnpm-full.tar.gz         # pnpm 完整模块
# link-targets.txt         # 软链接记录
# verdaccio-data.tar.gz    # 配置和依赖缓存

du -sh .

内网解压部署

cd /tmp
tar -xzf verdaccio-offline-linux.tar.gz
cd verdaccio-offline-package

# 查看文件
ls -lh

配置npm用户全局安装目录

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global

echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# 确认配置
npm config get prefix

还原模块文件

cd /tmp/verdaccio-offline-package
PREFIX=$(npm config get prefix)

# 确保目标目录存在
mkdir -p $PREFIX/lib/node_modules
mkdir -p $PREFIX/bin

# 还原完整模块(含所有子依赖)
tar -xzf verdaccio-full.tar.gz -C $PREFIX/lib/node_modules/
tar -xzf pnpm-full.tar.gz -C $PREFIX/lib/node_modules/

# 验证模块已还原
ls $PREFIX/lib/node_modules/ | grep -E "verdaccio|pnpm"

还原软链接

PREFIX=$(npm config get prefix)

# 读取外网记录的软链接目标
source /tmp/verdaccio-offline-package/link-targets.txt

# 建立软链接
ln -sf $PREFIX/lib/node_modules/$VERDACCIO_LINK $PREFIX/bin/verdaccio
ln -sf $PREFIX/lib/node_modules/$PNPM_LINK $PREFIX/bin/pnpm

# pnpx 可选
if [ -n "$PNPX_LINK" ]; then
    ln -sf $PREFIX/lib/node_modules/$PNPX_LINK $PREFIX/bin/pnpx
fi

# 验证软链接
ls -la $PREFIX/bin/ | grep -E "verdaccio|pnpm"

还原Verdaccio数据

tar -xzf /tmp/verdaccio-offline-package/verdaccio-data.tar.gz -C ~

# 验证
ls -la ~/.config/verdaccio/
ls ~/.config/verdaccio/storage/

设置systemd服务(可选)

PREFIX=$(npm config get prefix)

sudo tee /etc/systemd/system/verdaccio.service > /dev/null << EOF
[Unit]
Description=Verdaccio Private NPM Registry
After=network.target

[Service]
Type=simple
User=$USER
WorkingDirectory=$HOME
Environment=PATH=$PREFIX/bin:$HOME/nodejs/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=$PREFIX/bin/verdaccio
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl start verdaccio
sudo systemctl enable verdaccio

# 查看状态
sudo systemctl status verdaccio

# 查看日志
sudo journalctl -u verdaccio -f

缺失内容

上述我们只提到了最常见的场景,但是还有几类场景是不能忽视的,由于篇幅原因,这里先列出来,不做展开了,后续在补充。

  • electron/tauri等桌面端构建(涉及native binary 依赖的处理)
  • 二进制依赖, 如何处理 node-gyp、prebuild等
  • 私有业务组件库发布流程为涉及说明

扩展和思考

其实理论上有更加成熟的方案,Nexus Repository Manager或者淘宝 cnpm方案,但是cnpmcore对纯物理隔离部署有一定的要求,上述方案也是仅针对前端开发者去部署的,有更好的方案可以一起讨论。

文章同步地址:www.liumingxin.site/blog/detail…

❌