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实现浏览器扩展,包含热更新,无需重复加载浏览器插件)相关推荐

  1. vue3 项目创建(UI图形化界面方式,可视化操作Vue项目,vue ui)

    vue3 项目创建 (UI图形化界面方式,可视化操作Vue项目,vue ui) 目录 一.图形化界面方式搭建vue3 项目前提条件 1.检查node 和 @vue/cli 版本信息 2.升级你的 No ...

  2. 创建vue项目,vue项目自定义配置

    对于新手来说配置vue项目的各个插件时,总是会出现插件版本和vue框架版本适配问题.这篇文章简单的讲一下vue创建项目时自定义项目插件的配置. 首先我们想要在桌面创建一个新的vue项目. 首先我们找到 ...

  3. 在Centos 7 上跑 vue 项目 以及 Vue 热更新失效

    安装npm yum install npm 安装vue npm install vue 安装vue-cli sudo npm install --global vue-cli 注意: 因为全局安装,会 ...

  4. node服务器放vue项目,本地Vue项目跨域请求本地Node.js服务器的配置方法

    前言:跨域请求是在本地开发时经常遇到的需求,也很简单,只是几句代码配置一下的问题.我初次配置跨域请求时由于官方的说明太简洁,找到的教程又落伍,调试了一番并没有解决问题,到最后解决问题,已花费了很多时间 ...

  5. vue项目html,Vue项目接口.html

    Vue项目接口 电商管理后台API接口文档 接口说明 接口基准地址:http://localhost:8888/api/private/v1/ 服务端已开启 CORS 跨域支持 API V1 认证统一 ...

  6. IDEA中创建启动Vue项目--搭建vue项目

    文章目录 环境配置 安装Vue-cli构建工具 构建项目 使用命令启动Vue项目 使用idea启动Vue项目 环境配置 下载安装nodeJs 成功安装国内镜像或者是淘宝的npm镜像 详情见博客:Nod ...

  7. 【vue项目】vue项目创建全流程,创建使用 vue-cli 搭建项目

    一. 使用 vue-cli 搭建项目 1.安装vue/cli ,执行下面的命令安装或是升级 npm i -g @vue/cli npm i -g @vue/cli 安装报错 ​ 如果安装报错如下 np ...

  8. vue项目查看vue版本及cli版本

    查看cli版本,执行如下: vue -V 查看vue版本 npm list vue

  9. Vue项目搭建——Vue CLI安装失败解决方法

    1.安装node 官网下载:https://nodejs.org/en/ 下一步安装 2.设置镜像 要以管理员方式运行cmd npm install -g cnpm --registry=https: ...

  10. vue init webpack缺少标识符_Vue脚手架热更新技术探秘

    前言 热替换(Hot Module Replacement)或热重载(Hot Reload)是指在不停机状态下,实时更新,在前端利于来说,在各大框架中及库中都有体现,比如NG从5开始就提供了热更新,R ...

最新文章

  1. 自己理解接口回调入门
  2. Java如何连接openvas_gas: chinese Gui for openvAS(GAS)
  3. 最佳途径 | 容器规模化落地如何四步走?
  4. 小木棍(信息学奥赛一本通-T1442)
  5. node 报错 throw er; // Unhandled 'error' event 解决办法
  6. 计算机网络实验_中心聚焦|山东省计算机网络重点实验室学术交流会议顺利召开...
  7. Kickstart文件的编写
  8. python练手经典100例-Python入门练手100例
  9. samba服务器无法映射,ubuntu映射网络驱动器失败,以及samba服务
  10. Visual Studio 2013 旗舰版正式版密钥
  11. 毫米波雷达技术及应用大解析
  12. 技术美术自学——PBR材质通道基础 常见贴图种类列举(求dalao轻喷)
  13. distill介绍及优秀博客记录
  14. 【伪大数据】对QQ空间指定好友2017年说说数据的分析
  15. 逆波兰式的转换与计算(简单)
  16. NAS:以数据为中心的数据存储模式[zt]
  17. 计算机主板百科,计算机主板的模态分析
  18. 人工神经网络与神经网络,人工神经网络基本概念
  19. 道歉顶用?Facebook水逆不断
  20. Android解决小米手机相机和相册的问题(适配小米手机相机和相册)

热门文章

  1. 在3ds max中,什么是PBR材质?
  2. 记录一次在线网页加密PDF解密过程
  3. 微信关注公众号获取用户名的方法
  4. 阿里云 EMAS Serverless 重磅发布
  5. 怎么组建云计算中心?
  6. php excel 导入图片,利用php实现读取excel中的图片
  7. 我的世界服务器物品管道,物品导管 (Item Conduit)
  8. SeaweedFS 分布式 上传、下载、删除附件公共接口
  9. 用7z命令压缩文件夹
  10. 什么是Oracle数据库伪列,ORA-00976: 此处不允许指定的伪列或运算符