GitZip Pro 源码解析:一个 GitHub 文件/文件夹下载扩展是如何工作的(一)整体架构与扩展入口 项目地址fthux/GitZipPro。如果你正在寻找一个可以下载 GitHub 文件或文件夹的浏览器扩展可以先打开项目了解整体功能。如果只从功能上看GitZip Pro 做的事情很直接用户打开 GitHub 仓库页面勾选想要下载的文件或文件夹然后点击下载扩展把这些内容打包成一个 zip 文件交给浏览器下载。但从源码角度看这个过程并不是一个简单的“按钮点击事件”。它背后至少包含四个运行面注入 GitHub 页面的 content script、负责后台能力的 background service worker、承载设置项的 options 页面以及用于快速查看状态的 popup 页面。第一篇先不深入下载细节而是从扩展入口出发建立 GitZip Pro 的整体源码地图。GitZip Pro项目目录项目的核心源码集中在 source 目录source/manifest.jsonconstants.jsi18n.jsjszip.min.jsdownloader.jscontent.jscontent.cssbackground.jspopup.htmlpopup.jsoptions.htmloptions.jsoptions_init.jslocales/_locales/icons/根目录下还有构建脚本和发布相关文件build.jspackage.jsonBUILD.mdREADME.mdchrome-web-store-description.mdchrome-web-store-permission-justifications.txt所以读这个项目时可以先把它分成两层source 是扩展运行时源码根目录的 build.js 和 package.json 是构建发布层。整体架构图manifest.json扩展装配入口content scriptsconstants / i18n / jszip / downloader / contentbackground.js后台 service workerpopup.html popup.js扩展弹窗options.html options.js设置页面web_accessible_resources可被页面访问的资源GitHub 仓库页面注入选择框和下载按钮downloader.js解析 URL / 请求 GitHub API / 打包 zip右键菜单 / 通知 / 消息通信chrome.storage.local主题 / token / 规则 / 历史GitHub API这张图基本就是 GitZip Pro 的运行骨架。manifest.json 不直接实现业务逻辑但它决定了哪些脚本会在什么环境中加载。content.js 运行在 GitHub 页面上下文附近负责改造页面downloader.js 是下载引擎background.js 处理右键菜单和通知options.js 管理设置、token、历史记录和统计popup.js 则是扩展图标弹窗里的轻量入口。manifest.json扩展的装配说明书GitZip Pro 使用 Manifest V3{“manifest_version”: 3,“name”: “GitZip Pro”,“version”: “1.1.3”,“default_locale”: “en”,“description”: “GitZip for GitHub, but Pro.”}这个文件最重要的不是名称和版本而是它把扩展拆成了几个运行区域。首先是权限“permissions”: [“storage”,“tabs”,“downloads”,“notifications”,“contextMenus”,“identity”]这些权限和后面的模块是一一对应的。storage 用来保存设置、token、下载历史downloads 用来触发浏览器下载notifications 用来显示下载结果contextMenus 对应右键菜单identity 服务于 GitHub 授权相关流程tabs 则让扩展能读取和操作当前标签页上下文。然后是 host 权限“host_permissions”: [“https://github.com/,https://gitzip-pro-worker.fthux.com/”]这说明 GitZip Pro 的主要工作场景是 GitHub 页面同时还会访问一个扩展自己的 worker 服务。结合后面的源码可以看到GitHub 页面增强发生在 content.jsGitHub API 请求发生在 downloader.js而授权相关能力会牵涉到 options 页面中的 token 配置逻辑。content_scripts真正进入 GitHub 页面的一组脚本manifest.json 里最关键的配置是 content_scripts“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 的页面侧运行链路大致是JSZipGitHub APIdownloader.jscontent.jsGitHub Pagemanifest.jsonJSZipGitHub APIdownloader.jscontent.jsGitHub Pagemanifest.json在 github.com 注入脚本和样式扫描仓库文件列表注入选择框和下载按钮用户选择文件或文件夹传入选中项并启动下载请求文件树和文件内容写入 zip生成压缩包并触发下载这里有一个很清晰的分工content.js 不应该关心 GitHub API 细节它只负责页面交互和选中项收集downloader.js 不应该关心 DOM它只负责把 GitHub 文件路径变成实际的 zip 内容。constants.js跨模块共享的配置中心constants.js 使用一个立即执行函数把配置挂到 globalThis.GZP_CONSTANTS 上。它主要包含几类内容。第一类是 storage keyconst STORAGE_KEYS {THEME: ‘gzpTheme’,GITHUB_TOKEN: ‘gzpGitHubToken’,TOKEN_ACCESS_MODE: ‘gzpTokenAccessMode’,DOWNLOAD_HISTORY: ‘gzpDownloadHistory’,LANGUAGE: ‘gzpLocale’};第二类是默认设置例如主题、按钮位置、命名规则、通知开关、语言等。第三类是 URL 配置包括 GitHub、GitHub API、项目仓库地址和 OAuth worker。第四类是下载限制const DOWNLOAD {CONCURRENCY_LIMIT: 5,MAX_FILE_COUNT: 500};这两个值会影响下载器行为并发数量不能无限放大文件数量也不能无限递归。第一篇只需要知道它们属于全局配置具体如何在 downloader.js 中使用会在后面的下载核心篇展开。constants.js 里还有多浏览器商店配置const EXTENSION_STORES {chrome: CHROME_WEBSTORE,firefox: { … },edge: { … }};这和构建脚本有关。项目不是只面向 Chrome而是预留了 Chrome、Firefox、Edge 三个渠道。background.js后台能力入口background.js 被声明为 service worker“background”: {“service_worker”: “background.js”,“scripts”: [“background.js”]}它不负责页面 DOM也不负责 zip 打包。它的核心职责更像扩展的后台控制层初始化国际化、创建右键菜单、响应安装事件、处理消息、显示通知。从源码结构看background.js 启动后会先执行 initBackgroundI18n加载语言包然后调用 ensureContextMenus 创建或更新右键菜单。菜单项包括根菜单、下载已勾选项目、下载当前右键选中的项目等。这样用户不一定非要点击页面上的浮动下载按钮也可以通过浏览器右键菜单触发部分能力。popup 与 options两个不同的界面入口扩展图标弹窗由下面这段配置决定“action”: {“default_popup”: “popup.html”}对应源码是 popup.html 和 popup.js。popup.js 的逻辑很轻主要做主题应用、初始化国际化、读取当前标签页状态并提供进入设置页或 GitHub 页面的入口。设置页则由 options_page 指定“options_page”: “options.html”options.js 是一个体量很大的文件它承担了 GitZip Pro 的配置中心角色主题、语言、按钮位置、文件大小显示、双击选择、token 模式、命名规则、忽略规则、下载历史、统计面板和首次欢迎弹窗都在这里。后续第六篇会单独拆解这一部分。构建入口package.json 与 build.js运行时入口在 manifest.json构建入口则在 package.json“scripts”: {“build”: “node build.js”,“build:chrome”: “node build.js --channelchrome”,“build:firefox”: “node build.js --channelfirefox”,“build:edge”: “node build.js --channeledge”}https://github.com/sangesong/icoegs/blob/main/%E7%AC%AC%E4%B8%80%E7%B2%BE%E9%80%89%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E4%BB%A3%E7%90%86X.mdhttps://github.com/grayesters/xyakur/blob/main/%E8%B5%84%E8%AE%AF%E8%A7%A3%E8%AF%BB%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E5%BC%80%E6%88%B7L.mdhttps://github.com/drasesaggs/boqxcy/blob/main/%E5%AE%98%E6%96%B9%E5%8F%91%E5%B8%83%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%AE%98%E7%BD%91%E6%B3%A8%E5%86%8Cw.mdbuild.js 会遍历 source 目录处理 JavaScript、CSS、HTML 和静态资源。项目依赖里的 terser、clean-css、html-minifier 分别对应 JS、CSS、HTML 压缩。构建结果会进入 build 目录并根据渠道生成不同商店版本。这解释了为什么 constants.js 里有 STORE_CHANNEL 和多商店配置源码保持一份构建时根据 channel 替换或选择对应发布目标。第一篇小结到这里GitZip Pro 的整体源码地图就清楚了https://github.com/grayesters/xyakur/blob/main/%E7%AC%AC%E4%B8%80%E6%95%99%E8%82%B2%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E5%AE%A2%E6%9C%8DP.mdhttps://github.com/sangesong/icoegs/blob/main/%E5%AE%98%E6%96%B9%E5%8F%91%E5%B8%83%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E5%AE%98%E7%BD%91N.mdhttps://github.com/drasesaggs/boqxcy/blob/main/%E7%AC%AC%E4%B8%80%E8%A7%A3%E8%AF%B4%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E4%B8%8A%E5%88%86J.mdhttps://github.com/prabutuni/nmlajs/blob/main/%E8%B5%84%E8%AE%AF%E8%A7%A3%E8%AF%BB%3A%E7%BD%91%E7%BA%B8%F0%9D%9F%96%F0%9D%9F%96%F0%9D%9F%97.ga%E4%BA%9A%E6%98%9F%E5%85%AC%E5%8F%B8%E7%BD%91%E5%9D%80j.mdmanifest.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」版。