Manifest V3 Chrome扩展脚本注入报错:无法加载文件求助
问题描述
我正在开发Manifest V3版本的Chrome扩展,因禁止加载外部资源,已将html2canvas.min.js复制到本地libs文件夹中。需在内容脚本get-div-image.js中使用该库访问DOM,通过popup.js调用chrome.scripting.executeScript注入html2canvas.js和get-div-image.js时,触发以下错误:
Unchecked runtime.lastError: Could not load file: 'html2canvas.js'.
Unchecked runtime.lastError: Could not load file: 'get-div-image.js'.
修改文件路径为['libs/html2canvas.js']和['contents/get-div-image.js']后错误消失,但脚本似乎未注入成功,且该路径写法与content_scripts中的路径写法不一致,想知道问题出在哪里。
我的manifest.json配置:
{ "manifest_version": 3, "name": "Images Grabber v2", "version": "1.0", "description": "Monitors the screen and takes screenshots.", "permissions": ["activeTab", "storage", "tabs", "background", "scripting"], "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'self';" }, "background": { "service_worker": "background.js" }, "action": { "default_popup": "popup.html" }, "host_permissions": ["<all_urls>"], "content_scripts": [ { "matches": ["<all_urls>"], "js": ["contents/get-data-urls.js", "libs/html2canvas.js", "contents/get-div-image.js"] } ], "icons": { "128": "icons/icon.png" } }
文件夹结构:
extension/ │ ├── manifest.json │ ├── contents/ │ ├── get-data-urls.js │ └── get-div-image.js │ └── libs/ └── html2canvas.js ...
问题原因与解决方法
1. 路径写法差异的本质
content_scripts中的路径本身就是相对于扩展根目录的完整路径,而chrome.scripting.executeScript的files参数要求必须传入这种完整相对路径——你修改后的写法才是正确的。之前的错误是因为只写了文件名(比如html2canvas.js),Chrome会默认在当前执行上下文的目录中查找,而非扩展根目录,所以找不到文件。
2. 脚本看似未注入的核心原因
(1) 重复注入的冲突
你的manifest.json已经在content_scripts里声明了get-div-image.js和html2canvas.js,它们会自动注入到所有匹配的页面中。此时再通过executeScript注入同名脚本,会导致重复执行,出现逻辑覆盖或无响应的情况,看起来像没注入成功。
解决方式:
- 如果是需要按需触发脚本逻辑,建议移除
content_scripts中的这两个脚本,只保留必要的常驻脚本; - 或者在
get-div-image.js中添加触发判断,比如监听来自popup的消息,而非脚本加载后自动执行。
(2) 注入时机与上下文错误
确保popup.js中的注入代码逻辑正确,必须先获取当前活跃标签页的ID,且标签页处于可注入状态(排除chrome://等限制页面)。示例正确写法:
// popup.js 中的注入代码 document.getElementById('trigger-btn').addEventListener('click', async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); try { await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['libs/html2canvas.js', 'contents/get-div-image.js'] }); console.log('脚本注入成功'); } catch (err) { console.error('注入失败:', err); } });
(3) 第三方库的CSP兼容性问题
部分版本的html2canvas依赖eval执行代码,而网页自身的CSP或扩展的CSP可能限制了unsafe-eval,导致库无法正常运行,看起来像脚本未生效。
解决方式:
- 尝试替换为不需要
eval的html2canvas版本; - 若必须保留,可在扩展的CSP配置中添加
'unsafe-eval'(仅必要时使用):
"content_security_policy": { "extension_pages": "script-src 'self' 'unsafe-eval'; object-src 'self';" }
3. 最佳实践建议
- 按需注入:不要同时在
content_scripts和executeScript中注入相同脚本,避免逻辑冲突。常驻逻辑用content_scripts,按需触发的逻辑用executeScript注入单独的触发脚本; - 通信规范:如果
get-div-image.js需要和popup交互,使用chrome.runtime.sendMessage和chrome.runtime.onMessage进行消息传递,不依赖注入时机耦合逻辑。
内容的提问来源于stack exchange,提问作者Edoardo Balducci

