Chrome扩展框架-Vue项目(用vue配合webpack实现浏览器扩展,包含热更新,无需重复加载浏览器插件)
Chrome扩展框架系列文章
本人是一个web前端开发工程师,主要是vue框架,整理了一些Chrome扩展,今后也会一直更新,有好建议的同学欢迎评论区分享讨论 ;-)
Chrome扩展专栏:点击此处
文章目录
- Chrome扩展框架系列文章
- 前言
- 一、Chrome插件是什么
- 二、Vue对于Chrome扩展有什么优势
- 三、Chrome扩展都有什么功能页面
- 1.options_page页面
- 2.popup页面
- 3.devtools_page页面
- 4.background脚本
- 5.content_scripts脚本
- 四、项目结构
- 五、主要文件讲解
- 1.background/hot-reload.js
- 2.content/index.js
- 3.devtools/index.js
- 4.vue.config.js
- 总结
前言
之前写Chrome插件的时候,老是会遇到数据回显以及事件绑定的繁琐操作,代码量不多还好,随着需求的变动,项目到后期就显得很凌乱了,不好追溯问题,懒人创造天下,就想着能不能通过Vue来实现双向绑定问题,并且通过webpack打包。
(涵盖background,devtools pannel,popup,options,content_script)
一、Chrome插件是什么
Chrome 插件,如果是翻译过来,应该是Chrome扩展,是谷歌提供给用户对谷歌浏览器的功能进行扩展。用户可以通过扩展程序来根据个人的需求和喜好定制开发一些chrome功能。这些程序开发是基于html,javascript及css等技术。
二、Vue对于Chrome扩展有什么优势
- 轻量级框架,几十KB
- 视图以及数据分离
- 双向绑定以及组件化
- 是单页面web,符合Chrome扩展需要单个html文件或者js,该项目结构更加清晰明朗
三、Chrome扩展都有什么功能页面
首先我们要介绍Chrome扩展的配置文件 manifest.json,他主要用于向浏览器报告这个插件配置了什么功能,并且将该功能页告知浏览器。
{"manifest_version": 2,"name": "penk-ext","description": "penk extension by Vue","version": "1.0.1","options_page": "options.html","homepage_url": "https://www.baidu.com","icons": {"16": "images/logo.png","48": "images/logo.png","128": "images/logo.png"},"devtools_page": "devtools.html","web_accessible_resources": ["devtools.json", "fonts/element-icons.woff", "fonts/element-icons.ttf"],"background": {"scripts": ["background/hot-reload.js", "background/index.js"]},"browser_action": {"default_popup": "popup.html"},"content_scripts": [{"matches": ["https://www.baidu.com/*","https://www.zhihu.com/*","https://aline.mshengedu.com/yunkaiadmin/*"],"js": ["js/content.js"],"css": ["css/content.css"],"run_at": "document_end"}],"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}
1.options_page页面
所谓options页,就是插件的设置页面,右键图标有一个“选项”菜单:
"options_page": "options.html"
2.popup页面
popup页面,左键图标就会弹出来的页面,主要是用来做交互的,用来配置页可以~
"browser_action": {"default_popup": "popup.html"
}
3.devtools_page页面
devtools_page本身并没有展示什么,他主要是为了加载penal面板,打开方式就是打开它的控制台,F12。
"devtools_page": "devtools.html"
4.background脚本
background这个是后台页面,他只能配置html,或者JS,只有一个能生效,这边只配置了JS,因为还需要引入一个热加载hot-reload.js。
"background": {"scripts": ["background/hot-reload.js", "background/index.js"]
}
5.content_scripts脚本
content_scripts脚本主要是在目标页面注入脚本,这边通过JS新增了一个标签,并且显示在目标页上
"content_scripts": [{"matches": ["https://www.baidu.com/*","https://www.zhihu.com/*"],"js": ["js/content.js"],"css": ["css/content.css"],"run_at": "document_end"
}]
四、项目结构
文件名 | 文件作用 |
---|---|
src\background | 存放background脚本,其中包含着 hot-reload.js,主要用来热加载Chrome扩展,避免开发的时候重复加载问题;index.js文件,主要用来读取Chrome扩展文件夹中文件,其中包含webpack打包携带的devtools下的panel信息~,用于动态生成panel,避免了重复修改扩展配置文件manifest.json。 |
src\components | 存放通用组件的地方,这里主要存放了,hello.vue,上面的很多截图都已经用过啦~ |
src\content | 存放的是content_script脚本,这里比较特殊,因为不是使用html,所以只能用src\content\index.js中通过JS创建一个标签,然后再把Vue挂载上去即可。 |
src\devtools | 这里主要存放devtools_page的代码,其中,index.html 没什么用;index.json是webpack打包生成的一个临时文件,用于记录有多少个panel面板文件;主要是index.js 用于引入文件,下文讲解;后面的panel文件夹,是Vue项目,后期webpack会将根据文件名他们打包成一个个penal.html。 |
src\options | 存放的是options_page页面,是Vue项目 |
src\popup | 存放的是popup页面,是Vue项目 |
src\static | 存放公共静态资源 |
src\manifest.development.json | 开发环境下的,会将其打包成Chrome扩展的配置文件manifest.json |
src\manifest.production.json | 生产环境下的,会将其打包成Chrome扩展的配置文件manifest.json |
vue.config.js | Vue的配置文件,里面包含了webpack的打包配置~ |
package.json | 开发环境使用npm run build-watch,会实时更新Chrome扩展,如果是目录变动之类的就需要重新run一次。 |
五、主要文件讲解
1.background/hot-reload.js
主要用于热加载,来源于网上
https://github.com/xpl/crx-hotreload/edit/master/hot-reload.js
可以打开背景页,会发现他不断的轮训文件夹,如果有变动就重新加载~
// 代码来源:https://github.com/xpl/crx-hotreload/edit/master/hot-reload.js
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/5if (tabs[0]) {window.chrome.tabs.reload(tabs[0].id)}window.chrome.runtime.reload()})
}const watchChanges = (dir, lastTimestamp) => {timestampForFilesInDirectory(dir).then(timestamp => {if (!lastTimestamp || (lastTimestamp === timestamp)) {setTimeout(() => watchChanges(dir, timestamp), 1000) // retry after 1sconsole.log("插件文件夹没有变动,1秒后再检查...");} else {reload()console.log("插件文件夹有变动...");}})
}window.chrome.management.getSelf(self => {if (self.installType === 'development') {window.chrome.runtime.getPackageDirectoryEntry(dir => watchChanges(dir))}
})
2.content/index.js
1.加载elementUI;
2.通过window.chrome.extension.getURL 加载扩展文件夹中的文件,这里主要加载字体,加载扩展内容也是需要放开权限的需要再扩展配置文件manifest.json,修改:“web_accessible_resources”: [ “fonts/element-icons.woff”, “fonts/element-icons.ttf”],
3.在页面中通过JS新建一个标签;
4.将Vue挂载在该标签上
/** @Author: Penk* @LastEditors: Penk* @LastEditTime: 2022-07-05 21:09:44* @Desc:Vue的工作原理,是将一个指定的元素替换成vue示例,所以就算这里没有html也无妨,咋们,可以生成一个拥有ID选择器的元素,并将其VUE示例挂载在上面。* @FilePath: \vue-chrome-ext\src\content\index.js*/
import Vue from "vue";
import AppComponent from "./App/App.vue";
import 'element-ui/lib/theme-chalk/index.css';
// import $ from "jquery";// 通过Chrome插件的API加载字体文件
(function insertElementIcons() {let elementIcons = document.createElement('style')elementIcons.type = 'text/css';elementIcons.textContent = `@font-face {font-family: "element-icons";src: url('${ window.chrome.extension.getURL("fonts/element-icons.woff")}') format('woff'),url('${ window.chrome.extension.getURL("fonts/element-icons.ttf")}') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/}`document.head.appendChild(elementIcons);
})();Vue.component("app-component", AppComponent);// 部分引入
// import {// Card,
// Button
// } from 'element-ui';// 部分引入
// Vue.use(Card);
// Vue.use(Button);// 全局引入
import ElementUI from 'element-ui';
Vue.use(ElementUI);// 客优云弄个固定窗口存放按钮
function initBox() {console.log("initBox...");var contentBox = document.createElement("div");contentBox.setAttribute("class", "penk");contentBox.setAttribute("id", "penk");document.body.appendChild(contentBox);
}initBox();setTimeout(() => {new Vue({el: "#penk",render: createElement => {return createElement(AppComponent);}});
}, 2000);
3.devtools/index.js
咋们最开始的目的,是为了运行打包命令,就可以可以直接将devtools,里面的xxx文件夹,挨个编译成对应的xxx.html,并且devtools也会将xxx.html加载进去面板中去,并且面板名称就是文件夹名xxx。
打包后的文件如下:
于是呼,遇到了如下问题:
1、我怎么知道那个哪个html是属于devtools里面的呢,强迫症的我又不喜欢根据前缀判断?
答:webpack(vue.config.js)打包前将devtools目录里面的文件夹名遍历一下,存储在一个数组中,再变成一个临时文件,就是devtools/index.json,然后将其打包成devtools.json,放在扩展文件夹中,然后运行devtools/index的时候,只要读取了该文件,就可以知道有什么panel面板页面了。
// Vue.config.js
// 配置devtools
function dealDevtools() {// 读取devtools 目录文件var ret = fs.readdirSync('src/devtools');var devtools_panels = [];// 文件夹则打包,并且用数组存储文件夹信息ret.forEach(e => {var isDir = fs.lstatSync('src/devtools/' + e).isDirectory();if (isDir) {pagesObj[e] = {entry: `src/devtools/${e}/index.js`,template: "public/index.html",filename: `${e}.html`};devtools_panels.push(e);}})// 文件夹信息写进JSON文件var json = {panels: [...devtools_panels]}const content = JSON.stringify(json, null, "\t");// 生成临时文件devtools/index.jsonfs.writeFileSync("src/devtools/index.json", content, function (err) {if (err) {return console.log(err);}});// 将devtools/index.json文件打包到dist/devtools.jsonplugins.push(CopyWebpackPlugin([{from: path.resolve("src/devtools/index.json"),to: path.resolve("dist/devtools.json")}]))
}
2、devtools根据devtools.json文件,新增panels
// devtools/index.js
// 读取相对目录下的文件不用特殊权限,根据这个文件,自动配置panels
var url = 'devtools.json';
fetch(url).then(function (response) {//response.status表示响应的http状态码if (response.status === 200) {//json是返回的response提供的一个方法,会把返回的json字符串反序列化成对象,也被包装成一个Promise了response.json().then(data => {console.log(data);data.panels.forEach(panelName => {window.chrome.devtools.panels.create(panelName, 'static/images/logo.png', `${panelName}.html`, function (panel) {console.log('自定义面板创建成功!', panel); // 注意这个log一般看不到});});});} else {return {}}
});
4.vue.config.js
Vue的配置文件,里面有webpack打包的配置
注释很详细了,可以看注释~~~
/** @Author: Penk* @LastEditors: Penk* @LastEditTime: 2022-07-06 18:26:53* @Desc:这个配置有点复杂,需要慢慢阅读了...* 另外,有时候有问题的话,可以试试手动重新加载插件,有可能是修改了这个文件的问题~* @FilePath: \vue-chrome-ext\vue.config.js*/
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
const fs = require("fs");
const ZipPlugin = require('zip-webpack-plugin');// Generate pages object
const pagesObj = {};let plugins = []// 配置"popup", "options", "devtools"
dealPerfectProjectByVue();// 配置静态文件
dealStatic();// 配置manifest文件
dealManifest();// 配置devtools
dealDevtools();// 配置有完整vue项目的chrome扩展项,background没有html页面,只能特殊处理...
// 配置background
dealBackground();// 开发环境将热加载文件复制到dist文件夹
if (process.env.NODE_ENV !== 'production') {plugins.push(CopyWebpackPlugin([{from: path.resolve("src/background/hot-reload.js"),to: path.resolve("dist/background")}]))
}
// 生产环境打包dist为zip
else if (process.env.NODE_ENV === 'production') {plugins.push(new ZipPlugin({path: path.resolve("dist"),filename: 'dist.zip',}))
}module.exports = {pages: pagesObj,// // 生产环境是否生成 sourceMap 文件productionSourceMap: true,configureWebpack: {resolve: {alias: {// 'src': '@', 默认已配置'assets': '@/assets','common': '@/common','components': '@/components','api': '@/api','views': '@/views','plugins': '@/plugins','utils': '@/utils',}},entry: {'content': './src/content/index.js'},output: {filename: 'js/[name].js'},plugins},css: {extract: {filename: 'css/[name].css'}},chainWebpack: config => {// 处理字体文件名,去除hash值const fontsRule = config.module.rule('fonts')// 清除已有的所有 loader。// 如果你不这样做,接下来的 loader 会附加在该规则现有的 loader 之后。fontsRule.uses.clear()fontsRule.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i).use('url').loader('url-loader').options({limit: 1000,name: 'fonts/[name].[ext]'})// 查看打包组件大小情况if (process.env.npm_config_report) {// 在运行命令中添加 --report参数运行, 如:npm run build --reportconfig.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)}}
};// 配置manifest文件
function dealManifest() {const manifest =process.env.NODE_ENV === "production" ? [{from: path.resolve("src/manifest.production.json"),to: `${path.resolve("dist")}/manifest.json`}] : [{from: path.resolve("src/manifest.development.json"),to: `${path.resolve("dist")}/manifest.json`}];plugins.push(CopyWebpackPlugin(manifest));
}// 配置devtools
function dealDevtools() {// 读取devtools 目录文件var ret = fs.readdirSync('src/devtools');var devtools_panels = [];// 文件夹则打包ret.forEach(e => {var isDir = fs.lstatSync('src/devtools/' + e).isDirectory();if (isDir) {pagesObj[e] = {entry: `src/devtools/${e}/index.js`,template: "public/index.html",filename: `${e}.html`};devtools_panels.push(e);}})// 生成JSON文件var json = {panels: [...devtools_panels]}const content = JSON.stringify(json, null, "\t");// 生成临时文件devtools/index.jsonfs.writeFileSync("src/devtools/index.json", content, function (err) {if (err) {return console.log(err);}});// 将devtools/index.json文件打包到dist/devtools.jsonplugins.push(CopyWebpackPlugin([{from: path.resolve("src/devtools/index.json"),to: path.resolve("dist/devtools.json")}]))
}// 配置background
function dealBackground() {plugins.push(CopyWebpackPlugin([{from: path.resolve("src/background/index.js"),to: path.resolve("dist/background")}]))
}// 配置静态文件
function dealStatic() {// 引入图片plugins.push(CopyWebpackPlugin([{from: path.resolve("src/static"),to: path.resolve("dist/static")}]))
}// 配置有完整vue项目的chrome扩展项,background没有html页面,只能特殊处理...
function dealPerfectProjectByVue() {const chromeName = ["popup", "options", "devtools"];chromeName.forEach(name => {pagesObj[name] = {entry: `src/${name}/index.js`,template: "public/index.html",filename: `${name}.html`};});
}
总结
这个Git项目以后会持续更新优化!
有错误的地方或者可以优化的地方,在评论区留言即可~
Chrome扩展框架-Vue项目(用vue配合webpack实现浏览器扩展,包含热更新,无需重复加载浏览器插件)相关推荐
- vue3 项目创建(UI图形化界面方式,可视化操作Vue项目,vue ui)
vue3 项目创建 (UI图形化界面方式,可视化操作Vue项目,vue ui) 目录 一.图形化界面方式搭建vue3 项目前提条件 1.检查node 和 @vue/cli 版本信息 2.升级你的 No ...
- 创建vue项目,vue项目自定义配置
对于新手来说配置vue项目的各个插件时,总是会出现插件版本和vue框架版本适配问题.这篇文章简单的讲一下vue创建项目时自定义项目插件的配置. 首先我们想要在桌面创建一个新的vue项目. 首先我们找到 ...
- 在Centos 7 上跑 vue 项目 以及 Vue 热更新失效
安装npm yum install npm 安装vue npm install vue 安装vue-cli sudo npm install --global vue-cli 注意: 因为全局安装,会 ...
- node服务器放vue项目,本地Vue项目跨域请求本地Node.js服务器的配置方法
前言:跨域请求是在本地开发时经常遇到的需求,也很简单,只是几句代码配置一下的问题.我初次配置跨域请求时由于官方的说明太简洁,找到的教程又落伍,调试了一番并没有解决问题,到最后解决问题,已花费了很多时间 ...
- vue项目html,Vue项目接口.html
Vue项目接口 电商管理后台API接口文档 接口说明 接口基准地址:http://localhost:8888/api/private/v1/ 服务端已开启 CORS 跨域支持 API V1 认证统一 ...
- IDEA中创建启动Vue项目--搭建vue项目
文章目录 环境配置 安装Vue-cli构建工具 构建项目 使用命令启动Vue项目 使用idea启动Vue项目 环境配置 下载安装nodeJs 成功安装国内镜像或者是淘宝的npm镜像 详情见博客:Nod ...
- 【vue项目】vue项目创建全流程,创建使用 vue-cli 搭建项目
一. 使用 vue-cli 搭建项目 1.安装vue/cli ,执行下面的命令安装或是升级 npm i -g @vue/cli npm i -g @vue/cli 安装报错 如果安装报错如下 np ...
- vue项目查看vue版本及cli版本
查看cli版本,执行如下: vue -V 查看vue版本 npm list vue
- Vue项目搭建——Vue CLI安装失败解决方法
1.安装node 官网下载:https://nodejs.org/en/ 下一步安装 2.设置镜像 要以管理员方式运行cmd npm install -g cnpm --registry=https: ...
- vue init webpack缺少标识符_Vue脚手架热更新技术探秘
前言 热替换(Hot Module Replacement)或热重载(Hot Reload)是指在不停机状态下,实时更新,在前端利于来说,在各大框架中及库中都有体现,比如NG从5开始就提供了热更新,R ...
最新文章
- 自己理解接口回调入门
- Java如何连接openvas_gas: chinese Gui for openvAS(GAS)
- 最佳途径 | 容器规模化落地如何四步走?
- 小木棍(信息学奥赛一本通-T1442)
- node 报错 throw er; // Unhandled 'error' event 解决办法
- 计算机网络实验_中心聚焦|山东省计算机网络重点实验室学术交流会议顺利召开...
- Kickstart文件的编写
- python练手经典100例-Python入门练手100例
- samba服务器无法映射,ubuntu映射网络驱动器失败,以及samba服务
- Visual Studio 2013 旗舰版正式版密钥
- 毫米波雷达技术及应用大解析
- 技术美术自学——PBR材质通道基础 常见贴图种类列举(求dalao轻喷)
- distill介绍及优秀博客记录
- 【伪大数据】对QQ空间指定好友2017年说说数据的分析
- 逆波兰式的转换与计算(简单)
- NAS:以数据为中心的数据存储模式[zt]
- 计算机主板百科,计算机主板的模态分析
- 人工神经网络与神经网络,人工神经网络基本概念
- 道歉顶用?Facebook水逆不断
- Android解决小米手机相机和相册的问题(适配小米手机相机和相册)