Manifest V3 Chrome扩展无法导入Firebase数据库的解决方案咨询
问题说明
你在开发Manifest V3版本的Chrome扩展时,尝试在content.js中使用Firebase作为数据库,但导入Firebase时遇到了内容安全策略(CSP)限制:即使下载了本地的firebase-app.js和firebase-database.js,文件内仍包含对外部资源的导入,触发了报错:
Refused to load the script ‘https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js’ because it violates the following Content Security Policy directive: “script-src ‘self’ ‘wasm-unsafe-eval’“. Note that ‘script-src-elem’ was not explicitly set, so ‘script-src’ is used as a fallback.
以下是两种基于Vanilla JS的可行解决办法:
办法一:使用Firebase自包含UMD构建文件
Firebase的UMD(Universal Module Definition)版本是完全自包含的,不会依赖外部脚本导入,可规避CSP限制。
下载UMD包
从Firebase官网下载对应版本的UMD格式文件,比如firebase-app.umd.js、firebase-database.umd.js(确保版本统一,比如9.x系列),将其放到扩展目录的libs/文件夹下。配置manifest.json
在manifest.json中声明这些文件为可访问资源,确保content script能加载它们:"web_accessible_resources": [ { "resources": ["libs/firebase-app.umd.js", "libs/firebase-database.umd.js"], "matches": ["<all_urls>"] // 或指定你需要注入content script的特定域名 } ]在content.js中动态加载并初始化Firebase
通过动态创建script标签加载本地UMD文件,完成初始化后即可操作数据库:// content.js function loadFirebase() { return new Promise((resolve, reject) => { const scriptUrls = [ chrome.runtime.getURL('libs/firebase-app.umd.js'), chrome.runtime.getURL('libs/firebase-database.umd.js') ]; let loadedCount = 0; scriptUrls.forEach(url => { const script = document.createElement('script'); script.src = url; script.onload = () => { loadedCount++; if (loadedCount === scriptUrls.length) { // 初始化Firebase配置 const firebase = window.firebase; firebase.initializeApp({ apiKey: "你的API密钥", authDomain: "你的认证域名", databaseURL: "你的数据库URL", projectId: "你的项目ID", storageBucket: "你的存储桶", messagingSenderId: "你的消息发送ID", appId: "你的应用ID" }); resolve(firebase.database()); } }; script.onerror = reject; document.head.appendChild(script); }); }); } // 使用示例:读取数据库数据 loadFirebase().then(db => { db.ref('目标路径').once('value').then(snapshot => { console.log('获取到的数据:', snapshot.val()); }); }).catch(err => { console.error('Firebase加载失败:', err); });
办法二:通过Background Service Worker中转Firebase操作(推荐)
Manifest V3中,Background Service Worker的CSP限制更宽松,适合处理后端交互。可以将Firebase操作放在Background中,content.js通过消息通信完成交互,更符合扩展的设计规范。
在Background中配置Firebase
在background.js中加载Firebase并初始化,同时监听content script的消息:// background.js // 导入本地UMD文件 importScripts(chrome.runtime.getURL('libs/firebase-app.umd.js')); importScripts(chrome.runtime.getURL('libs/firebase-database.umd.js')); // 初始化Firebase const firebase = window.firebase; firebase.initializeApp({ /* 你的Firebase配置 */ }); const db = firebase.database(); // 监听content script的消息请求 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { switch(request.action) { case 'getDbData': db.ref(request.path).once('value') .then(snap => sendResponse({ success: true, data: snap.val() })) .catch(err => sendResponse({ success: false, error: err.message })); return true; // 保持端口开放,等待异步响应 case 'setDbData': db.ref(request.path).set(request.data) .then(() => sendResponse({ success: true })) .catch(err => sendResponse({ success: false, error: err.message })); return true; default: sendResponse({ success: false, error: '未知操作' }); } });更新manifest.json
配置Background Service Worker、CSP和可访问资源:"background": { "service_worker": "background.js" }, "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'none';", "sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';" }, "web_accessible_resources": [ { "resources": ["libs/firebase-app.umd.js", "libs/firebase-database.umd.js"], "matches": ["<all_urls>"] } ]在content.js中通过消息通信操作数据库
// content.js // 请求获取数据 function getDbData(path) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ action: 'getDbData', path }, res => { res.success ? resolve(res.data) : reject(new Error(res.error)); }); }); } // 请求设置数据 function setDbData(path, data) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ action: 'setDbData', path, data }, res => { res.success ? resolve() : reject(new Error(res.error)); }); }); } // 使用示例 getDbData('目标路径').then(data => { console.log('获取到的数据:', data); }).catch(err => { console.error('获取数据失败:', err); });
内容的提问来源于stack exchange,提问作者Raj Chandra

