GitZip Pro 源码解析:一个 GitHub 文件/文件夹下载扩展是如何工作的(一)整体架构与扩展入口

项目地址:fthux/GitZipPro。如果你正在寻找一个可以下载 GitHub 文件或文件夹的浏览器扩展,可以先打开项目了解整体功能。

如果只从功能上看,GitZip Pro 做的事情很直接:用户打开 GitHub 仓库页面,勾选想要下载的文件或文件夹,然后点击下载,扩展把这些内容打包成一个 zip 文件交给浏览器下载。

但从源码角度看,这个过程并不是一个简单的"按钮点击事件"。它背后至少包含四个运行面:注入 GitHub 页面的 content script、负责后台能力的 background service worker、承载设置项的 options 页面,以及用于快速查看状态的 popup 页面。第一篇先不深入下载细节,而是从扩展入口出发,建立 GitZip Pro 的整体源码地图。

项目目录

项目的核心源码集中在 source 目录:

text 复制代码
source/
  manifest.json
  constants.js
  i18n.js
  jszip.min.js
  downloader.js
  content.js
  content.css
  background.js
  popup.html
  popup.js
  options.html
  options.js
  options_init.js
  locales/
  _locales/
  icons/

根目录下还有构建脚本和发布相关文件:

text 复制代码
build.js
package.json
BUILD.md
README.md
chrome-web-store-description.md
chrome-web-store-permission-justifications.txt

所以读这个项目时,可以先把它分成两层:source 是扩展运行时源码,根目录的 build.jspackage.json 是构建发布层。

整体架构图

flowchart TD A"manifest.json\
扩展装配入口"
--> B"content scripts\
constants / i18n / jszip / downloader / content"
A --> C"background.js\
后台 service worker"
A --> D"popup.html + popup.js\
扩展弹窗"
A --> E"options.html + options.js\
设置页面"
A --> F"web_accessible_resources\
可被页面访问的资源"
B --> G"GitHub 仓库页面\
注入选择框和下载按钮"
B --> H"downloader.js\
解析 URL / 请求 GitHub API / 打包 zip"
C --> I"右键菜单 / 通知 / 消息通信" E --> J"chrome.storage.local\
主题 / token / 规则 / 历史"
D --> J B --> J H --> K"GitHub API"

这张图基本就是 GitZip Pro 的运行骨架。manifest.json 不直接实现业务逻辑,但它决定了哪些脚本会在什么环境中加载。content.js 运行在 GitHub 页面上下文附近,负责改造页面;downloader.js 是下载引擎;background.js 处理右键菜单和通知;options.js 管理设置、token、历史记录和统计;popup.js 则是扩展图标弹窗里的轻量入口。

manifest.json:扩展的装配说明书

GitZip Pro 使用 Manifest V3:

json 复制代码
{
  "manifest_version": 3,
  "name": "GitZip Pro",
  "version": "1.1.3",
  "default_locale": "en",
  "description": "GitZip for GitHub, but Pro."
}

这个文件最重要的不是名称和版本,而是它把扩展拆成了几个运行区域。

首先是权限:

json 复制代码
"permissions": [
  "storage",
  "tabs",
  "downloads",
  "notifications",
  "contextMenus",
  "identity"
]

这些权限和后面的模块是一一对应的。storage 用来保存设置、token、下载历史;downloads 用来触发浏览器下载;notifications 用来显示下载结果;contextMenus 对应右键菜单;identity 服务于 GitHub 授权相关流程;tabs 则让扩展能读取和操作当前标签页上下文。

然后是 host 权限:

json 复制代码
"host_permissions": [
  "https://github.com/*",
  "https://gitzip-pro-worker.fthux.com/*"
]

这说明 GitZip Pro 的主要工作场景是 GitHub 页面,同时还会访问一个扩展自己的 worker 服务。结合后面的源码可以看到,GitHub 页面增强发生在 content.js,GitHub API 请求发生在 downloader.js,而授权相关能力会牵涉到 options 页面中的 token 配置逻辑。

content_scripts:真正进入 GitHub 页面的一组脚本

manifest.json 里最关键的配置是 content_scripts

json 复制代码
"content_scripts": [
  {
    "matches": ["https://github.com/*"],
    "js": [
      "constants.js",
      "i18n.js",
      "jszip.min.js",
      "downloader.js",
      "content.js"
    ],
    "css": ["content.css"],
    "run_at": "document_idle"
  }
]

这个加载顺序很值得注意。constants.js 最先加载,因为后面的模块都需要公共配置;i18n.js 提供翻译能力;jszip.min.js 提供 zip 打包能力;downloader.js 提供下载引擎;最后才是 content.js,它负责把前面的能力接到 GitHub 页面上。

换句话说,GitZip Pro 的页面侧运行链路大致是:
sequenceDiagram participant M as manifest.json participant G as GitHub Page participant C as content.js participant D as downloader.js participant API as GitHub API participant Z as JSZip M->>G: 在 github.com 注入脚本和样式 C->>G: 扫描仓库文件列表 C->>G: 注入选择框和下载按钮 G->>C: 用户选择文件或文件夹 C->>D: 传入选中项并启动下载 D->>API: 请求文件树和文件内容 D->>Z: 写入 zip Z-->>G: 生成压缩包并触发下载

这里有一个很清晰的分工:content.js 不应该关心 GitHub API 细节,它只负责页面交互和选中项收集;downloader.js 不应该关心 DOM,它只负责把 GitHub 文件路径变成实际的 zip 内容。

constants.js:跨模块共享的配置中心

constants.js 使用一个立即执行函数把配置挂到 globalThis.GZP_CONSTANTS 上。它主要包含几类内容。

第一类是 storage key:

js 复制代码
const STORAGE_KEYS = {
  THEME: 'gzpTheme',
  GITHUB_TOKEN: 'gzpGitHubToken',
  TOKEN_ACCESS_MODE: 'gzpTokenAccessMode',
  DOWNLOAD_HISTORY: 'gzpDownloadHistory',
  LANGUAGE: 'gzpLocale'
};

第二类是默认设置,例如主题、按钮位置、命名规则、通知开关、语言等。第三类是 URL 配置,包括 GitHub、GitHub API、项目仓库地址和 OAuth worker。第四类是下载限制:

js 复制代码
const DOWNLOAD = {
  CONCURRENCY_LIMIT: 5,
  MAX_FILE_COUNT: 500
};

这两个值会影响下载器行为:并发数量不能无限放大,文件数量也不能无限递归。第一篇只需要知道它们属于全局配置,具体如何在 downloader.js 中使用,会在后面的下载核心篇展开。

constants.js 里还有多浏览器商店配置:

js 复制代码
const EXTENSION_STORES = {
  chrome: CHROME_WEBSTORE,
  firefox: { ... },
  edge: { ... }
};

这和构建脚本有关。项目不是只面向 Chrome,而是预留了 Chrome、Firefox、Edge 三个渠道。

background.js:后台能力入口

background.js 被声明为 service worker:

json 复制代码
"background": {
  "service_worker": "background.js",
  "scripts": ["background.js"]
}

它不负责页面 DOM,也不负责 zip 打包。它的核心职责更像扩展的后台控制层:初始化国际化、创建右键菜单、响应安装事件、处理消息、显示通知。

从源码结构看,background.js 启动后会先执行 initBackgroundI18n,加载语言包,然后调用 ensureContextMenus 创建或更新右键菜单。菜单项包括根菜单、下载已勾选项目、下载当前右键选中的项目等。这样用户不一定非要点击页面上的浮动下载按钮,也可以通过浏览器右键菜单触发部分能力。

扩展图标弹窗由下面这段配置决定:

json 复制代码
"action": {
  "default_popup": "popup.html"
}

对应源码是 popup.htmlpopup.jspopup.js 的逻辑很轻,主要做主题应用、初始化国际化、读取当前标签页状态,并提供进入设置页或 GitHub 页面的入口。

设置页则由 options_page 指定:

json 复制代码
"options_page": "options.html"

options.js 是一个体量很大的文件,它承担了 GitZip Pro 的配置中心角色:主题、语言、按钮位置、文件大小显示、双击选择、token 模式、命名规则、忽略规则、下载历史、统计面板和首次欢迎弹窗都在这里。后续第六篇会单独拆解这一部分。

构建入口:package.json 与 build.js

运行时入口在 manifest.json,构建入口则在 package.json

json 复制代码
"scripts": {
  "build": "node build.js",
  "build:chrome": "node build.js --channel=chrome",
  "build:firefox": "node build.js --channel=firefox",
  "build:edge": "node build.js --channel=edge"
}

build.js 会遍历 source 目录,处理 JavaScript、CSS、HTML 和静态资源。项目依赖里的 terserclean-csshtml-minifier 分别对应 JS、CSS、HTML 压缩。构建结果会进入 build 目录,并根据渠道生成不同商店版本。

这解释了为什么 constants.js 里有 STORE_CHANNEL 和多商店配置:源码保持一份,构建时根据 channel 替换或选择对应发布目标。

第一篇小结

到这里,GitZip Pro 的整体源码地图就清楚了:

  • manifest.json 是扩展装配入口,决定脚本、页面、权限和资源如何加载。
  • constants.js 是公共配置中心,统一 storage key、默认值、URL、下载限制和商店渠道。
  • content.js 负责进入 GitHub 页面,扫描文件列表并注入交互。
  • downloader.js 负责解析 GitHub 路径、请求 API、递归收集文件并打包 zip。
  • background.js 负责右键菜单、通知和后台消息。
  • popup.js 是轻量弹窗入口。
  • options.js 是完整设置中心。
  • build.js 负责把 source 构建成可发布的扩展包。

下一篇可以正式进入 content.js,看看 GitZip Pro 是如何识别 GitHub 仓库文件页、扫描文件行、插入选择框,并把原本只读的 GitHub 文件列表改造成一个可批量选择的下载界面。

项目源码可以在 fthux/GitZipPro 查看,欢迎顺手 Star 支持 GitZip Pro。

如果你也好奇这个 Pro 版为什么会做起来,可以接着看这篇项目缘起:用了 GitZip 这么多年,我动手做了一个「Pro」版

相关推荐
aqi001 小时前
15天学会AI应用开发(十七)使用LangGraph实现会话记忆功能
人工智能·python·大模型·ai编程·ai应用
第一程序员2 小时前
Rust Agent 子进程执行:Command 之前,先定义输入和超时
python·rust·github
xixixi777772 小时前
三大 AI 安全里程碑:Akamai 高危风险预警、智能体水印强制落地、PQC 量子安全全产业链统一
大数据·人工智能·安全·ai·大模型·智能体·政策
修己xj2 小时前
让README “活”起来:Readme Typing SVG 介绍与本地化改造实践
开源
筱白爱学习2 小时前
SpringAI完整学习指南(四)
ai·spring ai
AI小码2 小时前
LLM 应用的缓存工程:当每次 API 调用都在燃烧成本
java·人工智能·spring·计算机·llm·编程·api
code 小楊2 小时前
AI函数调用:Function Calling从理论到实战全解析
人工智能
delishcomcn2 小时前
智切未来:AI算法如何重塑不干胶标签分切机的精度与效率边界
人工智能·神经网络·计算机视觉
观远数据2 小时前
ChatBI选型对比:从意图识别到SQL修复,六个维度打分决定是否值得投产
数据库·人工智能·sql