node-tgz-downloader 的知识点笔记

349 阅读5分钟

在内网环境中,将项目所需的 npm 依赖下载为 tgz 格式,并上传到内部的仓库中,以便在没有外网访问权限的环境中使用。

node-tgz-downloader 是一个根据 package-lock.json 或 package.json 文件下载所有 node_modules tgz 文件的工具包。它支持通过本地文件、文件URL、包名、搜索关键字等方式来下载所需的 tarball 包。

  1. 全局安装 node-tgz-downloader
npm install node-tgz-downloader -g
  1. 根据 package-lock.json、package.json 内的版本信息下载对应的依赖包

在包含 package-lock.json、package.json 文件夹内打开 powershell 窗口选项执行以下代码,会生成一个文件夹 tarballs,里面包含 node_modules 所包含的依赖包

download-tgz package-lock package-lock.json

tarballs 的目录大致如下:

tarballs
├── @antv
│   ├── graphlib
│   │   └── graphlib-1.2.0.tgz
│   ├── g-webgpu
│   │   └── g-webgpu-0.7.2.tgz
│   ├── ...
├── @babel
│   ├── code-frame
│   │   ├── code-frame-7.12.11.tgz
│   │   └── code-frame-7.16.0.tgz
│   ├── compat-data
│   │   └── compat-data-7.16.4.tgz
│   ├── core
│   │   └── core-7.16.0.tgz
│   ├── generator
│   │   └── generator-7.16.0.tgz
│   ├── helper-annotate-as-pure
│   │   └── helper-annotate-as-pure-7.16.0.tgz
│   ├── ...

以下是关于 node-tgz-downloader 的一些详细信息和使用方法:

一、说明

node-tgz-downloader 是一个 Node.js 工具包,用于根据 package-lock.json 或 package.json 文件下载所有依赖的 tgz 文件。这对于需要将这些依赖包导入到没有网络连接或特定网络环境中的场景非常有用。

二、功能特点

  1. 支持多种下载方式
    • 从本地的 package-lock.json 或 package.json 文件下载。
    • 从远程的 package-lock.json 或 package.json 文件 URL 下载。
    • 通过包名下载,包括开发依赖和对等依赖。
    • 使用搜索关键字下载。
  2. 灵活的配置
    • 支持配置 HTTPS 代理。
    • 可以指定输出目录。
  3. 简单易用
    • 提供了命令行工具和编程接口,方便集成到自动化脚本中。

三、安装

使用 npm 全局安装 node-tgz-downloader

npm install -g node-tgz-downloader

四、使用示例

示例 1: 从本地的 package-lock.json 文件下载所有依赖的 tgz 文件
download-tgz package-lock ./path/to/package-lock.json

这将会在当前目录下生成一个 tarballs 文件夹,并将下载的 tgz 文件保存在其中。

示例 2: 从远程的 package-lock.json 文件 URL 下载所有依赖的 tgz 文件
download-tgz package-lock https://example.com/path/to/package-lock.json

这将会从指定的 URL 下载 package-lock.json 文件,并基于该文件中的依赖信息下载 tgz 文件。

示例 3: 通过包名下载特定依赖的 tgz 文件
download-tgz package lodash

这将会下载 lodash 包的 tgz 文件到 tarballs 文件夹中。

示例 4: 通过包名下载依赖,并包括开发依赖和对等依赖
download-tgz package @angular/cli --devdependencies --peerdependencies

这将会下载 @angular/cli 包及其开发依赖和对等依赖的 tgz 文件。

示例 5: 使用搜索关键字下载
download-tgz search tgz

这将会从 npm 搜索查询返回的包中下载 tgz 文件。请注意,这种方法可能会下载大量不相关的包,因此建议谨慎使用。

示例 6: 配置 HTTPS 代理

如果需要在有代理的网络环境中使用 node-tgz-downloader,可以配置 HTTPS 代理:

export https_proxy='https://proxy_url:port'
download-tgz package lodash

五、编程接口

除了命令行工具外,node-tgz-downloader 还提供了编程接口,方便在 Node.js 脚本中使用。

const downloader = require('node-tgz-downloader');

// 从本地的 package-lock.json 文件下载所有依赖的 tgz 文件
downloader.downloadFromPackageLock('./path/to/package-lock.json').then(() => {
  console.log('Download completed');
}).catch(err => {
  console.error('Error occurred:', err);
});

// 从远程的 package-lock.json 文件 URL 下载所有依赖的 tgz 文件
downloader.downloadFromPackageLockUrl('https://example.com/path/to/package-lock.json').then(() => {
  console.log('Download completed');
}).catch(err => {
  console.error('Error occurred:', err);
});

六、注意事项

  • 确保 package-lock.json 或 package.json 文件中的依赖信息是最新的,以避免下载到过时的包。
  • 在使用搜索关键字下载时,请注意可能会下载到大量不相关的包,建议结合其他过滤条件使用。
  • 在配置 HTTPS 代理时,请确保代理 URL 和端口是正确的。

node-tgz-downloader 核心技术解析与实践指南

一、模块概述

node-tgz-downloader 是一个专门用于高效下载和解析 .tgz 压缩包的 Node.js 工具库,其核心功能围绕 HTTP 文件下载与流式处理构建。该模块适用于以下典型场景:

  • NPM 包下载与离线存储 (默认下载到一个叫 tarballs的文件夹内)
  • 自动化部署流程中的资源获取
  • 大规模文件分发系统
  • CI/CD 流水线中的依赖预装

二、核心功能架构

2.1 全局安装

npm install node-tgz-downloader -g

2.2 基础工作流程

const Downloader = require('node-tgz-downloader');

const downloader = new Downloader({
  url: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz',
  dest: './downloads',
  extract: true
});

downloader
  .start()
  .then(() => console.log('下载并解压完成'))
  .catch(console.error);

三、高级配置参数

参数名类型默认值说明
concurrencynumber3并行下载线程数
retriesnumber2失败重试次数
timeoutnumber30000单次请求超时时间(毫秒)
checksumstringnullSHA256 校验码验证
proxyobjectnull代理服务器配置 { host: '', port: '', auth: { username: '', password: '' } }
headersobject{}自定义请求头
onProgressfunctionnull进度回调函数

四、事件驱动模型

4.1 事件监听示例

downloader
  .on('start', (url) => {
    console.log(`开始下载: ${url}`);
  })
  .on('progress', (state) => {
    console.log(`进度: ${state.percentage}% 速度: ${state.speed}KB/s`);
  })
  .on('retry', (attempt) => {
    console.warn(`第 ${attempt} 次重试`);
  })
  .on('extract', (files) => {
    console.log(`解压完成,文件数量: ${files.length}`);
  });

4.2 完整事件列表

事件名称触发时机回调参数
start开始下载时下载URL
chunk-receive接收到数据块时{ bytes: number }
progress进度更新(默认每秒触发){ percentage, speed, total, transferred }
retry重试操作发生时当前重试次数
checksum-verify文件校验开始时预期校验码
extract-start开始解压文件时压缩包路径
extract解压完成时解压文件列表
finish全部操作完成时最终存储路径

五、异常处理机制

5.1 错误分类处理

try {
  await downloader.start();
} catch (error) {
  switch(error.code) {
    case 'ECONNREFUSED':
      console.error('连接被拒绝,请检查网络');
      break;
    case 'ETIMEDOUT':
      console.error('请求超时,尝试增加timeout值');
      break;
    case 'CHECKSUM_MISMATCH':
      console.error(`文件校验失败: ${error.expected} vs ${error.actual}`);
      break;
    case 'EACCES':
      console.error('文件权限不足,请检查目录权限');
      break;
    default:
      console.error('未知错误:', error);
  }
}

5.2 自定义重试策略

const customRetryLogic = {
  retries: 3,
  factor: 2,
  minTimeout: 1000,
  maxTimeout: 5000,
  onRetry: (error, attempt) => {
    console.log(`Attempt ${attempt} failed: ${error.message}`);
  }
};

const downloader = new Downloader({
  url: '...',
  retry: customRetryLogic
});

六、流式处理优化

6.1 内存管理策略

const { Writable } = require('stream');

class ChecksumCalculator extends Writable {
  constructor() {
    super();
    this.hash = crypto.createHash('sha256');
  }

  _write(chunk, encoding, callback) {
    this.hash.update(chunk);
    callback();
  }
}

const checksumStream = new ChecksumCalculator();

downloader
  .getDownloadStream()
  .pipe(checksumStream)
  .on('finish', () => {
    console.log('SHA256:', checksumStream.hash.digest('hex'));
  });

6.2 管道式处理示例

const zlib = require('zlib');
const tar = require('tar-stream');

const extractor = tar.extract();

downloader
  .getDownloadStream()
  .pipe(zlib.createGunzip())
  .pipe(extractor);

extractor.on('entry', (header, stream, next) => {
  console.log('解压文件:', header.name);
  stream.resume();
  stream.on('end', next);
});

七、性能优化实践

7.1 分块下载加速

const downloader = new Downloader({
  url: '...',
  concurrency: 5,
  chunkSize: 1024 * 1024 // 1MB chunks
});

7.2 缓存策略实现

const cacheManager = {
  get: (url) => {
    // 返回本地缓存路径或null
  },
  set: (url, path) => {
    // 存储到缓存系统
  }
};

const downloadWithCache = async (url) => {
  const cached = cacheManager.get(url);
  if (cached) return cached;

  const downloader = new Downloader({ url });
  const path = await downloader.start();
  cacheManager.set(url, path);
  return path;
};

八、安全增强方案

8.1 完整性校验

const expectedHash = 'a1b2c3...';

const downloader = new Downloader({
  url: '...',
  checksum: {
    algorithm: 'sha512',
    digest: expectedHash
  }
});

8.2 安全下载实践

const { createSecureContext } = require('tls');
const { Agent } = require('https');

const secureAgent = new Agent({
  secureContext: createSecureContext({
    // 自定义CA证书
  }),
  rejectUnauthorized: true
});

const downloader = new Downloader({
  url: '...',
  agent: secureAgent,
  headers: {
    'Authorization': `Bearer ${process.env.API_TOKEN}`
  }
});

九、应用场景扩展

9.1 集群下载管理

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // 分布式任务调度
  const urls = [...]; // 下载任务列表
  const workerPool = urls.map((url, index) => {
    const worker = cluster.fork();
    worker.send({ url, index });
    return worker;
  });

  // 处理worker结果...
} else {
  process.on('message', async ({ url }) => {
    const downloader = new Downloader({ url });
    await downloader.start();
    process.send({ success: true });
  });
}

9.2 浏览器集成方案

// 前端代码
import { WebDownloader } from 'node-tgz-downloader/browser';

const downloader = new WebDownloader({
  url: '...',
  workerPath: '/path/to/web.worker.js'
});

downloader.on('progress', updateUI);
downloader.start().then(handleCompletion);

十、调试与监控

10.1 性能指标采集

const perfHook = require('perf_hooks');

const downloadWithMetrics = async (url) => {
  const start = perfHook.performance.now();
  const downloader = new Downloader({ url });
  
  downloader.on('progress', (state) => {
    recordMetric('download_speed', state.speed);
  });

  await downloader.start();
  
  const duration = perfHook.performance.now() - start;
  recordMetric('total_duration', duration);
};

10.2 日志跟踪配置

const tracer = require('dd-trace').init();

const downloader = new Downloader({
  url: '...',
  headers: {
    'x-datadog-trace-id': tracer.currentSpan().context().toTraceId(),
    'x-datadog-parent-id': tracer.currentSpan().context().toSpanId()
  }
});

十一、扩展开发指南

11.1 插件系统架构

// 自定义存储插件
class CloudStoragePlugin {
  constructor(config) {
    this.bucket = config.bucket;
  }

  async save(stream, filename) {
    // 上传到云存储
  }
}

Downloader.registerPlugin('cloudStorage', CloudStoragePlugin);

// 使用插件
const downloader = new Downloader({
  url: '...',
  plugins: [
    {
      name: 'cloudStorage',
      config: { bucket: 'my-bucket' }
    }
  ]
});

本指南深入探讨了 node-tgz-downloader 的各个技术层面,开发者可根据实际需求选择合适的功能模块组合使用。建议通过渐进式实践:从基础下载功能开始,逐步集成校验、缓存等高级特性,最终构建符合业务需求的定制化下载解决方案。