开发chrome扩展插件修改地址

引言

在前端开发过程中,一般分为三个环境:开发环境、测试环境和生产环境。这三个环境对于前端而言,不过就是请求的 API 接口不同罢了。如果是vue3项目,可以通过 import.meta.env.MODE来区分环境,可是站在后端兄弟角度,就必须修改配置文件的地址才能调试。如果要在本地调试,必须 clone 前端代码部署才行,这极为不方便。为此,我开发了一个 Chrome 插件用于解决这个问题,与项目的配置文件配合使用,可以提高后端同事的调试效率。

为什么采用插件

一般情况下,前端项目的配置文件会单独拧出来,方法网站根目录下。如果项目部署需要部署在不同的环境或者平台中,只需修改 config.js 的地址即可。我们可以将其挂载到window上,使之成为一个全局变量。通过浏览器的控制台console修改,这个没问题,但是如果页面刷新,修改的内容由于是保存在内存中,会被清空。

为此,修改的内容需要持久化储存。没错,数据可以储存在storage中,页面刷新后,可以从storage中读取应用。但是数据在控制台修改毕竟很繁琐,因此还需要一个可视化的页面去修改数据,将数据存储到storage中。如果开发一个前端页面去做这事,就有点得不偿失,而选择开发插件是一种更优的选择。

插件的介绍与开发

谷歌的插件网上有非常多的文档,本文只讲述为项目定制插件的核心实现。

其效果如下:

插件的功能

插件提供的功能非常简单。用户安装插件后,可以动态修改 接口地址,项目自动刷新,启用新的接口地址访问后台;在修改接口地址后,也可以恢复默认配置,系统会启用默认地址。

插件要主要解决的问题就是将输入的地址存储到网页的storage中,网页会去读取storage的值,并刷新页面,应用新值。

其核心工作与实现如下:

popup.html 界面

popup.html提供数据的入口以及交互操作界面,其中还会引入popup.js

html 复制代码
<div class="container">
  <div class="formItem">
    <h3>MMS自定义API地址:</h3>
    <img id="reset" title="重置" />
  </div>
  <div>
    <p>BASE_URL:</p>
    <div class="formItem">
      <input type="text" id="baseURL" placeholder="http://" />
      <button id="btn">保存</button>
    </div>
  </div>
</div>
<script src="../js/popup.js"></script>
popup.js

popup.js的作用包括设置弹窗内容、响应用户交互、处理事件以及与后台脚本进行数据交换。由于popup.js无法与网页进行通信,因此需要借助于后台脚本。

响应用户交互,其实现如下,通过chrome.runtime.sendMessagebackground.js发送消息

js 复制代码
/** 监听保存按钮事件 */
doms.btn.addEventListener("click", () => {
  const val = doms.input.value;
  if (val) {
    if (isValidURL(val)) {
      //判断输入是否是合法的url
      chrome.runtime.sendMessage(
        { action: "UPDATE_GLOBAL_VAR", value: val },
        (response) => {
          if (response.status === "success") {
            console.log("🚀设置BASE_URL成功");
            window.close();
          } else {
            alert("🚀设置BASE_URL失败");
          }
        }
      );
    } else {
      doms.input.value = preValue;
      alert("接口地址不合法");
    }
  }
});
background.js

background.js主要用于处理插件的后台逻辑和管理扩展的生命周期,此次开发中background.js主要做了两件事:

  • 1.安装成功后初始化storage.local的变量
  • 2.监听popup.js发送的消息以及接收到消息后,给popup.js一个反馈,并且将数据通过chrome.tab.sendMessage发送给content_script.js

其实现如下:

js 复制代码
// background.js
console.log("🚀 加载background.js成功");

// background.js
chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.local.set({ globalVar: null });
});

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === "UPDATE_GLOBAL_VAR") {
    chrome.storage.local.set({ globalVar: message.value });
    sendResponse({ status: "success" });
    chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
      chrome.tabs.sendMessage(tabs[0].id, {
        type: "UPDATE_CONTENT",
        data: message.value,
      });
    });
  }
});
content_script.js

插件中的content_script.js就像一个中转站一样,用于脚本和网页之间沟通的桥梁,监听二者的消息再转发。

content_script.jschrome.runtime.onMessage监听background.js的消息,再通过window.postMessage转发数据给网页

其实现如下:

js 复制代码
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
  console.log("Message received in content script:", message);
  if (message.type === "UPDATE_CONTENT") {
    console.log("Data from background:", message.data);
    window.postMessage({
      type: _CONST_.FROM_CONTENT_SCRIPT,
      data: message.data,
    });
  }
});

此外,由于插件还做到了初始配置的回显,所以在content_script.js中还通过window.addEventListener监听了网页的消息,如下

js 复制代码
window.addEventListener("message", function (event) {
  if (
    event.source === window &&
    event.data.type &&
    event.data.type == _CONST_.FROM_CONTENT_WEBPAGE
  ) {
    console.log("🚀 ~ WebPage`s Message received in content script:", event);

    // 定义你想要获取的数据键
    const keys = ["globalVar"];

    chrome.storage.local.get(keys, function (result) {
      console.log("🚀 ~ result:", result);
      // 确保获取的数据存在
      if (chrome.runtime.lastError) {
        console.error("Error retrieving data:", chrome.runtime.lastError);
        return;
      }

      const webPageValue = event.data.data;

      //存储最初始的值,用于重置
      if (result.globalVar == null) {
        chrome.storage.local.set({ originalValue: webPageValue });
      }
      // 处理获取的数据
      if (result.globalVar != webPageValue) {
        chrome.storage.local.set({ globalVar: webPageValue });
      }
    });
  }
});

content_script.js接收到网页消息后,将数据存储在chrome.storage.local中。

config.js

config.js不属于插件的内容,存在于前端项目中,但是config.js相当于是数据的最终接收方和响应对象。

其实现如下:

js 复制代码
window.addEventListener("message", function (event) {
  if (
    event.source === window &&
    event.data.type &&
    event.data.type == _CONST_.FROM_CONTENT_SCRIPT
  ) {
    window.localStorage.setItem(
      _CONST_.CONFIG_PLUGIN,
      JSON.stringify({ BASE_URL: event.data.data })
    );
    window.location.reload();
  }
});

let CONFIG_PLUGIN_STORAGE = window.localStorage.getItem(_CONST_.CONFIG_PLUGIN);

CONFIG_PLUGIN_STORAGE = CONFIG_PLUGIN_STORAGE
  ? JSON.parse(CONFIG_PLUGIN_STORAGE)
  : {};

window.config = {
  BASE_URL: "http://192.168.145.74:18430",
  ...CONFIG_PLUGIN_STORAGE,
};

window.postMessage({
  type: _CONST_.FROM_CONTENT_WEBPAGE,
  data: window.config.BASE_URL,
});

config.js的作用增强了,除了提供接口地址。它还承担了重要的作用。主要功能如下:

  • 监听content_script.js脚本发送的消息,然后将新数据存储到localStorage中去,最后刷新页面
  • 读取localStorage中数据,组装成环境地址接口
  • content_script.js发送消息

总结

插件的开发一定要符合 chrome 插件开发规范,脚本间的通信要一 一对应。通过crx格式安装的扩展插件的前提是插件要打包发布在 Chrome 的应用商店中,一次性收费25$

github地址,如果本文或插件对您有帮助,请给一个star。

相关推荐
我要洋人死28 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人39 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人40 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#