快速开发Chrome扩展
前言
- 前端有不少脚手架工具可以用来初始化项目,但对初始化Chrome扩展项目来说往往大材小用,初始化完后自己还需要二次精简。
- 当然不排除已经有大佬做出了精简的Chrome扩展项目初始化脚手架工具,但本文还是旨在通过最精简的手工方式,带大家一窥Chrome扩展项目的基础框架。
最基本的步骤
初始化项目目录
mkdir chrome-demo # 新建项目目录
cd chrome-demo # 进入项目目录
pnpm init -y # 将项目初始化为Node.js项目生成并package.json文件、pnpm-lock.yaml版本锁文件
安装必要的包
pnpm i --save-dev webpack webpack-cli html-webpack-plugin mini-css-extract-plugin babel-loader css-loader copy-webpack-plugin
包说明:
- webpack: 打包工具。
- html-webpack-plugin: 帮助生成带有注入脚本标签的 HTML 文件。
- **babel-loader:**处理各版本es。
- CSS and PostCSS Loaders: 用于处理 CSS(我们稍后将与 Tailwind 一起使用)。
- CopyWebpackPlugin: 确保将
manifest.json
和任何其他资产(如图标)从src
文件夹复制到dist
文件夹。
初始化基本文件结构
可以通过复制执行bash命令创建,或者自己手动创建也可以:
mkdir -p src/scripts \
mkdir src/popup \
touch webpack.config.js src/manifest.json src/scripts/{background.ts,contentScript.ts} src/popup/{popup.html,popup.ts}
最终对应结构如下:
├── package.json
├── pnpm-lock.yaml
├── webpack.config.js
├── src
├── manifest.json
├── popup
│ ├── popup.html // 弹窗页面
│ └── popup.js
└── scripts
├── background.js // 后台服务 Worker
└── contentScript.js // 内容脚本
初始化具体文件
Webpack 配置文件webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
entry: {
popup: './src/popup/popup.js',
background: './src/scripts/background.js',
contentScript: './src/scripts/contentScript.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.jsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new HtmlWebpackPlugin({
filename: 'popup.html',
template: 'src/popup/popup.html',
chunks: ['popup'],
}),
new CopyWebpackPlugin({
patterns: [
{ from: 'src/manifest.json', to: 'manifest.json' },
// { from: 'src/icons', to: 'icons' }, // 复制任何其他资产
],
}),
],
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? false : 'inline-source-map', // 在生产中禁用源映射
};
};
清单文件manifest.json
复制以下内容到manifest.json:
{
"manifest_version": 3,
"name": "Base Chrome extension",
"version": "1.0",
"description": "A Chrome extension demo.",
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
],
"permissions": ["storage"]
}
主要属性:
- **manifest_version: **必须使用 V3:Chrome 扩展强制要求,V3 更安全且性能更好(如限制远程代码加载)。
- **action:**控制浏览器工具栏按钮的交互逻辑,
default_popup
指向一个 HTML 文件(如popup.html
)。用户点击扩展图标时,弹出窗口将加载。 - background.service_worker:Manifest V3 特性,替代了 V2 的
background.page
或background.scripts
,用于处理事件监听、跨组件通信等。 - **content_scripts:**网页注入脚本,
contentScript.js
会注入到所有网页(<all_urls>
)中,可直接操作 DOM 或与扩展通信。 - **permissions: ["storage"]:**申请的浏览器权限,这里只申请了存储权限,允许扩展使用
chrome.storage
API 存储数据(类似localStorage
,但支持异步操作)。
弹出框口文件
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Popup</title>
</head>
<body>
<div>
<button id="show-message">点我</button>
</div>
<!-- 无需手动引入Webpack会在内部添加它 -->
<!-- <script src="popup.js"></script> -->
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', () => {
const curButton = document.getElementById('show-message');
if (curButton) {
curButton.addEventListener('click', () => {
alert('用户点了一次');
});
}
});
进阶步骤
除了上面这写基本的步骤外,开发稍复杂点儿的扩展可能还会用上React
添加 React
安装 React 和 ReactDOM
npm i react react-dom
popup.html改动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Popup</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
popup.js改动
将 popup.js
重命名为 popup.jsx
,并更新为一个基本的 React 组件:
import React from 'react';
import { createRoot } from 'react-dom/client';
const Popup = () => {
const handleClick = () => {
alert('用户点了一次');
};
return (
<>
<button onClick={handleClick}>
点我
</button>
</>
);
};
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<Popup />);
最终构建
命令行执行
npx webpack --mode development
使用插件
- 打开Chrome浏览器,输入
chrome://extensions/
并回车,进入扩展管理页面。 - 打开右上角的“开发者模式”。
- 点击左上角的“加载已解压的扩展程序”。
- 选择打包好的dist目录即可。
总结
本文通过摒弃所有旁枝末节、增光添彩的选项、三方组件,为大家呈现一个最基本、最干净的Chrome扩展项目该有的架构。方便初步接触的人不至于被杂项分神,有助于快速了解其核心。
当然也有因此需要暂时舍去的部分,比如:
- 没有引入ts;
- 没有引入sass、less、Tailwind 等样式库;
- 没有