豆皮粉兒們,又見面了,今天這一期,由字節跳動數據平臺的「皮蛋菌」較你們使用React開發一個本身的Chrome插件。css
做者:html
做爲前端程序員,chrome 插件已經成爲了咱們工做中必不可少的工具,可是大部分同窗都沒有去真正瞭解過 chrome 插件是如何開發的。本文就是帶你們一塊兒瞭解學習如何開發 chrome 插件以及如何利用 react 進行 chrome 插件的開發。前端
從 Google 的介紹中直譯過來,咱們一般說的「chrome 插件」實際上是指「chrome 擴展」,不過因爲你們都已經習慣於叫它做爲插件,因此咱們也繼續以「插件」的名稱來稱呼。react
chrome 插件是一個使用 web 技術進行開發的,用於加強瀏覽器功能的軟件,主要由 html、css、js以及圖片組成。webpack
chrome 插件能夠爲 chrome 瀏覽器增長個性化的功能,chrome 提供了開放的 api 可供插件調用,以知足用戶個性化的需求。程序員
咱們經常使用的插件大概有如下幾大類:web
Redux
插件等;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 擴展程序控制面板的右上角打開 開發者模式,經過 「加載已解壓的擴展程序」 能夠直接讀取本地開發的擴展程序。
被添加到 chrome 瀏覽器的插件均可以被固定在瀏覽器的右上角,有一個小圖標,在點擊圖標的時候,會呼出一個頁面,這個頁面就是 popup
頁面。它是一個臨時存在的小窗口,用戶能夠經過頁面內提供的配置項對插件進行簡單的配置。
popup
頁面和咱們普通開發的頁面同樣,開發者能夠開發任意的樣式和功能。須要注意的是,這個頁面的生命週期很短,只要被關閉了就會被銷燬,因此須要長期運行的代碼不能在 popup
頁面相關的 js
中編寫。
在 manifest.json
中,咱們能夠經過以下配置來指定 popup
:
{
"action": {
"default_popup": "popup.html"
},
}
複製代碼
background
是一個會常駐運行在 chrome 後臺的腳本,它不會由於頁面的關閉而被銷燬,只要瀏覽器沒有被關閉且插件沒有被禁用,那麼這個插件的 background
就會一直在後臺運行。
backgroung
能夠在後臺監聽瀏覽器事件,根據開發者和用戶的配置來對不一樣的事件做出不一樣的響應。
和 popup
同樣,咱們也須要在 manifest.json
中註冊 background
:
{
"background": {
"service_worker": "background.js"
},
}
複製代碼
content_scripts
是能夠被注入到咱們訪問的頁面中的腳本,能夠是 js
和 css
文件,它們能夠讀取瀏覽器訪問的網頁的詳細信息,對其進行更改,並將信息經過事件的形式與 background
通訊。
咱們常見的一些插件,如:廣告屏蔽、頁面翻譯等插件,就是利用了 content_scripts
的能力。
在 manifest.json
中,能夠經過以下配置來註冊 content_scripts
:
{
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["inject.js"],
"run_at": "document_start"
}],
}
複製代碼
chrome 插件能夠調用 chrome 瀏覽器開放的 api 對瀏覽器的能力進行加強,一些基礎的 api 無需指定權限便可使用,可是一些比較高級的 api 是須要在 permissions
中進行指定,才能使用。
一些經常使用的 permissions
如:
在 manifest.json
中,能夠這樣配置:
{
"permissions": [
"proxy",
"storage",
"declarativeNetRequest",
],
}
複製代碼
除了上述的幾個比較重要的組成元素,還有一些比較經常使用的元素:
popup
相似,不過能夠在tab頁中打開,能夠承載更多的內容,更方便配置;清單配置以下:
{
"options_ui": {
"page": "./options.html",
"open_in_tab": true
},
"devtools_page": "devtools.html",
"chrome_url_overrides": {
"newtab": "newtab.html"
},
}
複製代碼
|-- demo
|-- background.js
|-- devtools.html
|-- devtools.js
|-- inject.js
|-- manifest.json
|-- newtab.html
|-- options.html
|-- panel.html
|-- popup.html
複製代碼
chrome 插件與用戶交互主要經過 popup
和 options_ui
頁面來進行,可是經過寫純粹的 html
、css
、js
來進行開發效率會很是低,如何利用現有的框架技術和組件庫來快速搭建交互頁面是咱們須要關注的問題。
React 、Vue 、Angular 是目前最流行的三大前端開發框架,咱們能夠根據本身的偏好選擇相應的技術,本文是以 React 做爲框架技術選擇。
在開源社區內有很是成熟的前端開發腳手架可供原則,好比 create-react-app
。可是考慮到插件開發的實際場景,咱們並不須要這些腳手架內置的不少功能,咱們只須要一個簡單的能夠開發多頁應用的腳手架,因此咱們選擇本身手動地去搭建一個簡單的 chrome 插件開發工程。
因爲 chrome 插件支持的語法是 es5,因此咱們在依賴 React 等技術開發完成以後,須要藉助 babel
以及 webpack
的能力,把咱們的代碼編譯打包成符合 chrome 插件要求的文件及格式。
npm init -y
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
package.json
中配置開發和打包的命令:{
"scripts": {
"start": "webpack-dev-server",
"build": "webpack -p"
}
}
複製代碼
根據開發插件需求,建立不一樣的文件和目錄:
|-- 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
配置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": [
"*://*/*"
]
}
複製代碼
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()
]
}
複製代碼
細心的同窗可能會注意到,咱們的工程項目實際上是針對用戶交互頁面的開發,並無涉及到真正的 chrome api 的調用。若是想驗證咱們的 api 使用是否正確,功能是否符合預期,可能咱們須要頻繁的進行編譯打包,再把編譯後的文件從新加載到 chrome 中來進行驗證,這是一個很是繁瑣和耗時的過程,對開發效率有很大的影響。
那如何才能快速地調試本身在調用 chrome api 及處理的過程當中問題呢?
上面咱們提到了 background
,它是一個常駐在後臺運行的腳本,咱們的交互頁能夠和它進行事件通訊,突破口就在這裏。
background
之間約定事件,經過事件的形式來通知它執行實際的 api 調用。咱們只須要事先約定好事件的類型及須要傳遞的參數便可。background
發送事件。background
的邏輯代碼,咱們能夠經過在這裏動態的修改事件響應的處理函數,來達到快速調試 api 的目的,待調試經過後,便可將正確的邏輯寫回到咱們的工程文件中,最後進行打包發佈。3.0
版本,本文的示例是按照最新的文檔來實現的,目前應用市場上大部分的擴展仍然是2.0
版本開發的,有一些配置會稍有不一樣。typescript
開發的同窗,能夠對上面的工程示例進行改造,添加tsconfig.json
並對webpack
配置稍做修改便可,還能夠引入@types/chrome
提示 chrome 相關的 api(目前尚未支持到3.0)。