做爲一位前端開發人員,估計是離不開 chrome 瀏覽器吧,但是你在使用 chrome 時,有遇到一些痛點嗎?html
你有想過本身開發一款插件來解決本身使用上的不便嗎?其實 chrome 插件已經提供了挺多實用的 API,咱們徹底能夠根據本身的需求或興趣開發本身的插件。前端
chrome 插件沒有嚴格的項目結構的要求,只要求根目錄存在一個 manifest.json
相似安卓開發中的 AndroidManifest.xml
這是一個很是重要的功能清單文件,chrome 根據這個文件開放給擴展相應的功能權限。react
因此 chrome 擴展的開發徹底能夠選擇咱們本身熟悉的技術棧開發,好比咱們能夠用 React(Vue、Angular) 來開發。下面就是記錄我用 React 開發一款好用代理插件 Just Proxy 的過程webpack
已上架:chrome.google.com/webstore/de…git
首先須要肯定咱們的插件須要使用 chrome 開發的那些功能,先用戶提供哪些界面。github
由於如今要開發的是一款代理插件,咱們向用戶提供一下功能:web
根據上述的需求,咱們肯定的以下的 manifest.json
的內容。chrome
{
"manifest_version": 2,
"name": "Just proxy",
"description": "A simple proxy tool",
"version": "1.0.2",
"permissions": ["proxy", "storage", "tabs"],
"browser_action": {
"default_icon": "emoticon.png"
},
"icons": {
"64": "emoticon.png"
},
"options_page": "index.html",
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
複製代碼
關於 manifest.json
更加詳細的內容能夠查看 developer.chrome.com/extensions/…json
接下來咱們就可使用 Webpack(推薦) 來做爲擴展的構建工具,由於 chrome 擴展是須要讀取硬盤的文件的,咱們爲了提升咱們擴展開發的體驗(不要每次修改代碼,都須要從新構建擴展,支持熱更新),咱們須要藉助 write-file-webpack-plugin
來將咱們的內存的編譯文件寫回硬盤(不嚴謹)。由於咱們使用 React 構建咱們的擴展程序,因此也要 react-hot-loader
來實現熱更新。webpack-dev-server
的配置和咱們開發網頁時一致,這裏就再也不說明了。redux
由於 chrome 擴展程序 不是網頁,而且它對功能權限有着比網頁加嚴格要求因此咱們須要改造下咱們的 manifest.json
以便支持擴展的熱更新
{
"manifest_version": 2,
"name": "Just proxy",
"description": "A simple proxy tool",
"version": "1.0.2",
"permissions": ["proxy", "storage", "tabs", "http://127.0.0.1:8000/*"],
"browser_action": {
"default_icon": "emoticon.png"
},
"icons": {
"64": "emoticon.png"
},
"options_page": "index.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_security_policy": "default-src 'self' http://127.0.0.1:8000 http://localhost:8000; script-src 'self' http://127.0.0.1:8000 http://localhost:8000 'unsafe-eval'; connect-src http://127.0.0.1:8000 http://localhost:8000 ws://127.0.0.1:8000 ws://localhost:8000; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;"
}
複製代碼
這裏值得關注的點就是 content_security_policy
這一項,這裏再也不作詳細的說明,想要了解更多的話能夠戳下面的連接
developer.mozilla.org/zh-CN/docs/…
webpack.config.js
的配置須要注意的點,須要註明 publicPath
。
module.exports = {
// ...
output: {
// ...
publicPath: "http://127.0.0.1:8000/"
}
// ...
};
複製代碼
經過上面的設置咱們就能夠擁有一個良好的開發體驗了(開發環境和打包環境須要不一樣的配置,主要是針對熱更新方面)
項目的狀態管理我使用的是 redux
,關於狀態的持久化咱們能夠藉助 redux-persist
實現。由於 redux-persist
默認的是使用 localStorage
,可是 chrome 擴展中是不支持的,須要本身實現 chrome 插件版本的 storage
。 代碼以下:
export default class ChromeLocalStorage {
getItem(key: string) {
return new Promise(resolve => {
chrome.storage.local.get(key, item => resolve(item[key]));
});
}
setItem(key: string, value: string) {
return new Promise(resolve =>
chrome.storage.local.set({ [key]: value }, resolve)
);
}
removeItem(key: string) {
return new Promise(resolve => chrome.storage.local.remove(key, resolve));
}
}
複製代碼
在咱們這個擴展存在兩個操做比較麻煩的地方
爲了處理上面兩個問題咱們能夠實現一個 redux 中間件來簡化上面的操做,實現以下:
const chromeProxyMiddleware = store => {
// 處理其餘環境發過來的 action
chrome.runtime.onMessage.addListener(request => {
store.dispatch({ ...request, passed: true });
});
return next => action => {
// 給其餘環境發生 action
if (passingActions.indexOf(action.type) >= 0 && !action.passed) {
chrome.runtime.sendMessage(action);
}
// 設置代理
chrome.proxy.settings.set(/* proxy config */);
};
};
export default chromeProxyMiddleware;
複製代碼