外网向内网导包的坎坷之旅

2024-07-10
320611 分钟
...

最近工作遇到个问题,一开始项目是在外网运行的,后来需要导入内网运行,我一开始是把node_modules整个目录拷贝过去了,结果运行不起来,可能因为项目是pnpm的,直接从mac拷贝到windows似乎是运行不起来。然后尝试自己下载,缺了好多包,也启动不了运行不起来,最后只好开始了我的导包之旅。

这是一个悲伤的故事,前前后后和对应的人员来回导包4、5次,历时几周才搞完,因为项目不着急,所以就没有急着去搞,真是尴尬。下面就是我的导包之旅:

第一次:我是直接npm install来安装项目,遇到不能安装的话,就把这个包记录下来,而由于项目是pnpm的,并且有pnpm-lock.yaml文件,这样包的版本都是严格模式,即使内网有某个包的版本,但是只要不是同一版本就不算数。

最开始写了n个包,给了负责包的人一份,好,开始等待,一两天后,对方说上传上去了,好,我去install,尼玛,还是有404的包。

第二次:开始把所有的package.json给他,让他去安装,但由于项目是menorepo的项目,所以给了至少8个package.json。给了之后,继续等待,这次等待有点长。大概几天后,我问他才给我说好了。

然而,我去install后还是有没装上的,不知道是不是给的太多了?这次我把pnpm-lock.yaml删除掉了,不然总是锁固定的版本,如果没有这个文件的话,^x.x.x的版本号还是会根据仓库有的版本去下载的,不会下不到准确的版本就直接报错。后来我在想为什么还是会有缺的?是我给错了还是他们的程序有bug?

第三次,对方开始有点不耐烦了,说让我自己用npm pack打包自己缺少的包给他,他直接上传,这样才知道原来他们是这样打包的。然后我就把缺少的包,全部用npm pack命令打包了下,给他,这次传的挺快,结果。。。还是有缺的,原来是因为这个命令打的包是不包含所打包的依赖的,所以是包的依赖又缺少了。

所以我问他要脚本,没给,说是让自己写一个,行吧,那就自己写吧。

核心逻辑是:安装一个包的时候用npm view ${packageName}@${version} dependencies --json命令获取它的依赖,然后递归安装,但是发现出现了死循环,又fix了一下。

后来想了下是不是直接用pnpm-lock.yaml就好了,里面有packages字段,就包含了所有的依赖以及版本号了,所以可以根据这个值把所有的包用npm pack进行打包,这样就可以了。

第四次:把缺少的文件的tgz都打包出来,给了对方,这下好了,终于好了。

整个故事,很纠结,持续时间也很长,因为不是特别着急,所以就慢慢等着,也没仔细去想,但后来到之后的时候我就发现,这其实是不是pnpm的离线安装方案?所以这个问题的本质是如何从本地安装包。

所以一顿搜查,发现一般的思路都是:

  1. 先在有网的环境的环境下把包安装成功
  2. 将包打成tgz格式(npm pack),导入到内网,npm install xxx.tgz包安装,但是这样安装,其实也没那么简单,因为有n多个包, 如果包太多,它有一些依赖的包没有对应的tgz包,它会去请求网络安装,但是因为离线所以也安装不成功,所以这样装要保证所有的tgz都在。

如果是npm的项目,可以尝试直接node_modules打zip包,有时候是可以的,而且一般同样的系统的话问题大不,但可能就是存在linux->windows,mac->windows这样,这种可能就出问题。

如果是pnpm项目,大概率是不能直接打zip包启动的,还是得用tgz的方式,因为这种方式是跟系统无关的。

npm pack

npm pack的使用可以参考:npm pack命令,就是把包打成对应的tgz包。使用场景:

  • 打包某个单独的包的版本:npm pack xxx@1.2.2。这样就可以把对应的包的tgz版本下载下来。
  • 如果你是开发某个npm包,那在当前开发包的目录下执行npm pack会把整个包打包下来,也会包含当前目录的node_modules

发现这个命令还是挺有用的,例如下面两个场景:

  1. 这种情况离线安装包,
  2. 当你开发一个npm包,需要发布给别人的时候,可以用这个命令打包给对方安装测试用,那就不用发测试包啦~

那npm pack链接可以从哪看呢?其实在package-lock.json里就有:

这个resolved就是下载链接,可以直接拷贝下来直接就把tgz包下载了,所以如果写自动化程序,是可以直接根据这个链接下载的。

可以使用的方案如下:

方案一:npm pack打包所有包的tgz

  1. 在一个有网的机器上安装所有的包,然后会生成pnpm-lock.yaml文件,再根据文件中packages字段下载所有的包的tgz,搜了一下发现已经有现成的开源工具了:
效果
get-npm-tgzpackage-lock下载、或者单独的包,提供了命令行
batch-download-tgzpackage-lock下载、或者单独的包,这个没有package-lock的命令行
node-tgz-downloader这个执行失败

这几个都可以实现这个功能。实现从外网往内网导包的工具,还是很方便的。试了一下第一、第二个都可以成功,包含直接给一个package-lock来下载,或者给一个单独的包下载,都可以成功。

第一个还提供了yarn.lock和pnpm-lock.yaml的方式,把这个格式转换成package-lock的格式,就可以使用这个工具了,而转换当然也是使用工具:

  • synp:将 yarn.lock 转化为 package-lock.json
  • pnpm-lock-to-npm-lock:将 pnpm-lock.yaml 转化为 package-lock.json
  1. 下载完所有的tgz包之后,可以把包放到要安装的目录下,pnpm install tgz/*, 但是在实际操作中遇到了问题,因为有tgz没有下载成功,所以当这样安装的时候,如果遇到没有的tgz包就会报错,也安装不成功。

方案二:store离线安装

请教了chatgpt后,给了一种方案,看起来还可以,所以尝试了下,最后成功啦!方案步骤:

在联网的机器上
  1. 安装所有依赖:确保所有依赖已经下载并存储在 pnpm 的本地缓存中。

    pnpm install
    
  2. 找到 pnpm 的缓存目录

    pnpm store path
    

    例如,输出可能是 /home/user/.pnpm-store.

  3. 压缩缓存目录

    使用 tar 命令压缩缓存目录。

    tar -czvf cache.tar.gz -C /home/user .pnpm-store
    

    这将创建一个名为 cache.tar.gz 的压缩文件,包含 .pnpm-store 目录。

    这里它还给了另外一种生成tar文件的方式:pnpm store export --file /path/to/cache.tar.gz, 但是这种方式我并没有成功,报file参数错误。。所以就只能用本地打tar包的形式了。

  4. 复制 package.jsonpnpm-lock.yaml 文件

    确保将项目根目录下的 package.jsonpnpm-lock.yaml 文件复制到离线机器上。

在离线的机器上
  1. 传输缓存文件和项目文件

    cache.tar.gz 文件、package.jsonpnpm-lock.yaml 文件传输到离线机器。

  2. 解压缓存文件

    在离线机器上解压缓存文件。

    tar -xzvf cache.tar.gz -C /path/to/extract
    

    确保解压后的 .pnpm-store 目录在指定的路径,例如 /path/to/extract/.pnpm-store.

  3. 配置 pnpm 使用本地缓存

    编辑或创建项目根目录下的 .npmrc 文件,指向本地缓存目录。

    store-dir=/path/to/extract/.pnpm-store
    
  4. 安装依赖

    运行 pnpm install 命令并指定 --offline 选项。

    pnpm install --offline
    

    这将根据 package.jsonpnpm-lock.yaml 文件在离线环境中安装所有依赖。

示例过程

假设在联网机器上的项目目录结构如下:

my-project/
  ├── package.json
  ├── pnpm-lock.yaml
  └── ...

并且本地缓存目录为 /home/user/.pnpm-store.

在联网机器上:
  1. 安装所有依赖:

    cd my-project
    pnpm install
    
  2. 找到 pnpm 缓存目录:

    pnpm store path
    

    假设输出为 /home/user/.pnpm-store.

  3. 压缩缓存目录:

    tar -czvf cache.tar.gz -C /home/user .pnpm-store
    
  4. 复制 package.jsonpnpm-lock.yaml 文件到离线机器。

在离线机器上:
  1. 传输 cache.tar.gz 文件、package.jsonpnpm-lock.yaml 文件到离线机器。

  2. 解压缓存文件:

    tar -xzvf cache.tar.gz -C /path/to/extract
    
  3. 配置 pnpm 使用本地缓存:

    在项目根目录下创建或编辑 .npmrc 文件:

    store-dir=/path/to/extract/.pnpm-store
    
  4. 安装依赖:

    cd my-project
    pnpm install --offline
    

我按照上面过程试了一下,之前试是没有成功的,!!所以pnpm的项目也是可以参考这种方式来进行项目到内网的迁移。

npm的离线安装第一个思路一样:根据package-lock.json来打包所有的npm包,然后通过tgz的包的方式安装。

安装的话,把所有下载的tgz都放到一个文件夹,然后通过npm install ./pack/*.tgz,把文件夹下的内容一起安装,按照这种安装后一般会遇到两个问题:

  1. package.json的连接都被改成file:// 开头了,所以安装之前要把package.json先保存起来,等安装完了再恢复。

  1. 有依赖的tgz包没有,会导致安装失败,要保证tgz的全才能安装成功

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
pnpm2026-03-17
Bun 为什么比 pnpm(以及 npm、Yarn)快
Bun 之所以比 pnpm(以及 npm、Yarn)快,核心原因在于其 底层架构的彻底重构 。pnpm 虽然通过硬链接和内容寻址解决了磁盘空间和部分安装效率问题,但它本质上仍是一个运行在 Node.js 之上的 JavaScript 工具;而 Bun 是从底层用 Zig 语言 编写的原生二进制程序,并深度集成了 JavaScriptCore 引擎。 以下是 Bun 比 pnpm 快的具体技术原因: 1\. 编程语言与执行环境的差异(最根...
学习
pnpm2025-09-01
📦 npm、yarn、pnpm、bun 是什么
🎯 什么是包管理器? 在 JavaScript 和 Node.js 生态中,一个项目往往依赖很多第三方库,比如 Vue、React、Lodash 等。\ \ 包管理器(Package Manager)\ \ 的作用,就是: 安装/卸载这些依赖库; 管理依赖的版本; 构建依赖树; 提供运行脚本(如 npm run dev)等功能。 最早是 npm,后来有了性能更好的 yarn,又有了极致节省空间的 pnpm,最近还杀出了一个全能选手 —...
学习
pnpm2024-09-29
【npm私有化部署】手把手教你使用Verdaccio搭建私有化npm
一、Verdaccio是什么? 是一个 Node.js创建的轻量的私有npm代理注册源(proxy registry) 通过Verdaccio搭建私有npm服务器有着以下优势: 1. 零配置:无需安装数据库,基于 ,安装及运行。 2. 使用方便:将内部高复用的代码进行提取,方便在多个项目中引用。 3. 安全性:仓库搭建在局域网内部,只针对内部人员使用。 4. 权限管理:对发布和下载npm包配置权限管理。 5. 加速包下载:将下载过的依赖...
学习
pnpm2024-09-11
NPM私库搭建-verdaccio(Linux)
linux服务器安装node a)、官网下载所需的node版本 b)、解压安装包 若下载的是xxx.tar.xz文件,解压命令为 c)、修改环境变量 修改:/etc/profile文件 d)、环境变量需重启生效 e)、查看当前node版本 防止报grywarn权限的错 是因为原来的私库崩了 这里直接指明仓库地址为淘宝镜像 文件位置: 如果找不到该文件,需要先运行verdaccio,直接执行verdaccio命令即可。 继续修改配置文件:...
学习
pnpm2024-09-02
【npm进阶】探索npx:一次性执行包的新方式
在现代前端开发中,开发者们需要管理和使用各种各样的npm包。而在此过程中, 作为npm生态系统中的一部分,提供了一种方便的方式来执行本地或远程的npm包。本篇文章将详细介绍 的用途和优势,展示如何使用 来执行本地和远程包,并提供一些实际的npx示例。 引言 在过去,开发者通常会通过全局安装某些工具来使用它们。然而,全局安装不仅会污染全局环境,还可能导致不同项目之间的版本冲突。 是npm 5.2.0引入的一种新工具,旨在解决这些问题。通过...
学习
pnpm2024-06-04
从零到一使用 turborepo + pnpm 搭建企业级 Monorepo 项目
单纯使用 pnpm 就能实现 Monorepo 项目我们都知道,因为它原生支持 workspace,但是它也依然存在一些缺点,例如: 1. 任务运行策略:虽然 pnpm 支持工作空间间的依赖管理和一些任务的并行执行,但是它并不那么灵活或高效地处理跨包的构建、测试和发布任务比如增量构建和任务缓存,可以显著提高大型 Monorepo 的开发和持续集成的效率。 2. 自定义构建和发布流程:pnpm 在自定义构建流程、测试流程和发布流程方面的能...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录