本人Vue3小白一枚,目前正在研究基于Vue3的Chrome浏览器插件的使用,经过不断尝试和整合各路大佬方法,现将自己尝试有效的项目框架搭建流程进行总结。在此非常感谢大佬们的分享。
本文主要参考文章——15000字大章带你一步一步使用Vue3开发chrome浏览器插件
vue create XXX
创建新的vue工程项目npm install element-plus --save
向Vue项目安装element-plus组件├── dist
│ ├── assets
│ │ ├── images
│ │ │ ├── icon128.png
│ │ │ ├── icon16.png
│ │ │ └── icon48.png
│ │ └── logo.png
│ ├── js
│ │ ├── background.js
│ │ ├── chunk-vendors.js
│ │ ├── content.js
│ │ ├── inject.js
│ │ └── popup.js
│ ├── manifest.json
│ └── popup.html
├── src
│ ├── assets
│ │ ├── images
│ │ │ ├── icon128.png
│ │ │ ├── icon16.png
│ │ │ └── icon48.png
│ │ └── logo.png
│ ├── background
│ │ └── main.js
│ ├── content
│ │ ├── components
│ │ │ └── app.vue
│ │ └── main.js
│ ├── plugins
│ │ ├── inject.js
│ │ └── manifest.json
│ ├── popup
│ │ ├── components
│ │ │ └── app.vue
│ │ ├── index.html
│ │ └── main.js
│ ├── router
│ │ └── index.js
│ └── utils
│ └── hotReload.js
├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── babel.config.js
├── jsconfig.json
├── package-lock.json
├── package.json
├── README.md
└── vue.config.js
npm run build
指令后生成的,其他均应在执行npm run build
前准备就绪src/popup/main.js
中添加element-plus插件,代码如下:import { createApp } from 'vue'
import App from './components/app.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
const app = createApp(App)
app.use(ElementPlus, {locale: zhCn})
app.mount('#app')
chrome: true
从而让chrome属性在全局的.js文件中为可用状态module.exports = {
root: true,
globals: {
chrome: true,
},
env: {
node: true
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
// 复制文件到指定目录
const copyFiles = [
{
from: path.resolve("src/plugins/manifest.json"),
to: `${path.resolve("dist")}/manifest.json`
},
{
from: path.resolve("src/assets"),
to: path.resolve("dist/assets")
},
{
from: path.resolve("src/plugins/inject.js"),
to: path.resolve("dist/js")
}
];
// 复制插件
const plugins = [
new CopyWebpackPlugin({
patterns: copyFiles
})
];
// 页面文件
const pages = {};
// 配置 popup.html 页面
const chromeName = ["popup"];
chromeName.forEach(name => {
pages[name] = {
entry: `src/${name}/main.js`,
template: `src/${name}/index.html`,
filename: `${name}.html`
};
});
module.exports = {
pages,
productionSourceMap: false,
// 配置 content.js background.js
configureWebpack: {
entry: {
content: "./src/content/main.js",
background: "./src/background/main.js"
},
output: {
filename: "js/[name].js"
},
plugins
},
// 配置 content.css
css: {
extract: {
filename: "css/[name].css"
}
},
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.output.filename('js/[name].js').end()
config.output.chunkFilename('js/[name].js').end()
}
}
}
"scripts": {
"watch": "vue-cli-service build --watch",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
console.log('this is background')
this is the content
import { createApp } from 'vue'
import app from './components/app.vue'
joinContent(app)
injectJsInsert()
function joinContent (element) {
const div = document.createElement('div')
div.id = 'joinContentApp'
document.body.appendChild(div)
console.log(div)
createApp(element).mount('#joinContentApp')
}
//chrome的API接口,用于传输或监听数据信号
chrome.extension.onRequest.addListener(
function (request) {
if (request.popAction == "Test") {
console.log("test")
}
}
);
function injectJsInsert () {
document.addEventListener('readystatechange', () => {
const injectPath = 'js/inject.js'
const script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.src = chrome.extension.getURL(injectPath)
document.body.appendChild(script)
})
}
console.log('this is inject')
{
"manifest_version": 2,
"name": "test",
"description": "Vue3的Chrome插件",
"version": "1.0.0",
"browser_action": {
"default_title": "plugin-base-vue3",
"default_icon": "assets/images/icon48.png",
"default_popup": "popup.html"
},
"permissions": [],
"background": {
"scripts": ["js/chunk-vendors.js", "js/background.js"]
},
"icons": {
"16": "assets/images/icon16.png",
"48": "assets/images/icon48.png",
"128": "assets/images/icon128.png"
},
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"css": ["css/content.css"],
"js": ["js/chunk-vendors.js", "js/content.js"],
"run_at": "document_idle"
}
],
"web_accessible_resources": ["js/inject.js"]
}
<template>
<div class="wrapper">
<el-button type="danger" @click="test">测试按钮</el-button>
</div>
</template>
<script setup>
const test = () => {
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.sendRequest(tab.id, { popAction: "Test"});
});
}
</script>
<style scoped>
.wrapper{
width: 100px;
height: 100px;
background-color: aquamarine;
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>test</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>
npm run build
指令以获得dist文件,使用Chrome加载dist文件夹以加载插件// 加载文件
const filesInDirectory = dir =>
new Promise(resolve =>
dir.createReader().readEntries(entries => {
Promise.all(
entries
.filter(e => e.name[0] !== '.')
.map(e =>
e.isDirectory ? filesInDirectory(e) : new Promise(resolve => e.file(resolve))
)
)
.then(files => [].concat(...files))
.then(resolve);
})
);
// 遍历插件目录,读取文件信息,组合文件名称和修改时间成数据
const timestampForFilesInDirectory = dir =>
filesInDirectory(dir).then(files =>
files.map(f => f.name + f.lastModifiedDate).join()
);
// 刷新当前活动页
const reload = () => {
window.chrome.tabs.query({
active: true,
currentWindow: true
},
tabs => {
// NB: see https://github.com/xpl/crx-hotreload/issues/5
if (tabs[0]) {
window.chrome.tabs.reload(tabs[0].id);
}
// 强制刷新页面
window.chrome.runtime.reload();
}
);
};
// 观察文件改动
const watchChanges = (dir, lastTimestamp) => {
timestampForFilesInDirectory(dir).then(timestamp => {
// 文件没有改动则循环监听watchChanges方法
if (!lastTimestamp || lastTimestamp === timestamp) {
setTimeout(() => watchChanges(dir, timestamp), 1000); // retry after 1s
} else {
// 强制刷新页面
reload();
}
});
};
const hotReload = () => {
window.chrome.management.getSelf(self => {
if (self.installType === 'development') {
// 获取插件目录,监听文件变化
window.chrome.runtime.getPackageDirectoryEntry(dir => watchChanges(dir));
}
});
};
export default hotReload;
import hotReload from '@/utils/hotReload'
hotReload()
console.log('this is background')
scripts
字段中添加"watch": "vue-cli-service build --watch",
来向NPM脚本中添加热更新快捷操作{
"name": "plugin",
"version": "0.1.0",
"private": true,
"scripts": {
"watch": "vue-cli-service build --watch",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"element-plus": "^2.2.13",
"vue": "^3.2.13",
"vue-router": "^4.0.3"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"less": "^4.1.3",
"less-loader": "^11.0.0"
}
}
npm i
和npm install element-plus --save
指令完成所需环境的布置。环境布置完成后就可以愉快的开始你的创作啦。