本教學將引導如何開發一個 Chrome 擴充套件,此套件能將新建的書籤依域名分類到對應資料夾。我們會使用 background.js 來實現這個功能。

前提

擁有基本的 JavaScript 知識。
已安裝 Chrome 瀏覽器。

步驟1:建立擴充套件目錄

首先,在你的電腦上建立一個新的資料夾來存放擴充套件檔案,例如命名為 BookmarkOrganizer。

步驟2:撰寫 manifest.json

在 BookmarkOrganizer 資料夾內,建立一個名為 manifest.json 的檔案,並加入以下內容:

1
2
3
4
5
6
7
8
9
10
{
"manifest_version": 3,
"name": "自動整理書籤到域名資料夾",
"version": "1.0",
"description": "將新建的書籤自動整理到以域名命名的資料夾中。",
"permissions": ["bookmarks"],
"background": {
"service_worker": "background.js"
}
}

步驟3:撰寫 background.js

在 BookmarkOrganizer 資料夾內,建立一個名為 background.js 的檔案,並將提供的程式碼貼上到這個檔案中。

MV3 注意:Service Worker 是短暫存活(ephemeral)的,Chrome 在閒置後會將它終止,下次事件觸發時重新啟動。因此 folderCreationLocksdomainFoldersCache 只在同一次 SW 啟動週期內有效,跨次書籤新增之間快取會歸零。若需跨 SW 週期保存狀態,要改用 chrome.storage.local

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
let folderCreationLocks = {}; // 鎖定正在建立的資料夾(僅限本次 SW 週期)
let domainFoldersCache = {}; // 快取已建立的域名資料夾 ID(僅限本次 SW 週期)

chrome.bookmarks.onCreated.addListener(function(id, bookmark) {
if (!bookmark.url) return; // 忽略非URL書籤(即資料夾)

// 只處理 http/https,避免 javascript:、chrome:、about: 等協定丟出 TypeError
if (!/^https?:\/\//i.test(bookmark.url)) return;

const mainFolderName = "整理資料夾";
const url = new URL(bookmark.url);
const domain = url.hostname;

ensureMainFolderExists(mainFolderName, function(mainFolderId) {
if (!mainFolderId) return; // 如果沒有找到或建立主資料夾,則退出

ensureDomainFolderExists(mainFolderId, domain, function(domainFolderId) {
if (domainFolderId) {
// 存在域名資料夾,移動書籤
chrome.bookmarks.move(id, {parentId: domainFolderId});
}
});
});
});

function ensureMainFolderExists(mainFolderName, callback) {
// 尋找或建立主資料夾
chrome.bookmarks.search({title: mainFolderName}, function(results) {
let mainFolder = results.find(result => result.title === mainFolderName && !result.url);
if (!mainFolder) {
chrome.bookmarks.create({title: mainFolderName}, function(newFolder) {
callback(newFolder.id);
});
} else {
callback(mainFolder.id);
}
});
}

function ensureDomainFolderExists(mainFolderId, domain, callback) {
if (folderCreationLocks[domain]) {
// 如果域名資料夾正在建立中,則稍後重試
setTimeout(() => ensureDomainFolderExists(mainFolderId, domain, callback), 100);
return;
}

if (domainFoldersCache[domain]) {
// 如果域名資料夾已存在於快取中,直接使用
callback(domainFoldersCache[domain]);
return;
}

// 鎖定域名資料夾建立操作
folderCreationLocks[domain] = true;

chrome.bookmarks.getChildren(mainFolderId, function(children) {
let domainFolder = children.find(child => child.title === domain && !child.url);
if (!domainFolder) {
// 建立域名資料夾
chrome.bookmarks.create({parentId: mainFolderId, title: domain}, function(newFolder) {
domainFoldersCache[domain] = newFolder.id; // 快取資料夾 ID
delete folderCreationLocks[domain]; // 解鎖
callback(newFolder.id);
});
} else {
domainFoldersCache[domain] = domainFolder.id; // 快取資料夾 ID
delete folderCreationLocks[domain]; // 解鎖
callback(domainFolder.id);
}
});
}

步驟4:載入擴充套件到 Chrome

打開 Chrome 瀏覽器,進入 chrome://extensions/ 頁面。
開啟開發者模式。
點擊「載入未封裝項目」,選擇剛剛建立的 BookmarkOrganizer 資料夾。

步驟5:測試擴充套件

現在,當你建立一個包含 URL 的書籤時,擴充套件會自動將該書籤移動到以該 URL 的域名命名的資料夾內。如果相應的域名資料夾不存在,擴充套件會自動建立一個。

解析 background.js

監聽書籤建立事件:使用 chrome.bookmarks.onCreated.addListener 來監聽書籤的建立事件。
確保主資料夾存在:ensureMainFolderExists 函式會檢查是否存在一個名為「整理資料夾」的資料夾,如果不存在則建立它。建立時未指定 parentId,Chrome 預設會把它放在「其他書籤」(Other Bookmarks) 底下,找不到時往那邊找就對了。
確保域名資料夾存在:ensureDomainFolderExists 函式負責建立和維護以域名命名的資料夾,並將新的書籤移動到相應的資料夾中。

結語

會開發這個是因為日漸增加的書籤,書籤已經突破幾萬筆,看起來很亂,想了想有沒有解決方法,找了 Chrome 套件沒找到能解決這個問題的套件,最後決定自己寫一個。其實是第一次開發 Chrome 擴充套件,此文章當作筆記,沒做到上架的程度。開發中也遇到很多問題,例如一開始書籤一口氣複製進去,域名資料夾重複建立了,發現是非同步原因;也發現根目錄資料夾新增刪除移動都沒反應,查文件才知道根目錄不能做這些操作。