手动下载CDN资源?我花一晚上写了个自动化工具,现在全公司都在用

一、一个让我决定开发工具的需求

上个月接了一个政务系统的项目,技术方案评审会上,客户方的技术负责人提出了一个要求:

"你们的系统要部署在我们的内网环境,完全隔离外网。所有外部依赖必须本地化。"

我看了看我们的前端代码,心里一凉:

  • Vue 3 从 CDN 引入

  • Element Plus 从 CDN 引入

  • 十几个工具库都是 CDN 链接

  • 字体文件来自 Google Fonts

这要一个个手动下载、改路径,至少得两天时间。更关键的是,这种需求肯定会反复出现。

作为一个追求效率的开发者,我当晚就开始思考:为什么不开发一个工具,彻底解决这类问题?

二、需求分析与技术调研

在动手之前,我花了两天时间做调研,发现这个需求非常普遍:

典型场景

金融行业

  • 禁止任何外部请求

  • 资源必须通过安全审计

  • 版本需要完全可控

政府机构

  • 内网与外网物理隔离

  • 所有依赖需要报备

  • 源码和资源归档留存

大型企业

  • 限制外网访问

  • 代理配置复杂

  • 统一资源管理

教育培训

  • 课件离线分发

  • 不依赖网络环境

  • 保证资源完整性

现有方案的痛点

我调研了几个可能的方案:

方案

问题

手动下载

耗时、易错、无法自动化

Webpack

仅适用于工程化项目,配置复杂

浏览器另存为

文件混乱、资源缺失

现有工具

功能不够专注或维护停滞

结论:市场上缺少一个专门针对 HTML 资源离线化的轻量级工具。

三、工具设计与实现

核心功能定位

我决定开发 HTML Assets Localizer,专注解决一个问题:

自动将 HTML 文件中的外部 JavaScript 和 CSS 资源下载到本地,并更新引用路径。

功能特性:

  • 🔍 自动扫描 HTML 中的 <script><link> 标签

  • 📥 批量下载外部资源到本地

  • 📂 规范化目录结构(js/css/ 文件夹)

  • ✏️ 自动重写 HTML 引用路径

  • 🎯 重名文件自动添加数字后缀避免冲突

技术选型

为了实现跨平台和易用性,我提供了双语言实现

Node.js 版本

  • TypeScript 开发,类型安全

  • 支持 pnpm/npm/yarn 安装

  • 提供 CLI 和 UI 两种模式

Python 版本

  • 纯 Python 实现

  • 简单易懂,易于定制

  • 适合 Python 生态集成

实现架构

HTML文件输入
    ↓
解析HTML,提取外部资源URL
    ↓
并发下载资源到本地目录
    ↓
更新HTML中的引用路径
    ↓
输出离线化的HTML + 资源包

四、CLI 命令行工具

全局安装

# 使用 pnpm(推荐)
pnpm add -g html-assets-localizer

# 使用 npm
npm install -g html-assets-localizer

# 使用 yarn
yarn global add html-assets-localizer

基础使用

安装后可以使用 html-assets-localizer 或简写 hal

# 基础命令
hal <html-file> <output-dir>

# 实际示例
hal index.html ./offline-bundle

执行后工具会:

  1. offline-bundle 目录创建 js/css/ 文件夹

  2. 下载所有外部 JS 和 CSS 资源

  3. 生成更新后的 HTML 文件

  4. 打印资源处理摘要

其他命令

# 查看帮助
hal help

# 查看版本
hal version

五、UI 可视化界面

考虑到团队协作,我开发了一个 Web UI,让不熟悉命令行的同事也能使用:

hal ui

UI 功能特性

  • 📤 拖拽上传:直接拖拽 HTML 文件

  • 📊 实时进度:显示下载进度和状态

  • 📋 详细日志:查看每个资源的处理情况

  • 💾 一键下载:处理完成后直接下载压缩包

自定义配置

# 指定端口和主机
hal ui --port 4173 --host 0.0.0.0

# 禁止自动打开浏览器
hal ui --no-open

这样团队成员可以通过局域网访问,产品经理和设计师也能自己处理离线化需求。

六、程序化 API 调用

除了 CLI 和 UI,我还提供了编程接口,方便集成到构建流程:

import { HtmlAssetsLocalizer } from 'html-assets-localizer';

const localizer = new HtmlAssetsLocalizer({
  htmlFilePath: './example.html',
  targetDir: './offline',
});

const summary = await localizer.process();
console.log(summary.assets);

集成到 CI/CD

// build-offline.js
import { HtmlAssetsLocalizer } from 'html-assets-localizer';
import * as path from 'path';

async function buildOfflineVersion() {
  const files = ['index.html', 'dashboard.html', 'settings.html'];

  for (const file of files) {
    console.log(`📦 处理: ${file}`);
    
    const localizer = new HtmlAssetsLocalizer({
      htmlFilePath: path.join('./dist', file),
      targetDir: path.join('./dist/offline', path.dirname(file)),
    });

    await localizer.process();
  }
  
  console.log('✅ 离线包构建完成!');
}

buildOfflineVersion();

现在每次发布都会自动生成离线版本。

七、从源码构建

如果你想从源码构建或参与开发:

# 克隆仓库
git clone https://github.com/YangsonHung/html-assets-localizer.git
cd html-assets-localizer

# 安装依赖
pnpm install

# 构建 TypeScript
pnpm run build

# 本地测试
node dist/cli.js example.html offline-bundle

构建完成后,dist/ 目录会包含编译后的代码。

八、实战效果

回到项目场景,使用这个工具后:

$ hal src/index.html dist/offline

Processing: src/index.html
Downloading assets...
✅ vue.global.js (487KB)
✅ element-plus.css (234KB)
✅ element-plus.js (678KB)
✅ axios.min.js (32KB)

Complete! 
📦 Total assets: 12
💾 Total size: 1.52MB
📁 Output: dist/offline

效率对比

处理方式

耗时

出错率

可重复性

手动处理

2-3天

30%

自动化工具

10分钟

<1%

实际收益

  • ⏱️ 时间节省:从平均 2 天降到 10 分钟

  • 质量提升:自动化处理,零遗漏

  • 🔄 可重复:标准化流程,任何人都能操作

  • 📦 易维护:版本更新只需重新运行命令

九、最佳实践与技巧

1. 文件组织

建议的项目结构:

project/
├── src/
│   └── index.html          # 开发版(CDN引用)
├── dist/
│   ├── online/             # 线上版本
│   │   └── index.html
│   └── offline/            # 离线版本
│       ├── index.html
│       ├── js/
│       └── css/
└── scripts/
    └── build-offline.js    # 自动化脚本

2. 重名文件处理

工具会自动处理同名文件冲突:

jquery.min.js
jquery.min-1.js
jquery.min-2.js

3. 网络优化建议

  • 保持稳定的网络连接

  • 国外 CDN 可考虑使用代理

  • 大型项目可分批处理

4. 验证完整性

处理完成后建议本地测试:

# 启动本地服务器
cd dist/offline
python -m http.server 8000

# 访问 http://localhost:8000 测试

十、开源与社区

项目信息

双语言实现

项目提供了两种实现:

  • Node.js 版本:功能完整,提供 CLI + UI + API

  • Python 版本:简单实用,易于定制

可以根据技术栈选择合适的版本。

参与贡献

欢迎:

  • 🐛 提交 Bug 报告

  • 💡 提出功能建议

  • 🔧 提交 Pull Request

  • ⭐ GitHub Star 支持

十一、开发心得

1. 解决真实痛点

这个工具的诞生源于真实需求。好的工具不一定要复杂,但一定要解决实际问题

2. 用户体验优先

提供多种使用方式:

  • CLI:适合开发者和自动化

  • UI:适合非技术人员

  • API:适合程序化集成

3. 保持专注

不追求大而全,专注做好一件事:HTML 资源离线化。这让工具保持简单、可靠、易用。

4. 开源的价值

开源让工具获得了:

  • 更多用户的实际反馈

  • 社区贡献的代码和想法

  • 持续改进的动力

5. 文档的重要性

详细的文档(README.md + README.zh.md)让不同语言背景的用户都能快速上手。

写在最后

作为开发者,当我们遇到重复性工作时,应该思考:这能自动化吗?能做成工具吗?能帮助到更多人吗?

html-assets-localizer 就是这样诞生的。从解决自己的问题开始,到开源分享帮助更多人,这个过程让我深刻体会到了技术的价值。

如果你也有内网部署或离线化的需求,欢迎试用这个工具。


如果这篇文章对你有启发,欢迎点赞收藏!期待在评论区看到你的想法,或者到 GitHub 提 Issue 交流~

最近的文章

环境说明 测试环境: 操作系统:macOS 15.7.2 (支持 macOS 10.14+) 芯片架构:Apple Silicon (M1/M2/M3/M4) Flutter 版本:3.35.7 (stable) 支持的开发平台: iOS 应用开发 macOS 应用开发 Android 应用开发 W…

继续阅读
更早的文章

一、那个让人崩溃的下午 上个月的某个下午,我正在工位上处理一个紧急需求。领导突然走过来:"小王的项目需要紧急支持,你把那几个Agent任务都启动一下,测试环境要用。" 我盯着屏幕上密密麻麻的10个项目目录,心里一阵发麻。每个项目都需要启动不同的Agent CLI工具——有的用codex,有的用cla…

继续阅读