调试和性能分析 ManifestV3 扩展 Service Worker

2024-01-11

我正在学习如何使用清单 v3 构建 chrome 扩展,我想做的是以下内容

在我的扩展background.js(服务工作者)中,我想这样做:

  • 连接到WebSocket以获取数据更新
  • 当 service-worker 唤醒时重新连接到 Websocket
  • 这些任务是从 WebSocket 获取数据更新、更新徽章文本和发送通知。

我需要执行这些任务,同时不依赖于通过弹出窗口或内容脚本打开端口。

我正在使用 Chrome 闹钟来唤醒 Service Worker

听起来很奇怪,每次 Service Worker 醒来时,我都必须重新连接,因为一旦我关闭扩展开发工具,Chrome 就会每隔 15 秒或更短时间关闭 Service Worker(这让我哭了),但这比发送 XHR 更好定期使用 Chrome 警报,这会导致更多请求发送到 API,因此重新连接到 Websocket 似乎问题不大。

我在 chrome 扩展中调试我的服务工作人员(后台脚本)时遇到了超级困难。问题是,当我打开开发工具时,服务工作线程永远不会变得不活动,而我想做的是确定软件何时醒来执行任务,超级奇怪,因为我需要打开开发工具来调试。 。

如何在未打开 devtools 的情况下调试扩展软件?

您/任何读到这篇文章的人对我想用这个扩展做什么以及调试软件的痛苦过程有什么建议/想法吗?

这是我的 background.js 代码


const extension = {
  count: 0,
  disconnected: false,
  port: {} as any,
  ws: null,
};

const fetchData = () => {
  return fetch(
    'https://api.coingecko.com/api/v3/coins/ethereum?localization=incididuntelit&tickers=false&market_data=true&community_data=true&developer_data=true&sparkline=true'
  ).then((res) => res.json());
};

// Chrome Alarms
const setupAlarms = () => {
  console.log('###ALARMS-SETUP');
  chrome.alarms.get('data-fetch', (alarm) => {
    if (!alarm) {
      chrome.alarms.create('data-fetch', { periodInMinutes: 0.1 });
    }
  });
  chrome.alarms.get('client-pinging-server', (alarm) => {
    if (!alarm) {
      chrome.alarms.create('client-pinging-server', { periodInMinutes: 0.1 });
    }
  });

  chrome.alarms.onAlarm.addListener((e) => {
    if (e.name === 'data-fetch') {
      fetchData()
        .then((res) => {
          // console.log('###ETHEREUM:', res.market_data.current_price.cad);
          chrome.action.setBadgeText({ text: `${Math.round(Math.random() * 100)}` });
        })
        .catch((error) => console.error('###ERROR', error));
    }

    if (e.name === 'client-pinging-server') {
      if (!extension.ws || !extension.ws.getInstance()) {
        console.log('\n');
        console.log('###reconnecting...', extension.ws);
        console.log('\n');
        extension.ws = WebSocketClient();
        extension.ws.connect();
      }
      if (extension.ws.getInstance()) {
        console.log('###sending-client-ping');
        extension.ws.getInstance().send(JSON.stringify({ message: 'client ping - keep alive' }));
      }
    }
  });
};

// ON INSTALL
chrome.runtime.onInstalled.addListener(async (e) => {
  const API_URL = 'ws://localhost:8080';
  chrome.storage.local.set({ apiUrl: API_URL, count: 0 });
  console.info('###Extension installed', e);

  chrome.action.setBadgeText({ text: '0' });
  chrome.action.setBadgeBackgroundColor({ color: '#FF9900' });
});

// ON SUSPEND
chrome.runtime.onSuspend.addListener(() => {
  console.log('Unloading.');
  chrome.action.setBadgeText({ text: `off` });
});

function WebSocketClient() {
  let instance = null;
  const connect = () => {
    return new Promise((resolve, reject) => {
      const ws = new WebSocket('ws://localhost:8080');

      const onOpen = () => {
        instance = ws;
        console.log('###websocket:connected', instance);
        return resolve(ws);
      };

      const onError = (event) => {
        console.log('###INIT-FAILED', event);
        ws.close(1000, 'closing due to unknown error');
        return reject('failed to connect to websocket');
      };

      const onClose = () => {
        console.log('###websocket:disconnected');
        instance = null;
        // reconnect is happening in the alarm callback
      };

      ws.onopen = onOpen;
      ws.onerror = onError;
      ws.onclose = onClose;
    });
  };

  const getInstance = () => {
    return instance;
  };

  return {
    connect,
    getInstance,
  };
}

self.addEventListener('install', async (event) => {
  console.log('====install', event);
  chrome.action.setBadgeBackgroundColor({ color: '#a6e22e' });
});

self.addEventListener('activate', async (event) => {
  console.log('====activate', event);
  chrome.action.setBadgeBackgroundColor({ color: '#FF9900' });
  extension.ws = WebSocketClient();
  extension.ws.connect();
  setupAlarms();
});

self.addEventListener('push', function (event) {
  // Keep the service worker alive until the notification is created.
  event.waitUntil(
    self.registration.showNotification('Testing PUSH API', {
      body: 'coming from push event',
    })
  );
});

由于 Devtools 可以同时附加到多个上下文,因此您可以为另一个上下文打开它,这样 SW 将成为次要的,从而能够正常卸载。

调试

  1. 打开扩展程序的任何可见页面,或者如果没有,则打开其manifest.json URL:
    chrome-extension://ID/manifest.json where ID是扩展程序的 id
  2. 打开devtools并切换到它Application选项卡,然后选择Service worker在左侧。
  3. Click start(如果显示)要启动服务工作线程,请单击后台脚本名称以在“源”面板中将其打开,设置断点等。
  4. Click stop要停止服务工作线程,可以选择单击Update在顶部,并且skip waiting中间(如果显示)以强制更新。
  5. Click start再次 - 你的断点将触发。

性能分析

  1. 打开扩展程序的任何可见页面,或者如果没有,则打开其manifest.json URL:
    chrome-extension://ID/manifest.json where ID是扩展程序的 id
  2. 打开devtools并切换到它Application选项卡,然后选择Service worker在左侧。
  3. 复制选项卡,打开开发工具,转到性能选项卡,单击“开始”或按 Ctrl-E
  4. 切换回第一个选项卡并单击start按钮(或stop首先,然后start)。在某些情况下,您可能还会看到skip waiting中间,然后单击它。
  5. 切换到第二个选项卡,等待一段时间,再次单击录制按钮或按 Ctrl-E。

Notes

当服务工作线程启动时,您可以在左侧(文件面板中)、右上角(线程面板中)、控制台工具栏(上下文选择器)的“源”面板中看到其上下文。

一开始这可能看起来很笨拙,但是一旦你尝试掌握它的诀窍,它就变得非常简单,甚至可以击败单击 chrome://extensions 页面中的“serviceworker”链接时显示的开发工具,因为这个 a) 显示了扩展的devtools 中的 localStorage/IndexedDB,b) 提供对服务工作线程生命周期/执行的控制,c) 支持软件启动的性能分析。

请注意,ManifestV3 文档中有关服务人员为扩展提供的好处的声明很大程度上被夸大或完全错误,例如在你的情况下,很明显重新启动服务工作者是不好的,所以你应该使用端口来延长软件的使用寿命 https://stackoverflow.com/a/66618269越多越好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调试和性能分析 ManifestV3 扩展 Service Worker 的相关文章

  • 将 Chrome 扩展上的权限移至可选

    我了解到 Chrome 在添加新权限时会禁用扩展程序 当我向扩展添加新功能时 我需要在permissions列表 现在我知道我应该使用optional permissions 我的问题是 如果我将网站列表从permissions to op
  • 当选项卡重新加载(chrome 扩展)时,如何运行此脚本?

    所以我想在指定 URL 中重新加载选项卡时运行脚本 它几乎可以工作 但实际上 id 不能 这是我的清单文件 manifest version 2 name Sample Extension description Sample Chrome
  • Service Worker 对 CSS 的响应时间较慢

    我们在 sw toolbox 之上编写了 Service Worker 一旦静态资源被缓存 Service Worker 就会花费更长的时间 特别是下载 css 资源 30 100 毫秒 而对于 js 资源 时间几乎为 0 CSS 加载时间
  • Chrome 扩展程序可以相互通信吗?

    我正在编写一个Chrome扩展程序 并且想要实现一个接口或api 以便我将来制作的其他扩展程序可以使用它 最终的效果可能如下 分机 B 呼叫extensionA someMethod someParameters 并向分机A发送一些数据 分
  • chrome 扩展弹出窗口和背景 ajax

    我有一个要求 background html 每 10 分钟持续更新一次 当我单击弹出窗口时 它应该触发后台立即更新并在弹出窗口中显示结果 我有使用 ajax 工作的后台更新 并且我有弹出窗口触发后台以使用 ajax 工作进行立即更新 但是
  • DOM 解析器 Chrome 扩展内存泄漏

    问题 我开发了一个扩展程序 可以拦截 Web 请求 获取 Web 请求来源的 HTML 并对其进行处理 我使用 DOMParser 来解析 HTML 并且意识到 DOMParser 正在导致大量内存泄漏问题 最终导致 chrome 扩展崩溃
  • 通过 declarativeNetRequest + extensionPath 重定向时获取原始 URL

    我需要在导航时但在用户从使用设置的规则重定向之前获取 chrome 选项卡的 urldeclarativeNetRequest 目前 用户可以使用上下文菜单添加规则 当尝试访问过滤的主机时 它将被重定向到内部扩展页面 chrome cont
  • 加密 Chrome 扩展程序?

    无论如何 要加密 Chrome 扩展程序 以免暴露源代码 您可以使用混淆器隐藏您的代码 市场上有很多可用的 像Google Closure编译器这样的工具很少 而且市场上有很多在线javascript ofuscators 你可以使用任何一
  • Google Hangouts 扩展程序如何创建面板窗口?

    The Doc http code google com chrome extensions windows html说如果你想创建一个面板窗口 你应该使用 chrome windows create type panel function
  • Google 文档 - 以编程方式将鼠标点击发送到大纲窗格中的项目

    在 Google 文档中 您可以打开大纲窗格并查看文档中的所有标题 您也可以单击标题 视图将滚动到标题 我的问题是如何使用 Chrome 扩展中的 JS 以编程方式模拟鼠标单击 以将视图滚动到所需的标题 我尝试了以下代码 但没有任何反应 u
  • 如何使用chrome扩展文件系统api?

    嗨 作为例子 我想阅读 c x txt as text 和写 有关于 chrome fileSystem 的例子吗 注意 我不想向用户询问文件的路径 已经回答于Chrome 扩展 HTML 文件系统访问 https stackoverflo
  • Chrome 扩展:以编程方式检查元素和“复制 xpath”或“复制 css 路径”[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想知道是否可以以编程方式访问一个元素 比如说我悬停在其上的当前元素 并执行相当于右键单击它 转到 检查元素 在 元素 选项卡中选择它
  • 获取css规则、chrome扩展

    我正在开发 Chrome 扩展程序 它需要访问document styleSheets cssRules 它在某些网站上运行良好 例如w3school 但其他人则不然 比如堆栈溢出 我收到错误 Failed to read the cssR
  • HTML5 网站在手机屏幕关闭时运行?

    基本上 我的问题与这个话题 https stackoverflow com questions 15465242 html5 mobile app running while phone screen is off但现在已经是 2018 年
  • 无法在 Chrome 扩展中添加侦听器

    我正在尝试创建 chromium 扩展 但无法以正确的方式将侦听器附加到按钮 必须注意的是 我对js不是很熟悉 所以mb问题在于一些误解概念或某些元素加载时机 background page kbm html 我正在使用清单 v2 因此内联
  • 手动重播由 workbox-background-sync 排队的请求

    我正在我的 PWA 应用程序中提供离线支持 我在用workbox https developers google com web tools workbox modules workbox sw为了那个原因 这是我当前的代码 const a
  • “窗口未定义”服务工作者

    我正在尝试为我的 django 项目注册一个服务人员 这是我用于注册的代码
  • 在 Google Chrome 扩展程序中播放盈利的 YouTube 歌曲。我有什么选择吗?

    我在开发 Google Chrome 扩展程序时遇到了巨大的障碍 任何盈利的 YouTube 歌曲 例如带有广告 都不会播放 此处记录了这一点 https developers google com youtube flash api re
  • 内容脚本和 web_accessible_resources iframe 之间的通信

    我有一个将 iframe 注入网页的内容脚本 内容 js var iframe document createElement iframe iframe id frame iframe style cssText position fixe
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序

随机推荐