Chrome Extension 開發解析
一、Chrome Extension 簡介
Chrome Extension,本質上是一個由 HTML、CSS、JavaScript 等前端技術開發的程序,就像我們平時開發的前端項目一樣,它只是一個有各種資源組成的程序,被安裝到瀏覽器後,能極大地擴展瀏覽器的功能。Chrome Extension 可以理解爲一個獨立運行在 Chrome 瀏覽器下的 APP,能夠與打開的網頁、Chrome 控制面板、第三方插件等進行通信。比如,它可以實現屏蔽廣告(如 Adblock Plus)、幫助開發者進行調試開發(如 React Developers Tools)、自動更換壁紙(如 Momentum)、解決跨域問題(如 Allow CORS)、翻譯網頁內容等諸多功能。2009 年,Google Chrome Web Store 推出,標誌着 Chrome Extension 正式進入開發者社區。此後,隨着 Chrome 瀏覽器用戶基數的增加,Chrome Extension 也在不斷髮展。2010 年開始穩步增長,發佈了許多實用的拓展;2013 年,Chrome App 和擴展合併;2014 年,採用 Material Design 風格並增加更多 API;2016 年,Google 宣佈推出 Manifest V3 計劃;2021 年,Manifest V3 正式發佈;2022 年持續發展,到 2024 年 Manifest V2 將會被逐步棄用。使用 Chrome Extension 可以根據個人需求自定義瀏覽器功能,提高工作效率,改善隱私和安全,同時也爲開發者創造了創新和實用的工具。它不僅是技術的體現,還能調整用戶使用瀏覽器的心態,讓用戶更加舒適、高效地瀏覽網頁。
二、開發基礎
- 基本組成
Chrome Extension 主要由以下幾個部分組成:
manifest.json:這是擴展的核心配置文件,就像項目的 “說明書” 一樣,詳細列出了擴展的名稱、版本、描述、權限等重要信息。它位於擴展的根目錄,是 Chrome 瀏覽器識別和運行擴展的關鍵。例如,通過 “manifest_version” 指定清單文件的版本,目前逐漸向 Manifest V3 過渡,到 2024 年 Manifest V2 將被逐步棄用。“name” 定義擴展的名稱,方便用戶識別;“version” 明確擴展的版本號,便於開發者進行版本管理;“description” 提供擴展的描述,幫助用戶瞭解其功能。此外,“icons” 屬性可以設置不同尺寸的圖標,適應不同的顯示場景,如在擴展管理頁面、安裝過程以及瀏覽器工具欄上的顯示。“browser_action” 或 “page_action” 配置項可以定義擴展在瀏覽器工具欄上的表現行爲,包括圖標、標題和點擊圖標時彈出的頁面等。“permissions” 則用於聲明擴展所需的權限,確保擴展能夠正常運行並訪問必要的資源。總之,manifest.json 是 Chrome Extension 不可或缺的重要組成部分。
background script:可以理解爲插件運行在瀏覽器中的一個後臺 “網站” 或腳本,與當前瀏覽頁面無關。它通常包含對擴展很重要的瀏覽器事件的偵聽器,處於休眠狀態,直到觸發事件才執行相應的邏輯。有效的後臺腳本僅在需要時加載,並在空閒時卸載。例如,可以調用全部的 Chrome API,實現跨域請求、網頁截屏、彈出 Chrome 通知消息等功能。在 manifest.json 文件中,通過 “background” 配置項來指定後臺腳本的相關信息,如 “scripts” 屬性可以指定要執行的腳本文件。
content script:是在網頁上下文中運行的文件,能夠讀取瀏覽器訪問的網頁的詳細信息,對其進行更改,並將信息傳遞給父級擴展。它可以操作 DOM,但是和頁面其他的腳本是隔離的,訪問不到其他腳本定義的變量、函數等,相當於運行在單獨的沙盒裏。在 manifest.json 中,通過 “content_scripts” 屬性來配置內容腳本,包括匹配的域名、要執行的腳本文件以及腳本運行的時刻等。
popup:當用戶點擊插件圖標時彈出的頁面,包含 HTML、CSS 和 JavaScript 文件。它會在每次點擊插件圖標時重新載入,可以實現與用戶的交互功能。在 manifest.json 中,通過 “browser_action” 或 “page_action” 的 “default_popup” 屬性來指定彈出頁面的路徑。
這些組成部分相互協作,共同構成了功能強大的 Chrome Extension。
- 開發準備
開發 Chrome Extension 非常簡單,僅需 Chrome 瀏覽器和一個帶語法高亮的文本編輯器即可。首先,打開 Chrome 瀏覽器,在地址欄中輸入 “chrome://extensions/”,進入擴展程序管理頁面,然後開啓開發者模式。這樣就可以通過加載已解壓的擴展程序來進行本地開發和調試。對於文本編輯器,可以選擇 Visual Studio Code、Sublime Text 等,它們提供了豐富的插件和語法高亮功能,方便開發者編寫和編輯 Chrome Extension 的代碼。在開發過程中,可以利用 Chrome 瀏覽器提供的開發者工具來調試擴展程序,查看日誌輸出、檢查元素等,提高開發效率。總之,開發 Chrome Extension 所需的工具簡單易獲取,使得開發者能夠快速上手並實現各種創意功能。
三、開發步驟
- 創建 manifest
manifest.json 文件是 Chrome Extension 的核心配置文件,它定義了插件的基本屬性信息和運行路徑等。在創建這個文件時,我們需要明確以下幾個關鍵部分:
manifest_version:指定清單文件的版本。目前,逐漸向 Manifest V3 過渡,到 2024 年 Manifest V2 將被逐步棄用。這個版本號的選擇會影響到插件能夠使用的 API 和功能。name:插件的名稱,應簡潔明瞭,方便用戶識別。例如,可以根據插件的功能來命名,如 “廣告攔截器”、“語法檢查助手” 等。
version:插件的版本號,便於開發者進行版本管理。每次對插件進行更新時,應該相應地增加版本號,以便用戶瞭解插件的更新情況。
description:對插件功能的簡短描述,幫助用戶在安裝之前瞭解插件的用途。描述應該清晰、準確,突出插件的主要特點和優勢。
icons:定義一系列圖標,用於在不同的場景下顯示插件的圖標。可以根據需要提供不同尺寸的圖標,以適應不同的顯示環境。例如,可以提供 16x16、32x32、48x48 等尺寸的圖標。
browser_action 或 page_action:配置插件在瀏覽器工具欄上的表現行爲。可以定義圖標、標題和點擊圖標時彈出的頁面等。如果插件對在瀏覽器中加載的所有網頁都生效,可以選擇 browser_action;如果只針對特定的網頁生效,則可以選擇 page_action。
permissions:聲明插件所需的權限,確保插件能夠正常運行並訪問必要的資源。例如,如果插件需要訪問存儲功能,就需要在 permissions 中添加 “storage” 權限。
總之,創建 manifest.json 文件是開發 Chrome Extension 的重要一步,它爲插件的運行提供了基本的配置信息和權限聲明。
- 加載插件
加載插件的方法非常簡單。首先,在地址欄中輸入 “chrome://extensions/”,進入擴展程序管理頁面。然後,開啓開發者模式,這將允許我們加載未經過 Chrome Web Store 審覈的本地插件。接着,點擊左上角的 “加載已解壓的擴展程序”,並選擇插件所在的目錄。這樣,插件就會被成功載入到 Chrome 瀏覽器中。
需要注意的是,插件不會熱更新,每次修改代碼後,需要點擊擴展程序管理頁面中的刷新按鈕,才能載入最新的代碼。此外,爲了方便使用,可以將插件固定到標籤欄裏,這樣可以快速訪問插件的功能。
- 添加功能
註冊 background.js,作爲後臺腳本初始化事件監聽並設置存儲初始值。
background.js 是一種後臺腳本,它在插件安裝或重新加載時被掃描並初始化。在這個腳本中,我們可以添加事件監聽器,以響應各種瀏覽器事件。例如,可以在插件安裝完畢後,設置一個初始值爲空數組的存儲字段,以便後續存儲用戶的訪問歷史。
以下是一個示例代碼:
chrome.runtime.onInstalled.addListener(() => {
console.log('後臺腳本運行成功!')
chrome.storage.sync.set({ history: [] });
});
這段代碼在插件安裝後,打印一段日誌信息,並通過 storage API 設置一個初始值爲空數組的存儲字段。覆蓋默認 popup 界面,展示用戶訪問歷史,包括從 storage 讀取歷史內容並組裝成 html 插入文檔。爲了展示用戶的訪問歷史,我們需要覆蓋默認的 popup 界面。在 manifest.json 文件中,可以通過 “action” 配置項的 “default_popup” 屬性來指定彈出頁面的路徑。例如:
{
"action": {
"default_popup": "popup.html"
}
}
在 popup.html 文件中,可以使用 HTML、CSS 和 JavaScript 來構建用戶界面。以下是一個示例代碼:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div id="container">暫無瀏覽記錄~</div>
<script src="popup.js"></script>
</body>
</html>
在 popup.js 文件中,可以從 storage 中讀取歷史內容,並將其組裝成 html 插入到文檔中。以下是一個示例代碼:
chrome.storage.sync.get("history", ({ history }) => {
const contentHTML = history.length === 0? "暫無瀏覽記錄~" : history.map((record) => {
return `<div class="item-box"><div class="item-box_time">${record.time}</div><a class="item-box_text" href="${record.url}">${record.title}</a></div>`;
}).join("");
document.querySelector('#container').innerHTML = contentHTML
});
通過內容腳本記錄瀏覽歷史,將訪問頁面的標題、url 和時間存儲到 storage。爲了記錄用戶的瀏覽歷史,我們需要在內容腳本中編寫記錄的邏輯。在 manifest.json 文件中,可以通過 “content_scripts” 配置項來指定要注入到網頁中的腳本。例如:
{
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["content/index.js"]
}]
}
在 content/index.js 文件中,可以獲取訪問的頁面的標題、url 和時間,並將其存儲到 storage 中。以下是一個示例代碼:
chrome.storage.sync.get("history", ({ history }) => {
console.log("history--->", history);
history.unshift({
title: document.title,
url: location.href,
time: new Date().toLocaleString(),
});
chrome.storage.sync.set({ history });
});
4. 添加自定義 icon
爲了讓插件更加個性化,可以使用熊貓圖片作爲插件的 icon。首先,在插件目錄中新增一個 assets 目錄,並將熊貓圖片命名爲 icon.png 放入該目錄。然後,在 manifest.json 文件中,通過 “action” 配置項的 “default_icon” 屬性來指定 icon 的路徑。例如:
{
"action": {
"default_icon": {
"16": "/assets/icon.png"
}
}
}
這樣,插件就會使用熊貓圖片作爲 icon 顯示在瀏覽器工具欄上。
四、開發注意事項
1.chrome 傳遞消息
chrome 傳遞消息的 API 在不同版本有變化,需進行兼容處理。在開發 Chrome Extension 的過程中,需要注意 chrome 傳遞消息的 API 在不同版本有變化。爲了確保插件在不同版本的 Chrome 瀏覽器上都能正常運行,可以進行兼容處理。以下是一段兼容處理的代碼示例:
function compatibleChrome() {
if (!chrome.runtime) {
// Chrome 20 - 21
chrome.runtime = chrome.extension;
} else if (!chrome.runtime.onMessage) {
// Chrome 22 - 25
chrome.runtime.onMessage = chrome.extension.onMessage;
chrome.runtime.sendMessage = chrome.extension.sendMessage;
chrome.runtime.onConnect = chrome.extension.onConnect;
chrome.runtime.connect = chrome.extension.connect;
}
}
通過這段代碼,可以在不同版本的 Chrome 瀏覽器中實現對傳遞消息 API 的兼容,確保插件能夠正常接收和發送消息。
2. 本地存儲
本地存儲 Localstorage 只能設置字符串,json 需轉成字符串形式,配置 background.js 可隨時讀取本地數據。在使用 Chrome Extension 的本地存儲 Localstorage 時,需要注意它只能設置字符串類型的值。如果要存儲 JSON 對象,需要將其轉換爲字符串形式。例如:
// 設置 JSON 對象到 Localstorage
const jsonObject = { key: 'value' };
window.localStorage.setItem('domain:key', JSON.stringify(jsonObject));
// 從 Localstorage 獲取 JSON 對象
const storedValue = window.localStorage.getItem('domain:key');
const parsedObject = JSON.parse(storedValue);
此外,如果要隨時讀取本地數據,可以在 manifest.json 中配置 background.js。例如:
{
"background": {
"scripts": ["js/background.js"]
}
}
這樣,content_script 裏面的代碼就可以隨時讀取 Localstorage 裏面的數據,避免了需要 Browser_action 的 popup.html 一直打開的情況。通過這種方式,可以更加方便地管理和使用插件的本地存儲數據。
五、開發案例展示
1.git 提交的 emoji 速查工具
此工具由一個 manifest.json 文件、html 文件和一個 png 圖片文件組成。功能非常簡單,點擊彈出一個 html 頁面,以達到速查的目的,html 裏可以替換成任何想要的內容。以下是 manifest.json 的基本配置:
{
"manifest_version":2,
"name":"git commit emoji速查",
"description":"git commit emoji對照表",
"version":"1.0.0",
"browser_action":{
"default_icon":"icon.png",
"default_title":"這是一個 git commit emoji 速查的Chrome插件",
"default_popup":"popup.html"
}
}
2. 自定義右鍵菜單
鼠標右鍵的菜單使用 chrome.contextMenus 實現。例如:
chrome.contextMenus.create({id: 'page',title: '測試右鍵菜單'});
chrome.contextMenus.create({id: 'baidu-search',title: '使用百度搜索:%s',contexts: ['selection']});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
switch(info.menuItemId){
case'baidu-search':
chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(info.selectionText)});
break;
}
});
3. 覆蓋特定頁面
在 manifest.json 裏添加 chrome_url_overrides,可以被替換的只有新標籤頁 newtab、歷史記錄頁 history、書籤頁 bookmarks 這三個選項,但是一個插件只能重寫一個默認頁。例如:
"chrome_url_overrides":{
"newtab":"newtab.html"
}
4. 開發者工具自定義面板
通過 chrome.devtools API 來實現自定義開發者工具面板,大家熟悉的 vue 插件就是通過這種方式實現。例如:
// 幾個參數依次爲:panel標題、圖標(其實設置了也沒地方顯示)、要加載的頁面、加載成功後的回調
chrome.devtools.panels.create("TestPanel", "", "devtools.html", function(panel) {
console.log("自定義面板創建成功!", panel);
});
// 創建自定義側邊欄
chrome.devtools.panels.elements.createSidebarPane("Images", function(sidebar) {
sidebar.setExpression('document.querySelectorAll("img")', 'All Images');
});
5. 選項頁
選項頁實際上是指插件的詳細信息介紹,配置在 manifest.json 裏的 options_ui。例如:
"options_ui":{
"page":"options.html",
"browser_style":true
}
6. 搜索建議
在 manifest.json 裏配置觸發關鍵詞,配置後再地址欄輸入關鍵詞後按空格鍵觸發插件搜索建議。例如:
"omnibox":{
"keyword":"go"
}
chrome.omnibox.onInputChanged.addListener((text, suggest) => {
console.log('inputChanged: ' + text);
if(!text) return;
if(text == 'c') {
suggest([{
content: 'extension' + text,
description: 'chrome://extension'
},
{
content: 'bookmarks' + text,
description: 'chrome://bookmarks'
},
{
content: 'history' + text,
description: 'chrome://history'
}]);
}
});
chrome.omnibox.onInputEntered.addListener((text) => {
console.log('inputEntered: ' + text);
if(!text) return;
var href = '';
if(text.endsWith('extension')) href = 'chrome://extension'
else if(text.endsWith('history')) href = 'chrome://history'
else href = 'chrome://bookmarks'
openUrlCurrentTab(href);
});
function getCurrentTabId(callback){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
if(callback) callback(tabs.length? tabs[0].id: null);
});
}
function openUrlCurrentTab(url){
getCurrentTabId(tabId => {
chrome.tabs.update(tabId, {url: url});
})
}
7. 桌面通知
使用 chrome.notifications API,首先在 permissions 裏聲明 notifications 權限,再在 background 裏創建通知。例如:
chrome.notifications.create('', {
type: 'basic',
iconUrl: 'icons/icon.png',
title: '這是標題',
message: '您剛纔點擊了自定義右鍵菜單!'
});
六、框架
1.WXT 框架介紹
WXT 是一個免費的開源瀏覽器插件開發框架,致力於爲開發者帶來最好的開發體驗和最快的開發速度。
特性:支持所有瀏覽器:包括 Chrome、Firefox、Edge、Safari 和一切基於 Chromium 的瀏覽器,大大提高了開發效率和代碼的複用性。
一套代碼支持 Manifest V2 和 V3 的插件:開發者可以根據需要選擇適合的擴展版本,以滿足不同瀏覽器的兼容性和性能要求。
支持 HMR:更新內容不再需要重新加載整個插件,極大地提高了開發效率。
入口點:manifest.json 是根據入口點的文件生成,方便快捷。
默認使用 typescript:使代碼更加健壯、易於維護和擴展。
自動導入:與 Nuxt 一樣的自動導入功能,默認的接口無需導入即可使用,加速開發過程。
自動下載遠程代碼:Google Manifest V3 要求拓展程序不依賴遠程代碼,WXT 滿足這一要求。
輕鬆使用任何帶有 vite 插件的前端框架:開發者可以根據項目需求選擇合適的前端框架,而不必受限於特定的技術棧。內置包分析工具:方便優化,最小化擴展應用。官方提供多個快速入門模板:方便生成開發者習慣的技術方案。未來還會推出自動壓縮、上傳、發佈功能。
安裝與目錄結構:執行命令 npx wxt@latest init 或使用 pnpm 的 pnpx wxt@latest init 進行安裝。安裝後會出現選擇起始模板的選項,可根據喜歡的框架選擇。目錄結構包括. output / 構建結果目錄、.vscode / 和. wxt / 配置目錄、assets / 資源目錄、public / 資源目錄、components / 通用組件目錄、entrypoints / 核心業務源碼目錄、package.json 和 wxt.config.ts 重要配置文件目錄。
配置:打開 wxt.config.ts 文件,裏面有 vite 的配置,代表不論使用什麼框架都構建於 vite。WXT 提供 defineConfig 方法,攜帶完全的 ts 類型說明,方便配置。重要配置項包括目錄配置(不建議修改官方提供的目錄結構)、添加前端框架支持(如在 wxt.config.ts 文件中安裝框架的 Vite 插件並添加到配置中,可支持 Vue、React、Svelte 等框架)。
支持 Storage API:WXT 提供簡化的 API 來替換 browser.storage.* API,可以使用從 wxt/storage 自動導入的 storage 或手動導入。所有存儲鍵都必須以其存儲區域爲前綴,還可以使用 local:、session:、sync: 或 Managed:。如果使用 TypeScript,可以向大多數方法添加類型參數來指定鍵值的預期類型。
支持遠程代碼:WXT 將自動下載並打包帶有 url: 前綴的導入,滿足 Google 對 MV3 的要求,擴展不依賴於遠程代碼。
2. 框架橫向對比
WXT 與另一款常用框架 Plasmo 相比,各有優劣。
Plasmo 的優勢:已有 7.7k star,在知名度上遙遙領先於 WXT。支持多種前端框架,如 React、Svelte 和 Vue。採用組件化開發方式,提高代碼的可維護性和可重用性。內置熱更新功能,僅支持 React,但能讓開發者在開發過程中實時查看代碼更改的效果。提供從開發到測試再到發佈的完整解決方案,包括高效開發工具、真實環境測試和自動化發佈流程。
WXT 的優勢:支持所有前端框架,不受限於特定技術棧。支持自動打開瀏覽器並安裝擴展,提升開發體驗。除了支持 React 的熱更新外,在內容 / 後臺腳本變更時不會重新加載整個插件。未來會推出自動壓縮、上傳、發佈功能,目前已具備內置包分析工具等特性。綜上所述,開發者可以根據自己的需求和技術棧選擇適合的框架進行 Chrome Extension 開發。
七、總結
Chrome Extension 的開發雖然在技術上存在一定的複雜性,但通過對各種組成部分的理解和運用,開發者能夠創造出功能強大、個性化的瀏覽器擴展。
從基本組成來看,manifest.json 文件作爲核心配置,明確了擴展的各項屬性和權限;background script 提供了後臺運行的能力,可實現各種高級功能;content script 能夠與網頁交互,實現對頁面內容的操作;popup 則爲用戶提供了直觀的交互界面。
在開發過程中,僅需簡單的工具即可上手,Chrome 瀏覽器和帶語法高亮的文本編輯器爲開發者提供了便捷的開發環境。通過一系列的開發步驟,從創建 manifest 到加載插件、添加功能,開發者可以逐步實現自己的創意。
同時,開發過程中也需要注意一些事項,如 chrome 傳遞消息 API 的版本變化和本地存儲的使用限制等。通過兼容處理和合理配置,可以確保插件在不同版本的 Chrome 瀏覽器上穩定運行。
Chrome Extension 官網有大量的案例可供參考,從簡單的速查工具到複雜的開發者工具自定義面板,都體現了其強大的功能。而框架的出現,如 WXT 和 Plasmo,爲開發者提供了更高效的開發方式和更多的選擇。WXT 以其全面的特性和對多種前端框架的支持,爲開發者帶來了良好的開發體驗和未來的發展潛力。
總之,Chrome Extension 的開發爲用戶和開發者帶來了更多的可能性和便利。無論是提高工作效率、改善瀏覽體驗還是實現個性化需求,Chrome Extension 都發揮着重要的作用。隨着技術的不斷髮展,相信 Chrome Extension 將在未來繼續爲我們帶來更多的驚喜和創新。
DEMO 案例:
Chrome extensions: https://developer.chrome.com/docs/extensions/samples?hl=zh-cn
Wxt: https://wxt.dev/examples.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/6L5evort4dO9XXBGvuVoag