项目地址: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.js 和 package.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 创建或更新右键菜单。菜单项包括根菜单、下载已勾选项目、下载当前右键选中的项目等。这样用户不一定非要点击页面上的浮动下载按钮,也可以通过浏览器右键菜单触发部分能力。
popup 与 options:两个不同的界面入口
扩展图标弹窗由下面这段配置决定:
json
"action": {
"default_popup": "popup.html"
}
对应源码是 popup.html 和 popup.js。popup.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 和静态资源。项目依赖里的 terser、clean-css、html-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」版。