Chrome扩展:在Fetch加载的HTML中注入内容脚本问题求助
解决方案
问题1:配置Vite输出IIFE/非模块格式内容脚本
修改你的vite.config.js,通过Rollup配置指定输出格式为IIFE,并处理Svelte的动态导入打包:
import { defineConfig } from 'vite'; import { crx } from '@crxjs/vite-plugin'; import svelte from '@sveltejs/vite-plugin-svelte'; import manifest from './manifest.json'; export default defineConfig({ plugins: [ svelte(), crx({ manifest }), ], build: { rollupOptions: { // 指定content script的入口文件 input: { content: './src/content-script.js', }, output: { entryFileNames: '[name].js', format: 'iife', // 输出IIFE格式 inlineDynamicImports: true, // 将动态导入打包进单个文件,避免依赖拆分 // 若有全局依赖需映射,可在此配置globals globals: { svelte: 'Svelte' } } } } });
配置完成后,执行vite build生成的content.js即为非模块格式,可直接通过chrome.scripting.registerContentScripts注册,无需指定type: 'module'。
问题2:SPA切换时注入/重新初始化脚本
若无法解决模块格式问题,或网站通过Service Worker实现无刷新路由,可采用以下两种方案:
方案A:监听历史状态变化注入脚本
在扩展的Service Worker中注册chrome.webNavigation.onHistoryStateUpdated事件,监听目标网站的路由变化,触发脚本注入:
// 扩展的service-worker.js chrome.webNavigation.onHistoryStateUpdated.addListener( async (details) => { // 匹配目标设置页面的URL规则 if (details.url.match(/^https:\/\/目标网站域名\/settings\//)) { try { await chrome.scripting.executeScript({ target: { tabId: details.tabId }, files: ['./content.js'], // 若仍为模块格式,添加 type: 'module' // type: 'module' }); } catch (err) { console.error('注入内容脚本失败:', err); } } }, { url: [{ hostEquals: '目标网站域名', pathContains: '/settings' }] } );
需在manifest.json中添加对应权限:
{ "permissions": ["webNavigation", "scripting"], "host_permissions": ["https://目标网站域名/*"] }
方案B:监听DOM变化重新初始化组件
若内容脚本已注入,仅需在SPA切换后重新渲染按钮,可在内容脚本中使用MutationObserver监听DOM更新:
// content-script.js function initCustomButtons() { // 避免重复创建按钮 if (document.querySelector('.custom-preset-button')) return; // 创建并挂载自定义按钮 const saveBtn = document.createElement('button'); saveBtn.className = 'custom-preset-button'; saveBtn.textContent = '保存预设'; saveBtn.addEventListener('click', () => { // 保存预设逻辑 }); // 将按钮插入目标容器 const targetContainer = document.querySelector('.settings-action-bar'); targetContainer?.appendChild(saveBtn); } // 首次初始化 initCustomButtons(); // 监听DOM变化,当目标容器出现时重新初始化 const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.addedNodes.length && document.querySelector('.settings-action-bar')) { initCustomButtons(); } }); }); observer.observe(document.body, { childList: true, subtree: true });
注意:无法直接介入网页自身的Service Worker,Chrome扩展的权限模型隔离了网页与扩展的Service Worker,因此不推荐尝试此路径。
内容的提问来源于stack exchange,提问作者Kat Lim Ruiz
相关产品推荐
相关产品推荐

