前言
最近在搞一个 chrome
插件,主要开发的是 content script
往站点插入一些 dom
的功能。开发过此类功能的同学可能会清楚,如果你用纯 JS
来做这件事情的话是比较麻烦的,当然你也可以选择 jquery
。
我作为一个 React+Antd
的重度患者,肯定是希望以自己最为舒适的方式去做开发。所以就想着自己去搭建一个简单的脚手架,检验一下自己的工程化能力。
PS:这里的浏览器插件指的是 Chrome
插件,下文就不再做解释。
插件简述
先来看看一个浏览器插件原生的工程目录下会包含什么东西:
manifest.json
Chrome
扩展的配置文件,用来描述扩展的基本信息和配置。以下是一个实例:
{
"manifest_version": 3,
"name": "My Chrome Extension",
"version": "1.0",
"description": "A simple Chrome extension.",
"permissions": ["storage", "activeTab", "scripting"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
manifest_version
指定清单文件的版本,当前版本为3。name
扩展的名称。version
扩展的版本号。description
扩展的描述信息。permissions
扩展所需的权限,例如访问存储、当前标签页等。background
配置后台脚本,在manifest_version 3
中,使用service_worker
指定后台脚本文件。action
配置扩展的操作,包括默认的弹出页面和图标。default_popup
:指定用户点击扩展图标时显示的HTML文件。default_icon
:指定扩展图标的不同尺寸。
icons
配置扩展的图标,提供16x16、48x48和128x128像素的图标。content_scripts
配置内容脚本。matches
:指定内容脚本将注入哪些页面,这里使用<all_urls>
表示所有页面。js
:指定要注入的内容脚本文件。
content.js
在网页的上下文中运行,能够与网页的DOM和JavaScript交互。可以访问和操作页面上的元素、修改样式、响应用户事件等。
alert('这是contentjs')
background.js
Chrome
扩展的后台持续运行的脚本。它不直接与网页交互,而是负责处理全局的任务和逻辑。处理长时间运行的任务,如监听浏览器事件、管理扩展状态、执行定时任务等。
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed');
});
popup
在用户点击扩展图标时显示的HTML页面。它通常用作扩展的用户界面。主要用作用户与扩展交互的界面,提供按钮、表单、信息显示等。
<!DOCTYPE html>
<html>
<head>
<title>My Extension</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Hello, Chrome Extension!</h1>
<button id="action-button">Click me</button>
<script src="popup.js"></script>
</body>
</html>
document.getElementById("action-button").addEventListener("click", () => {
alert(1);
});
Content Script
OK,那我们现在第一步就先来实现:用 React+Antd
来写内容脚本。
首先把该安装的依赖先装一遍:
然后把图标、 manifest.json
这种配置的东西放到 public
目录下,后续打包通过一个 copy
插件拷贝到产物文件夹中:
然后新建一个 config
文件夹,用来放 webpack
配置:
主要的配置都在 common
中,其他两个是根据不同的环境做一些不同的策略而已。
这里主要贴一下 webpack.common.js
的配置:
const path = require("path");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
content: path.resolve(__dirname, "../src/content/index.js"),
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "../dist"),
clean: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
{
loader: "less-loader",
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
],
},
resolve: {
extensions: [".js", ".jsx"],
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
},
],
}),
],
};
先看 entry
,我们现在主要关注内容脚本,所以有一个 content
入口,入口文件对应 src/content/index.js
。
rules
中就是一些 loader
,这里就不展开, plugins
中主要是一个拷贝插件。
这里再顺便贴一下其他两个配置文件:
下面主要来看 src/content/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const div = document.createElement("div");
document.body.appendChild(div);
ReactDOM.createRoot(div).render(<App />);
首先引入一个 App
组件,这就是一个 React
组件,然后通过 ReactDOM
,把它渲染到 dom
上。注意 createElement
产生的div标签,我们的 React
组件最后会作用到这个 div
上。
所以最终渲染出来的 dom
节点,你想挂在页面的哪个元素下,你就把这个 div
追加到哪个元素下,这里我直接放到了 body
下。
最后看一下 App.jsx
,就是一段平平无奇的 React
代码了
import { Button } from "antd"
import React from "react"
const App = () => {
return (
<div>
<Button onClick={()=>{
alert('🐔')
}} type="primary">插件插入的按钮</Button>
</div>
)
}
export default App
然后在 package.json
中加入下面两条命令:
无论是开发环境打包还是生产打包,都会有一个 dist
目录,安装插件时,直接安装这个 dist
目录即可。
最后看看效果:
Background
有了上面的基础之后,我们再来打包一个 background.js
就已经轻车熟路了。
首先 manifest.json
中加入配置:
然后 webpack
打包中加一个入口:
尝试修改一下 background.js
:
import { isEmpty } from "lodash";
chrome.runtime.onInstalled.addListener(() => {
console.log("这里是background", isEmpty([1, 2, 3]));
});
发现打包也是没问题的。
Popup
最后再来打包一个 popup
页面,先来把 manifest.json
的配置加上:
打包这个 popup
页面你可以理解为跟你平时打包一个 React
的 SPA
应用一样。
首先是一个 html
模版文件,然后是一个 index.js
入口:
最后是一个 App
组件:
webpack
的配置需要注意:
先加一个入口:
然后看到了一个熟悉的插件:
filename
就是输出的文件,这个需要对应 manifest.json
的配置; chunks
就是这个插件需要帮你自动引入哪个打包后的 js
,由于我们上面入口配置的是 popup
,所以这里写 popup
。
最后大功告成:
最后
对我来说,这是一次好玩的工程化实战体验。重温了一次 webpack+react
的实战配置,如果你用的是 Vue
,那其实也大差不差。你要搞清楚的是, webpack
的打包入口在哪里,打出来的产物你希望是什么,就可以了。
希望对你有帮助,如果觉得有意思的话,点点关注点点赞吧~