失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > vue-cli3开发Chrome Extension实践 | vue开发浏览器插件 | vue开发chrome插件

vue-cli3开发Chrome Extension实践 | vue开发浏览器插件 | vue开发chrome插件

时间:2023-06-09 07:06:40

相关推荐

vue-cli3开发Chrome Extension实践 | vue开发浏览器插件 | vue开发chrome插件

转自: Mrli 的博客 vue-cli3开发Chrome Extension实践

简介

之前找了不少如何开发谷歌插件的文章,结果发现都是些很基础的内容,并没有写到如何快速编译打包插件。我就在想为什么不能通过webpack来打包插件呢?如果通过webpack编译的话,就能使开发过程变得更舒服,使文件结构趋向模块化,并且打包的时候直接编译压缩代码。后来发现了vue-cli-plugin-chrome-ext插件,通过这个插件能很方便地用vue-cli3来开发谷歌插件,并能直接引用各种UI框架跟npm插件。

tip:如果你没接触过谷歌插件开发的话建议先看看基础文档:

Chrome 插件开发中文文档Chrome插件开发全攻略

环境需求

nodeyarnvue cli

注意:因开发环境随时间前进,存在版本优化升级,按本文操作可能存在个别微差,有能力者自行解决,如无法解决可在文末下载已搭建好的框架模板,或调整到和我一致的开发环境

搭建环境

创建一个vue-cli3项目: vue create vue-extension,对话流程选择默认就行。

进入项目cd vue-extension

安装vue-cli-plugin-chrome-ext插件:vue add chrome-ext,根据安装对话选项设置好。

删除vue-cli3无用文件跟文件夹:src/main.js、src/components

运行项目

运行开发环境

npm run build-watch

运行开发环境,对修改文件进行实时编译并自动在根目录下生成dist文件夹,然后在浏览器上加载dist文件夹完成插件安装。(注意:修改background文件跟manifest.json文件并不能实时刷新代码,需要重新加载插件才行。后面已经有实时刷新的解决方法)

运行生产环境

npm run build

运行生产环境编译打包,将所有文件进行整合打包。

浏览器加载生成的dish

引入element UI

目前的插件加载到浏览器后弹出页面是这种界面: 平时我们肯定要引入好看的UI框架的,在这里我们可以引入element-ui

npm install element-ui

如果出现"Not Found - Get … @vue%2fvue-loader-…"的情况多半是选择vue2开发但vue cli版本过高导致,解决办法可以调整vue cli版本或安装指定"core-js"版本号(如3.6.5)

考虑到插件打包后的文件大小,最后通过按需加载的方式来引入组件,按照element-ui官方的按需加载方法,要先安装babel-plugin-component插件:

npm install babel-plugin-component -D

然后,将babel.config.js修改为

module.exports = {presets: ['@vue/app'],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]}

接下来修改popup相关文件引入所需组件, src/popup/index.js内容

import Vue from "vue";import AppComponent from "./App/App.vue";ponent("app-component", AppComponent);import {Card} from 'element-ui';Vue.use(Card);new Vue({el: "#app",render: createElement => {return createElement(AppComponent);}});

src/popup/App/App.vue 内容

<template><el-card class="box-card"><divslot="header"class="clearfix"><span>卡片名称</span><el-buttonstyle="float: right; padding: 3px 0"type="text">操作按钮</el-button></div><divv-for="o in 4":key="o"class="text item">{{'列表内容 ' + o }}</div></el-card></template><script>export default {name: 'app',}</script><style>.box-card {width: 300px;}</style>

渲染效果

当然,不仅仅是插件内部的页面,还可以将element-ui组件插入到content页面。

content.js(注入web脚本)使用element-ui组件

content.js主要作用于浏览网页,对打开的网页进行插入、修改DOM,对其进行操作交互。别觉得element-ui只能配合vue使用,其实就是一个前端框架,只要我们引入了就能使用,webpack会自动帮我们抽离出来编译打包。

根据评论的朋友提示,可以通过Chrome插件的chrome.extension.getURLAPI来引入字体文件,解决element-ui无法引入相对路径的字体文件问题。

首先我们创建src/content/index文件,在里面我们通过chrome.extension.getURLAPI来引入插件的字体文件,内容

import {Message,MessageBox} from 'element-ui';// 通过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);})();MessageBox.alert('这是一段内容', '标题名称', {confirmButtonText: '确定',callback: action => {Message({type: 'info',message: `action: ${action }`});}})

content.js里调用了chrome API而在vue里并不知道chrome是全局变量,可执行npm install --save @types/chrome 或 在根目录添加 .eslintrc.js 进行全局变量声明vue.config.js增加content.js文件的打包配置,因为content.js(background.js同样可以只生成js文件)只有js文件,不用像app模式那样打包生成相应的html文件。这里我们还要对字体打包配置处理下,因为默认打包后的文件名是带有hash值的,在这里我们要去除掉,完整内容如下

const CopyWebpackPlugin = require("copy-webpack-plugin");const path = require("path");// Generate pages objectconst pagesObj = {};const chromeName = ["popup", "options"];chromeName.forEach(name => {pagesObj[name] = {entry: `src/${name}/index.js`,template: "public/index.html",filename: `${name}.html`};});// 生成manifest文件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`};const plugins = [CopyWebpackPlugin([manifest])]module.exports = {pages: pagesObj,// // 生产环境是否生成 sourceMap 文件productionSourceMap: false,configureWebpack: {entry: {'content': './src/content/index.js'},output: {filename: 'js/[name].js'},plugins: plugins },css: {extract: {filename: 'css/[name].css'// chunkFilename: '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]'})}};

最后在manifest.development.json加载content.js文件,以及将字体文件添加到网页可加载资源字段web_accessible_resources里去

{"manifest_version": 2,"name": "chrome-ext","description": "chrome extension","version": "0.0.1","options_page": "options.html","browser_action": {"default_popup": "popup.html"},"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'","content_scripts": [{"matches": ["*://*./*"],"css": ["css/content.css"],"js": ["js/content.js"],"run_at": "document_end"}],"web_accessible_resources": ["fonts/*"]}

然后浏览器重新加载插件后打开/网址后可看到:

实时刷新插件

之前写的时候发现单纯地通过vue-cli3更新代码并不能使插件的background.js、content.js也跟着更新,因为代码已经加载到浏览器了,浏览器并不会监听这些文件的变化。也是通过评论的朋友推荐,通过crx-hotreload可以完美实现实时刷新功能,而不用重新手动加载。代码还简单易用,在这里我们直接将代码复制到src/utils/hot-reload.js文件:

// 代码来源:/xpl/crx-hotreload/edit/master/hot-reload.jsconst 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 /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 1s} else {reload()}})}window.chrome.management.getSelf(self => {if (self.installType === 'development') {window.chrome.runtime.getPackageDirectoryEntry(dir => watchChanges(dir))}})

然后在vue.config.js对热刷新代码进行处理,如果是开发环境的话就将其复制到assets文件夹里面:

// vue.config.js...// 在这段下面添加const plugins = [CopyWebpackPlugin([manifest])]// 开发环境将热加载文件复制到dist文件夹if (process.env.NODE_ENV !== 'production') {plugins.push(CopyWebpackPlugin([{from: path.resolve("src/utils/hot-reload.js"),to: path.resolve("dist")}]))}...

vue.config.js 配置如图

最后只要在开发环境manifest.development.json里配置一下,将hot-reload.js加载到background运行环境中即可:

"background": {"scripts": ["hot-reload.js"] }

添加打包文件大小预览配置

既然用了vue-cli3了,怎能不继续折腾呢,我们平时用webpack开发肯定离不开打包组件预览功能,才能分析哪些组件占用文件大,该有的功能一个都不能少😎。这么实用的功能,实现起来也无非就是添加几行代码的事:

// vue.config.jsmodule.export = {/* ... */chainWebpack: config => {// 查看打包组件大小情况if (process.env.npm_config_report) {// 在运行命令中添加 --report参数运行, 如:npm run build --reportconfig.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)}}}

配置代码如图

就辣么简单,然后运行npm run build --report看看效果

npm run build --report

自动打包zip

做过Chrome插件的都知道,提交到谷歌插件市场的话需要打包为zip文件才行。如果每次我们都需要将编译文件打包成zip的话就太麻烦了,这种每次都要经历的重复流程当然是交给程序来处理啦。 想打包zip的话首先要安装zip-webpack-plugin插件到开发环境:

npm install --save-dev zip-webpack-plugin

然后添加打包代码到vue.config.js: vue.config.js最终全文代码

// vue.config.jsconst CopyWebpackPlugin = require("copy-webpack-plugin");const ZipPlugin = require('zip-webpack-plugin');const path = require("path");// Generate pages objectconst pagesObj = {};const chromeName = ["popup", "options"];chromeName.forEach(name => {pagesObj[name] = {entry: `src/${name}/index.js`,template: "public/index.html",filename: `${name}.html`};});// 生成manifest文件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`};const plugins = [CopyWebpackPlugin([manifest])]// 开发环境将热加载文件复制到dist文件夹if (process.env.NODE_ENV !== 'production') {plugins.push(CopyWebpackPlugin([{from: path.resolve("src/utils/hot-reload.js"),to: path.resolve("dist")}]))}// 生产环境打包dist为zipif (process.env.NODE_ENV === 'production') {plugins.push(new ZipPlugin({path: path.resolve("dist"),filename: 'dist.zip',}))}module.exports = {pages: pagesObj,// // 生产环境是否生成 sourceMap 文件productionSourceMap: false,configureWebpack: {entry: {'content': './src/content/index.js'},output: {filename: 'js/[name].js'},plugins: plugins},css: {extract: {filename: 'css/[name].css'// chunkFilename: '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) {config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)}}};

搞定收工!

结语

事实证明,vue-cli3很强大,vue相关的插件并不是不能应用于开发浏览器插件,element-ui也不仅限于vue的运用。只有你想不到,没有做不到的事😁。

tip:如果你懒得从头开始搭建模板的话也可以从GitHub拉取 vue-extension-template 或 csdn 下载

如果觉得《vue-cli3开发Chrome Extension实践 | vue开发浏览器插件 | vue开发chrome插件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。