chrome插件入門及如何利用react進行開發

豆皮粉兒們,又見面了,今天這一期,由字節跳動數據平臺的「皮蛋菌」較你們使用React開發一個本身的Chrome插件。css

做者:html

做爲前端程序員,chrome 插件已經成爲了咱們工做中必不可少的工具,可是大部分同窗都沒有去真正瞭解過 chrome 插件是如何開發的。本文就是帶你們一塊兒瞭解學習如何開發 chrome 插件以及如何利用 react 進行 chrome 插件的開發。前端

什麼是 chrome 插件?

從 Google 的介紹中直譯過來,咱們一般說的「chrome 插件」實際上是指「chrome 擴展」,不過因爲你們都已經習慣於叫它做爲插件,因此咱們也繼續以「插件」的名稱來稱呼。react

chrome 插件是一個使用 web 技術進行開發的,用於加強瀏覽器功能的軟件,主要由 html、css、js以及圖片組成。webpack

chrome 插件能幹什麼?

chrome 插件能夠爲 chrome 瀏覽器增長個性化的功能,chrome 提供了開放的 api 可供插件調用,以知足用戶個性化的需求。程序員

咱們經常使用的插件大概有如下幾大類:web

  • 書籤管理;
  • 窗口控制;
  • 網絡請求管理:如Proxy、header修改、攔截請求等;
  • 頁面能力加強:去廣告、翻譯等;
  • 輔助開發調試:Redux 插件等;
  • 其餘功能;

chrome 插件的組成元素

1. manifest.json

chrome 插件的核心之一是一個 manifest.json 文件,這個文件是 chrome 插件的配置清單,chrome 瀏覽器經過讀取插件的配置清單來獲取插件的詳細信息,同時爲插件開放相應的 api 能力。chrome

下面就是一個最簡單的配置:typescript

{
  "name": "Hello Chrome Extensions",
  "version": "1.0",
  "manifest_version": 3
}
複製代碼

上面的幾個配置項是配置清單中的必須項,分別表明擴展名稱擴展版本號chrome api 版本。只須要這一個簡單的清單文件,咱們就完成了最簡單的 chrome 插件開發,能夠直接添加到 chrome 瀏覽器中。npm

Tip: 在 chrome 擴展程序控制面板的右上角打開 開發者模式,經過 「加載已解壓的擴展程序」 能夠直接讀取本地開發的擴展程序。

2. popup 頁面

被添加到 chrome 瀏覽器的插件均可以被固定在瀏覽器的右上角,有一個小圖標,在點擊圖標的時候,會呼出一個頁面,這個頁面就是 popup 頁面。它是一個臨時存在的小窗口,用戶能夠經過頁面內提供的配置項對插件進行簡單的配置。

popup 頁面和咱們普通開發的頁面同樣,開發者能夠開發任意的樣式和功能。須要注意的是,這個頁面的生命週期很短,只要被關閉了就會被銷燬,因此須要長期運行的代碼不能在 popup 頁面相關的 js 中編寫。

manifest.json 中,咱們能夠經過以下配置來指定 popup

{
    "action": {
        "default_popup": "popup.html"
    },
}
複製代碼

3. background

background 是一個會常駐運行在 chrome 後臺的腳本,它不會由於頁面的關閉而被銷燬,只要瀏覽器沒有被關閉且插件沒有被禁用,那麼這個插件的 background 就會一直在後臺運行。

backgroung 能夠在後臺監聽瀏覽器事件,根據開發者和用戶的配置來對不一樣的事件做出不一樣的響應。

popup 同樣,咱們也須要在 manifest.json 中註冊 background

{
    "background": {
        "service_worker": "background.js"
    },
}
複製代碼

4. content_scripts

content_scripts 是能夠被注入到咱們訪問的頁面中的腳本,能夠是 jscss 文件,它們能夠讀取瀏覽器訪問的網頁的詳細信息,對其進行更改,並將信息經過事件的形式與 background 通訊。

咱們常見的一些插件,如:廣告屏蔽、頁面翻譯等插件,就是利用了 content_scripts 的能力。

manifest.json 中,能夠經過以下配置來註冊 content_scripts

{
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["inject.js"],
        "run_at": "document_start"
      }],
}
複製代碼

5. permissions

chrome 插件能夠調用 chrome 瀏覽器開放的 api 對瀏覽器的能力進行加強,一些基礎的 api 無需指定權限便可使用,可是一些比較高級的 api 是須要在 permissions 中進行指定,才能使用。

一些經常使用的 permissions 如:

  • storage:可使用 chrome 的文件系統來保存數據的 api;
  • proxy: 可使用對請求進行代理的 api;
  • declarativeNetRequest: 可使用經過指定聲明性規則來阻止或修改網絡請求的 api;

manifest.json 中,能夠這樣配置:

{
    "permissions": [
        "proxy",
        "storage",
        "declarativeNetRequest",
    ],
}
複製代碼

6. 其餘

除了上述的幾個比較重要的組成元素,還有一些比較經常使用的元素:

  • options_ui:和 popup 相似,不過能夠在tab頁中打開,能夠承載更多的內容,更方便配置;
  • devtools_page:開發者工具中的頁面,比較常見的有Redux插件等;
  • chrome_url_overrides: tab頁的內容,能夠自定義;

清單配置以下:

{
    "options_ui": {
        "page": "./options.html",
        "open_in_tab": true
    },
    "devtools_page": "devtools.html",
    "chrome_url_overrides": {
    "newtab": "newtab.html"
  },
}
複製代碼

7. 目錄結構

|-- demo
    |-- background.js
    |-- devtools.html
    |-- devtools.js
    |-- inject.js
    |-- manifest.json
    |-- newtab.html
    |-- options.html
    |-- panel.html
    |-- popup.html
複製代碼

如何更高效地開發 chrome 插件

chrome 插件與用戶交互主要經過 popupoptions_ui 頁面來進行,可是經過寫純粹的 htmlcssjs來進行開發效率會很是低,如何利用現有的框架技術和組件庫來快速搭建交互頁面是咱們須要關注的問題。

1. 框架技術選擇

React 、Vue 、Angular 是目前最流行的三大前端開發框架,咱們能夠根據本身的偏好選擇相應的技術,本文是以 React 做爲框架技術選擇。

2. 腳手架的選擇

在開源社區內有很是成熟的前端開發腳手架可供原則,好比 create-react-app。可是考慮到插件開發的實際場景,咱們並不須要這些腳手架內置的不少功能,咱們只須要一個簡單的能夠開發多頁應用的腳手架,因此咱們選擇本身手動地去搭建一個簡單的 chrome 插件開發工程。

3. 編譯打包

因爲 chrome 插件支持的語法是 es5,因此咱們在依賴 React 等技術開發完成以後,須要藉助 babel 以及 webpack 的能力,把咱們的代碼編譯打包成符合 chrome 插件要求的文件及格式。

4. 工程搭建

  1. 首先使用 npm 來初始化一個項目:

npm init -y

  1. 咱們須要安裝咱們開發所需的依賴:

npm install -D @babel/core @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-react babel-loader copy-webpack-plugin clean-webpack-plugin html-loader html-webpack-plugin webpack webpack-cli webpack-dev-server

npm i -S react react-dom

  1. package.json 中配置開發和打包的命令:
{
    "scripts": {
        "start": "webpack-dev-server",
        "build": "webpack -p"
    }
}
複製代碼
  1. 根據開發插件需求,建立不一樣的文件和目錄:

    |-- react-based-extension |-- package.json |-- webpack.config.js |-- src |-- background.js |-- devtools.html |-- icon.png |-- index-devtools.js |-- index-options.js |-- index-panel.js |-- index-popup.js |-- inject_script.js |-- manifest.json |-- options.html |-- panel.html |-- popup.html |-- components |-- DevTools.js |-- Options.js |-- Panel.js |-- Popup.js

  2. 配置manifest.json

{
  "name": "React Based Extension",
  "description": "Using ReactJS to build a Chrome Extension",
  "version": "1.0.0",
  "manifest_version": 3,
  
  "icons": {
    "128": "icon.png"
  },
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "background": { "service_worker": "./background.js"},
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["./inject_script.js"],
    "run_at": "document_start"
  }],
  "options_ui": {
    "page": "./options.html",
    "open_in_tab": true
  },
  "devtools_page": "devtools.html",
  "permissions": [
    "proxy",
    "contentSettings"
  ],
  "host_permissions": [
    "*://*/*"
  ]
}
複製代碼
  1. 配置 webpack,一個多頁應用的簡單配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  devServer: {
    contentBase: path.resolve(__dirname, './src'),
    historyApiFallback: true
  },
  entry: {
    popup: path.resolve(__dirname, "./src/index-popup.js"),
    options: path.resolve(__dirname, "./src/index-options.js"),
    panel: path.resolve(__dirname, "./src/index-panel.js"),
    devtools: path.resolve(__dirname, "./src/index-devtools.js")
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env',
                '@babel/preset-react',
                {
                  'plugins': ['@babel/plugin-proposal-class-properties']
                }
              ]
            }
          }
        ]
      },
      {
        test: /\.html$/,
        use: ['html-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'popup.html',
      template: 'src/popup.html',
      chunks: ['popup']
    }),
    new HtmlWebpackPlugin({
      filename: 'options.html',
      template: 'src/options.html',
      chunks: ['options']
    }),
    new HtmlWebpackPlugin({
      filename: 'panel.html',
      template: 'src/panel.html',
      chunks: ['panel']
    }),
    new HtmlWebpackPlugin({
      filename: 'devtools.html',
      template: 'src/devtools.html',
      chunks: ['devtools']
    }),
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/*.json', to: '[name].[ext]' },
        { from: 'src/background.js', to: '[name].[ext]' },
        { from: 'src/inject_script.js', to: '[name].[ext]' },
        { from: 'src/*.png', to: '[name].[ext]' }
      ]
    }),
    new CleanWebpackPlugin()
  ]
}
複製代碼
  1. 經過以上配置,就完成了一個簡單的基於 react 的 chrome 插件開發工程搭建,咱們可使用 Antd 等開源組件庫來快速的進行交互頁面的開發。

如何快速的調試

細心的同窗可能會注意到,咱們的工程項目實際上是針對用戶交互頁面的開發,並無涉及到真正的 chrome api 的調用。若是想驗證咱們的 api 使用是否正確,功能是否符合預期,可能咱們須要頻繁的進行編譯打包,再把編譯後的文件從新加載到 chrome 中來進行驗證,這是一個很是繁瑣和耗時的過程,對開發效率有很大的影響。

那如何才能快速地調試本身在調用 chrome api 及處理的過程當中問題呢?

上面咱們提到了 background,它是一個常駐在後臺運行的腳本,咱們的交互頁能夠和它進行事件通訊,突破口就在這裏。

  1. 在開發交互頁的過程當中,咱們須要重點關心的是頁面自己的邏輯,保證在交互過程當中頁面自己邏輯質量,若是有涉及到 chrome api 調用相關的邏輯,咱們能夠先放在一邊。
  2. 在交互頁面開發完成以後,咱們須要考慮調用 chrome api 的邏輯,這個時候咱們能夠利用「事件機制」,即頁面自己不調用具體的 api,而是經過和 background 之間約定事件,經過事件的形式來通知它執行實際的 api 調用。咱們只須要事先約定好事件的類型及須要傳遞的參數便可。
  3. 而後,咱們能夠先進行代碼編譯打包,並將打包後的代碼添加到 chrome 中,如今已經能夠正常的訪問插件的交互界面並進行操做,經過事先約定的行爲能夠向 background 發送事件。
  4. 重點來了,在 chrome 的擴展程序管理界面,咱們能夠看到每一個插件都有一個「查看視圖」的按鈕,點擊之後就會出現一個相似於控制檯的窗口,這個窗口裏運行的就是background的邏輯代碼,咱們能夠經過在這裏動態的修改事件響應的處理函數,來達到快速調試 api 的目的,待調試經過後,便可將正確的邏輯寫回到咱們的工程文件中,最後進行打包發佈。

一些補充

  • chrome 擴展在20年10月份升級到了3.0版本,本文的示例是按照最新的文檔來實現的,目前應用市場上大部分的擴展仍然是2.0版本開發的,有一些配置會稍有不一樣。
  • 習慣了使用typescript開發的同窗,能夠對上面的工程示例進行改造,添加tsconfig.json並對webpack配置稍做修改便可,還能夠引入@types/chrome提示 chrome 相關的 api(目前尚未支持到3.0)。
  • 若是想要發佈本身開發的擴展,能夠到 chrome 應用商店註冊成爲開發者便可(須要$5);
相關文章
相關標籤/搜索