
Chrome 是 web 開發(fā)人員必備的瀏覽器沒有之一。
要編寫一個 chrome 瀏覽器擴(kuò)展也只需要(基本的)html,js ,css 這些 web 開發(fā)的基本能力。
下面先看一下一個 chrome 擴(kuò)展的項(xiàng)目結(jié)構(gòu)吧:
├── images
│ ├── icon-128.png
│ └── icon-16.png
├── manifest.json
├── options.html
├── popup.html
└── scripts
├── background.js
從文件結(jié)構(gòu)來看,其實(shí)所謂的 chrome 擴(kuò)展也就是一個類似 webapp 的東西。
其中最重要的就是 manifest.json 這個配置文件了,其中包含了擴(kuò)展的一些元數(shù)據(jù),
包含名稱,版本,圖標(biāo),權(quán)限,各類入口文件等信息。
在上面的例子中,options.html 是配置項(xiàng)的界面,popup.html 是擴(kuò)展彈出頁的界面,而 background.js 相當(dāng)于擴(kuò)展的后臺進(jìn)程,可以獨(dú)立執(zhí)行邏輯或者給前端(popup)提供數(shù)據(jù)。
一般來說對于擴(kuò)展或者插件類應(yīng)用的編寫采取任務(wù)驅(qū)動的方式是最適合的。下面我們就以一個『send to gitlab issue』的擴(kuò)展為例,來講解一下 chrome 擴(kuò)展的開發(fā)流程。
這個擴(kuò)展的功能類似于 pocket 這個稍后閱讀的服務(wù),只不過 pocket 這類應(yīng)用都只能對保存的網(wǎng)頁做出『已讀』或者『未讀』的區(qū)分,而對于一篇技術(shù)文章,很難說到底讀懂了多少,理解消化的程度讓我很難把一篇技術(shù)文章標(biāo)記為『已讀』,這就造成了我的 pocket 中未讀數(shù)量只增不減,到頭來等于沒有整理。
所以我打算寫一個擴(kuò)展,可以根據(jù)當(dāng)前網(wǎng)頁鏈接創(chuàng)建一個 gitlab 的 issue ,gitlab 的 issue 相對而言,可以有更大的空間做筆記,也可以很方便的直接把文章中的知識學(xué)以致用后和 gitlab 上托管的項(xiàng)目代碼直接關(guān)聯(lián),而且 Milestone 配合 label 的分類也比 pocket 單純的 tag 要強(qiáng)不少,更別提還能和別人一起討論了。
那么先分析一下需求,作為一個用戶,當(dāng)我看到一篇不錯的技術(shù)文章,我想把它記錄到 gitlab 上,然后下班后仔細(xì)研讀,做筆記,并和同事們討論一下。于是我點(diǎn)擊了 chrome 瀏覽器右上角的 『send to gitlab issue』圖標(biāo),彈出了一個小頁面,里面預(yù)先填好了文章的標(biāo)題和 url,我可以稍微修改(或?不做),然后點(diǎn)擊保存,那么這篇文章就被記錄到(預(yù)先配置好的)gitlab 服務(wù)器上了。
對于這樣一個小項(xiàng)目,可以先從一個最簡的 demo 開始,先讓擴(kuò)展在瀏覽器上『占有一席之地』,然后點(diǎn)擊后可以彈出一個小的 ui 界面。
別急著創(chuàng)建配置文件和 html 頁面,懶惰是程序員的一種美德,先使用 這個 基于 yeoman 的 chrome 擴(kuò)展 generator 來生成項(xiàng)目骨架(還支持 es2015 哦)。
然后在 manifest.json 中指定擴(kuò)展的彈出頁面文件:
"browser_action": {
"default_popup": "popup.html"
}
然后創(chuàng)建 popup.html 文件,編寫 html 內(nèi)容,一般樣式文件直接在 header 中即可,而 js 文件 必須 從外部引用,不能直接寫在 html 中。
<body>
<p id="flash">
</p>
<input type="text" id="popup_title" placeholder="標(biāo)題"/>
<textarea type="text" id="popup_url" placeholder="url">
</textarea>
<br />
<button type="button" id="popup_button">發(fā)送</button>
<script src="scripts/app.js"></script>
</body>
現(xiàn)在可以打開 chrome 瀏覽器的擴(kuò)展管理頁面,如圖勾選載入開發(fā)中的擴(kuò)展,選定項(xiàng)目的 app 目錄,就能看到瀏覽器的右上角出現(xiàn)了我們正在開發(fā)的擴(kuò)展了。

一切順利的話,點(diǎn)擊圖標(biāo),就會出現(xiàn)我們編寫的 html 頁面了。

好了讓我們進(jìn)入下一步,獲取當(dāng)前頁面的標(biāo)題和 url。很明顯這兩個數(shù)據(jù)需要通過 chrome 提供的接口才能獲取,這里我本來采用的是在 background.js 中直接去獲取 dom 樹的內(nèi)容,可是測試后發(fā)現(xiàn),background.js 獲取的總是第一個頁面的內(nèi)容,當(dāng)切換 tab 頁后數(shù)據(jù)也不會改變。結(jié)果還是老老實(shí)實(shí)地看文檔,找到了下面的這段代碼:
chrome.tabs.query({
active: true,
currentWindow: true
}, (tabs) => {
document.getElementById('popup_title').value = tabs[0].title;
document.getElementById('popup_url').value = tabs[0].url;
});
chrome 提供了獲取當(dāng)前激活的 tab 頁面的接口,于是我們就能獲取到當(dāng)前 tab 頁的 title 和 url 了, 順便把他們自動填充到頁面的 input 框中。
注意這里需要配置擴(kuò)展的權(quán)限,加入對 tab 的訪問權(quán)限才行,在 manifest.json 中加入:
"permissions": ["tabs"]
之后的工作就是把 input 框的內(nèi)容傳遞給 gitlab 了,關(guān)于 gitlab 的接口調(diào)用不是本文重點(diǎn),可以直接參考官方的文檔。gitlab 對外暴露 RESTful 的 http 接口,不需要任何 sdk 也可以很方便地調(diào)用。
document.getElementById('popup_button').addEventListener('click', function() {
createGitlabIssue(localStorage.options_project_id,
document.getElementById('popup_title').value,
document.getElementById('popup_url').value)
});
一開始我先把 gitlab 相關(guān)配置都硬編碼到了擴(kuò)展中,跑通流程后當(dāng)然就不能直接就這樣提交,需要把它們做成配置項(xiàng)。
chrome 擴(kuò)展可以自定義一個配置頁面,在 manifest.json 中加入:
"options_page": "options.html",
然后創(chuàng)建 options.html 文件,并編寫 html 內(nèi)容:
<body>
<p id="flash"></p>
gitlab host: <input type="text" id="options_host" placeholder="gitlab host" />
<br />
project id: <input type="text" id="options_project_id" placeholder="project id" />
<br />
private token: <input type="text" id="options_token" placeholder="private token" />
<br />
<button type="button" id="options_save">save</button>
<script src="scripts/options.js"></script>
</body>

然后編寫 options.js 文件,把配置項(xiàng)持久化到 localStorage 中:
var options_host = localStorage.options_host
document.getElementById('options_host').value = options_host;
var options_project_id = localStorage.options_project_id
document.getElementById('options_project_id').value = options_project_id;
var options_token = localStorage.options_token
document.getElementById('options_token').value = options_token;
document.getElementById('options_save').onclick = function() {
localStorage.options_host = document.getElementById('options_host').value;
localStorage.options_project_id = document.getElementById('options_project_id').value;
localStorage.options_token = document.getElementById('options_token').value;
document.getElementById('flash').innerHTML = '保存成功';
}
現(xiàn)在如果右鍵點(diǎn)擊擴(kuò)展的圖標(biāo)的話,就能看到『選項(xiàng)』這個菜單是可點(diǎn)擊的:

然后在處理 gitlab 的 api 調(diào)用時,動態(tài)讀取配置內(nèi)容即可。
這樣一來,一個簡單的 chrome 擴(kuò)展就這樣完成了。當(dāng)然還有很多細(xì)節(jié)需要打磨。
項(xiàng)目地址:https://github.com/teddy-ma/send-to-gitlab-issue ,歡迎各類 issue 和 pr。