NemoZhong / blog-nemo

0 stars 0 forks source link

搭建离线npm仓库遇到的问题 #25

Open NemoZhong opened 1 year ago

NemoZhong commented 1 year ago

background: 在vdi纯内网环境搭建Npm仓库,使用verdaccio镜像直接启动仓库,项目中的包打算下载到仓库内存放包的地方

NemoZhong commented 1 year ago

😂刚开始以为直接把项目的package.json和lock文件拿出来install后,放在verdaccio仓库镜像里就好了,dockerfile将本地install的node_modules拷进/verdaccio/storage目录下,结果启起来始终找不到任何包。后面打开package-lock文件才注意到npm仓库实际上存放的是.tgz的压缩包。比如dayjs@1.11.9,在lock文件中是存在https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz下的。所以实际上应该把所有的tgz包放在容器的/verdaccio/storage目录下

NemoZhong commented 1 year ago
  1. 全局安装tgz包下载工具 node-tgz-downloader
  2. 将package-lock.json放在目录下,下载文件
    
    npm install node-tgz-downloader -g

package-lock.json可以是url

download-tgz package-lock package-lock.json


3. 得到的文件夹tarballs,目录结构就是实际上npm仓库存放包的结构
NemoZhong commented 1 year ago

然后直接把文件夹挂载在容器的/storage目录下,使用docker-compose up -d启动仓库镜像,即可

version: '3'
services:
  verdaccio:
    image: verdaccio/verdaccio
    ports:
      - "4873:4873"
    volumes:
      - ./tarballs:/verdaccio/storage
    restart: always
NemoZhong commented 1 year ago

遇到的问题,本地启动服务能正常访问包,但是把文件上传到远程linux服务器上的时候,仓库能正常启动,但是包访问不到,报错500,internal server error. 通过docker logs可以看到是挂载的文件目录没有权限。 通过chmod 777 tarballs/*把所有包的权限全部放开后,解决该问题

在远程linux上使用到的命令

## 连接远程服务器
ssh username@ip

## 将本地文件夹(-r)拷贝到远程服务器的根目录'/'下的文件夹下   注意ip不带端口号
scp -r /Users/Workspace/raysaNpm username@ip:/directoryName/

## 将tarballs下的所有文件夹及文件读写执行权限放开(实际上只需要读)   
chmod 777 tarballs/* 
-rw------- (600) 只有拥有者有读写权限。
-rw-r--r-- (644) 只有拥有者有读写权限;而属组用户和其他用户只有读权限。
-rwx------ (700) 只有拥有者有读、写、执行权限。
-rwxr-xr-x (755) 拥有者有读、写、执行权限;而属组用户和其他用户只有读、执行权限。
-rwx--x--x (711) 拥有者有读、写、执行权限;而属组用户和其他用户只有执行权限。
-rw-rw-rw- (666) 所有用户都有文件读、写权限。
-rwxrwxrwx (777) 所有用户都有读、写、执行权限。

docker保存/载入镜像

docker save `imgID` > `imgName`.tar
docker load < `imgName`.tar

上传文件(夹)到远程服务器(scp会覆盖同名文件,rsync可以增加上传)

scp -r ./myfile.txt user@hostname:/dir
NemoZhong commented 1 year ago

外网维护一个npm本地仓库文件夹,如果要装新包怎么办?

  1. 建新目录下:npm install moduleA
  2. download-tgz package-lock package-lock.json
  3. 把新目录下的tarballs下面的所有文件 【合并】 到本地仓库文件夹下的tarballs里(mac下command+c和command+v自带合并选项)
NemoZhong commented 1 year ago
NemoZhong commented 1 year ago

再贴下花时间边gpt边写的下载package.json的脚本[😅]

const fs = require('fs');
const path = require('path');
const https = require('https');

const tarballsDir = './tarballs'; // 指定 tarballs 文件夹的路径

// 递归查找子文件夹的函数
function findInnermostFolders(dir) {
  const subdirs = fs.readdirSync(dir);

  // 过滤出子文件夹
  const innermostFolders = subdirs.filter(subdir => {
    const subDirPath = path.join(dir, subdir);
    return fs.statSync(subDirPath).isDirectory();
  });

  if (innermostFolders.length === 0) {
    // 如果没有子文件夹,返回当前目录
    return [dir];
  }

  // 递归查找子文件夹的子文件夹
  const subInnermostFolders = innermostFolders.map(subdir => {
    const subDirPath = path.join(dir, subdir);
    return findInnermostFolders(subDirPath);
  });

  // 使用 flat() 方法将多维数组展平为一维数组
  return subInnermostFolders.flat();
}

// 获取最里面的文件夹路径
const innermostFolders = findInnermostFolders(tarballsDir)?.map(str=>str.split('tarballs/')?.[1])

// 下载 package.json 文件并保存到相应的文件夹中
innermostFolders.forEach(dirPath => {
  const packageJsonPath = path.join(tarballsDir, dirPath, 'package.json');

  // 检查是否已经存在 package.json 文件
  if (fs.existsSync(packageJsonPath)) {
    console.log(`package.json already exists in ${dirPath}. Skipping download.`);
  } else {
    const packageJsonUrl = `https://registry.npmjs.org/${dirPath}`;

    https.get(packageJsonUrl, (response) => {
      let data = '';

      response.on('data', (chunk) => {
        data += chunk;
      });

      response.on('end', () => {
        try {
          // 保存 package.json 文件到相应的文件夹
          fs.writeFileSync(packageJsonPath, data);
          console.log(`Downloaded and saved package.json for ${dirPath}`);
        } catch (error) {
          console.error(`Error downloading package.json for ${dirPath}: ${error.message}`);
        }
      });
    }).on('error', (error) => {
      console.error(`Error downloading package.json for ${dirPath}: ${error.message}`);
    });
  }
});
NemoZhong commented 1 year ago

package.json中dependency的版本 : Major.Minor.Patch 主版本号(Major):当进行不兼容的 API 变化时增加。 次版本号(Minor):当添加向后兼容的新功能时增加。 补丁版本号(Patch):当进行向后兼容的修复时增加。

^ 允许1.2.3升级到1.3.3 ~ 只允许1.2.3升级到1.2.x

当npm install时,如果package.json中,依赖的版本是^或者~,【在没有npm缓存的情况下】装包后就会使用最新的小版本,有缓存的话,还是会安装缓存的版本,所以在外网装包时,必须先清除缓存npm cache clean --force保证装包都是最新的tar包。

NemoZhong commented 9 months ago

之前内网仓库包装包经常遇到integrety校验失败 sha-512码不对,这里直接在外网搭个verdaccio环境,然后把package.jsonpackage-lock.json放文件夹里执行npm install,装包之后把外网容器环境的verdaccio/storage/data下的文件拷出来,放内网仓库即可(integrety基本上校验没问题),个别包可在registry.npm.org里单独下载

完全不需要手动用node-tgz-downloader下载 🤮

NemoZhong commented 9 months ago

内网仓库的某个包,如果要进行魔改,或者修复bug,除了更新解决bug后的版本外,可以使用patch-packages进行包打补丁 ✈️ 特别要注意:执行npx patch-package A时,实际上是先去内网仓库装A对应版本的包,由于项目中有package-lock文件,把小版本锁死的,但是npx A时,依赖的小版本可能是最新的,但是内网仓库没有对应的包,因此会报错! 类似这种: image 需要把patch-package源码的日志放开才能定位到缺少什么包,具体如图 image