Vite+Chrome Extension Manifest v3:页内脚本import语句模块报错
问题描述
基于chrome-extension-boilerplate-react-vite项目创建扩展,在manifest中将background设置为模块:
background: { service_worker: "background.js", type: "module", },
在后台服务中通过以下方式动态注册内容脚本:
await chrome.scripting.registerContentScripts([ { id: currInpageId, matches: ["file://*/*", "http://*/*", "https://*/*"], js: [`inpage-${inpageType}.js`], runAt: "document_start", allFrames: true, world: "MAIN", }, ]);
同时在vite.config中把inpage文件配置为单独输入项:
input: { ...inpageTypes.reduce( (acc, inpageType) => ({ ...acc, [`inpage-${inpageType}`]: resolve( inpageDir, `inpage-${inpageType}.ts` ), }), {} ), },
运行扩展时出现错误:
Uncaught SyntaxError: Cannot use import statement outside a module
解决方法
错误根源是注入到MAIN world的inpage脚本被打包为ES模块,但MAIN world默认不允许在非模块脚本中使用import语句,以下两种方案可解决:
方案一:将inpage脚本打包为自执行格式(IIFE)
修改vite构建配置,给inpage相关入口单独指定输出格式为IIFE,打包后的代码会合并所有依赖为自执行函数,消除import语句:
// vite.config.js import { resolve } from 'path'; export default { // 其他原有配置... build: { rollupOptions: { input: { // 保留background、popup等其他入口 ...inpageTypes.reduce( (acc, inpageType) => ({ ...acc, [`inpage-${inpageType}`]: resolve(inpageDir, `inpage-${inpageType}.ts`), }), {} ), }, output: { entryFileNames: (chunkInfo) => { if (chunkInfo.name.startsWith('inpage-')) { return '[name].js'; // 保持inpage文件名简洁 } return 'assets/[name]-[hash].js'; // 其他文件默认命名规则 }, format: (chunkInfo) => { // 给inpage脚本指定IIFE格式 if (chunkInfo.name.startsWith('inpage-')) { return 'iife'; } return 'es'; // 其他文件保留ES模块格式 }, }, }, }, };
方案二:将inpage脚本注册为模块类型
若希望保留ES模块写法,需在注册内容脚本时添加type: "module"参数,同时确保vite打包的inpage脚本为ES模块格式:
await chrome.scripting.registerContentScripts([ { id: currInpageId, matches: ["file://*/*", "http://*/*", "https://*/*"], js: [`inpage-${inpageType}.js`], runAt: "document_start", allFrames: true, world: "MAIN", type: "module", // 新增该参数 }, ]);
注意:此方案要求目标浏览器支持ES模块,且inpage脚本的依赖需正确打包为ES模块,避免运行时解析错误。
推荐优先使用方案一,IIFE格式兼容性更强,不会受限于浏览器模块支持,也能规避MAIN world中模块带来的隔离问题。
内容的提问来源于stack exchange,提问作者Rony Fragin
相关产品推荐
相关产品推荐

