如何愉快的開發 Chrome 插件

做爲一位前端開發人員,估計是離不開 chrome 瀏覽器吧,但是你在使用 chrome 時,有遇到一些痛點嗎?html

你有想過本身開發一款插件來解決本身使用上的不便嗎?其實 chrome 插件已經提供了挺多實用的 API,咱們徹底能夠根據本身的需求或興趣開發本身的插件。前端

chrome 插件沒有嚴格的項目結構的要求,只要求根目錄存在一個 manifest.json 相似安卓開發中的 AndroidManifest.xml 這是一個很是重要的功能清單文件,chrome 根據這個文件開放給擴展相應的功能權限。react

<!-- more -->webpack

因此 chrome 擴展的開發徹底能夠選擇咱們本身熟悉的技術棧開發,好比咱們能夠用 React(Vue、Angular) 來開發。下面就是記錄我用 React 開發一款好用代理插件 Just Proxy 的過程git

已上架:https://chrome.google.com/web...github

首先須要肯定咱們的插件須要使用 chrome 開發的那些功能,先用戶提供哪些界面。web

由於如今要開發的是一款代理插件,咱們向用戶提供一下功能:chrome

  • 配置界面(options_page,配置代理服務器設置)
  • 當前 tag 的代理狀態(經過右上角的擴展的 Icon 展現,高亮表明當前 tag 使用代理,灰色表明不使用)
  • 代理的切換(點擊右上角擴展的 Icon 交互,代理 和 取消代理 之間的狀態切換)
  • 代理設置的持久化存儲

根據上述的需求,咱們肯定的以下的 manifest.json 的內容。json

{
  "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 更加詳細的內容能夠查看 https://developer.chrome.com/...redux

熱更新配置

接下來咱們就可使用 Webpack(推薦) 來做爲擴展的構建工具,由於 chrome 擴展是須要讀取硬盤的文件的,咱們爲了提升咱們擴展開發的體驗(不要每次修改代碼,都須要從新構建擴展,支持熱更新),咱們須要藉助 write-file-webpack-plugin 來將咱們的內存的編譯文件寫回硬盤(不嚴謹)。由於咱們使用 React 構建咱們的擴展程序,因此也要 react-hot-loader 來實現熱更新。webpack-dev-server 的配置和咱們開發網頁時一致,這裏就再也不說明了。

由於 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 這一項,這裏再也不作詳細的說明,想要了解更多的話能夠戳下面的連接

https://developer.mozilla.org...

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 自動設置代理及多個 store 之間的數據同步

在咱們這個擴展存在兩個操做比較麻煩的地方

  1. 如何保證 chrome 的代理設置和 redux store 的代理設置數據一致
  2. 如何保證多個不一樣環境(這個擴展中是存在兩個環境 options_page 和 background_script)的 store 數據一致

爲了處理上面兩個問題咱們能夠實現一個 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;

項目地址:https://github.com/0jinxing/j...

插件地址:https://chrome.google.com/web...

相關文章
相關標籤/搜索