GitZip Pro 源码解析:一个 GitHub 文件/文件夹下载扩展是如何工作的(五)后台脚本与右键菜单

项目地址:fthux/GitZipPro。本文继续分析 GitZip Pro 的 background service worker 和右键菜单实现。
前两篇围绕 downloader.js 讲完了下载核心:解析 GitHub URL、请求 API、递归收集文件、并发下载并生成 zip。生成 zip 之后,下载器并没有直接完成浏览器下载,而是把 base64 zip 发送给 background.js。
这一篇来看 GitZip Pro 的后台脚本:source/background.js。
background.js 的职责不是操作 GitHub 页面,也不是遍历文件树,而是提供扩展级能力:右键菜单、下载 API、系统通知、下载完成监听和历史记录保存。
background 在扩展中的位置
manifest.json 中声明:
"background": {
"service_worker": "background.js",
"scripts": ["background.js"]
}
在 Manifest V3 中,background 以 service worker 形式运行。它可以响应消息、监听事件、调用扩展 API。GitZip Pro 把必须由扩展后台执行的工作都集中到这里。
整体关系可以画成这样:
这个图里有一个双向关系:content script 会把右键行信息发送给 background;background 的右键菜单点击后,又会把下载命令发回 content script。
菜单 ID 与后台状态
background.js 开头定义了右键菜单 ID:
const MENU_IDS = {
ROOT: 'gitzip-pro-download',
CHECKED: 'gitzip-pro-checked-items',
SEPARATOR: 'gitzip-pro-separator',
SELECTED: 'gitzip-pro-selected-item'
};
同时还有几个后台状态:
const activeDownloads = new Map();
let selectedItemHref = null;
let backgroundTranslations = {};
let backgroundLocale = 'en';
activeDownloads 用来记录当前由 GitZip Pro 触发的下载,便于在下载完成时显示通知、打开下载项或保存历史记录。selectedItemHref 则保存最近一次右键点击的 GitHub 文件或目录链接。
后台国际化初始化
background 没有页面 DOM,但右键菜单和通知也需要国际化。启动时会调用:
async function initBackgroundI18n() {
const locale = await GZP_I18N.init();
backgroundLocale = locale;
backgroundTranslations = await GZP_I18N.loadLocale(locale);
ensureContextMenus();
}
这里复用了 i18n.js 暴露的 GZP_I18N。加载语言后,调用 ensureContextMenus() 创建或更新菜单。
同时,background 还监听 storage 变化。当用户在 options 页面切换语言时,background.js 会重新加载语言包并更新菜单文案。
创建和更新右键菜单
右键菜单由两个函数管理:
ensureContextMenus()
createContextMenus()
ensureContextMenus() 会先尝试更新已有菜单。如果更新失败,说明菜单还不存在,就调用 createContextMenus() 创建。
菜单结构大致是:
GitZip Pro
下载已勾选项目
--------
下载当前右键项目
createContextMenus() 使用 chrome.contextMenus.create() 创建根菜单和子菜单。菜单文案通过 t('context_menu.xxx') 获取。
这里的设计让菜单可以随着语言切换动态更新,而不是只在安装时固定一次。
首次安装事件
background.js 监听安装事件:
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
chrome.storage.local.set({
'gitzip-pro-show-welcome': true
}, () => {
chrome.runtime.openOptionsPage();
});
}
});
首次安装时,它会写入一个 welcome 标记,然后打开 options 页面。后续 options.js 会读取这个标记,跳转到 token 页面并展示欢迎弹窗。
这说明首次体验不是 popup 负责的,而是 background 触发 options 页面完成的。
接收下载消息
下载器生成 zip 后,会发送:
{
type: 'GZP_DOWNLOAD_FILE',
filename,
base64,
mimeType,
notifyShow,
notifyOpen,
historyRecord
}
background.js 在 chrome.runtime.onMessage 中处理这个消息。它先对文件名做一次安全处理:
safeFilename = safeFilename.replace(/(^|\/)[.~]/g, '$1_');
这是因为 chrome.downloads 不允许路径段以点号或波浪号开头。然后把 base64 组装成 data URL:
const dataUrl = `data:${mimeType};base64,${base64}`;
最后调用:
chrome.downloads.download({
url: dataUrl,
filename: safeFilename,
saveAs: false
}, callback);
如果下载成功,并且用户开启了通知或打开下载项,background 会把下载 ID 记录到 activeDownloads:
activeDownloads.set(downloadId, {
notifyShow,
notifyOpen,
filename,
historyRecord
});
后续下载状态变化时,就能根据这个 ID 找回对应上下文。
右键菜单通信
当用户在 GitHub 文件行上右键时,content.js 会发送:

{
type: 'GZP_UPDATE_CONTEXT_MENU',
href,
itemName,
itemType
}
background 收到后,把 href 保存到 selectedItemHref,并更新菜单标题。例如“下载当前选中文件 README.md”。
当用户真正点击右键菜单时,background 监听:
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === MENU_IDS.SELECTED && selectedItemHref) {
chrome.tabs.sendMessage(tab.id, {
type: 'GZP_DOWNLOAD_CONTEXT_ITEM',
href: selectedItemHref
});
}
});
这条消息会回到 content script。content script 再构造单项 selectedItems,调用 GZPDownloader.start()。
完整右键链路如下:
下载完成监听与历史保存
background 还监听浏览器下载状态:
chrome.downloads.onChanged.addListener((delta) => {
...
});
当下载状态变成 complete,它会从 activeDownloads 中取出下载偏好:
- 如果
notifyShow为 true,就创建系统通知。 - 如果
notifyOpen为 true,就调用chrome.downloads.show(delta.id)。 - 如果存在
historyRecord,就保存下载历史。
历史保存由 saveHistoryRecord(record) 完成。它读取 STORAGE_KEYS.DOWNLOAD_HISTORY,把新记录放到最前面,并限制最多保留 100 条。
保存完成后,background 还会尝试发送:
chrome.runtime.sendMessage({
type: 'GZP_DOWNLOAD_COMPLETE',
record
});
如果 options 页面正打开,它可以收到这条消息并实时刷新历史列表;如果没打开,也没关系,因为记录已经写入 storage。
本篇小结
background.js 是 GitZip Pro 的扩展后台层。它把下载器不能或不适合直接做的事情接了过来:
GZP_DOWNLOAD_FILE
-> chrome.downloads.download()
-> chrome.downloads.onChanged
-> notification / open downloaded item / save history
同时它还负责右键菜单:
content.js 发送右键行信息
-> background 更新菜单标题
-> 用户点击菜单
-> background 通知 content.js 启动下载
下一篇进入 options.js,看 GitZip Pro 的设置页如何管理主题、语言、token、命名规则、忽略规则、下载历史和统计数据。
项目源码可在 fthux/GitZipPro 查看。欢迎 Star 支持 GitZip Pro,也方便后续对照源码阅读本系列。
如果你也好奇这个 Pro 版为什么会做起来,可以接着看这篇项目缘起:用了 GitZip 这么多年,我动手做了一个「Pro」版。
下载器生成 zip 之后,真正调用浏览器下载 API 的是后台脚本。`background.js` 负责右键菜单、通知、下载完成监听和历史保存,是 GitZip Pro 从“页面脚本”走向“完整扩展”的关键一层。
浙公网安备 33010602011771号