shared worker 不支持 import/export 是因浏览器以普通脚本(非模块)方式加载,导致 es 模块语法无效;可行方案包括 importscripts、构建为 iife、或现代浏览器中在 onconnect 内使用动态 import。

Shared Worker 脚本默认不支持 import/export 语法,直接写 ES Module 会报 Unexpected token 'export' 或 Cannot use import statement outside a module —— 这不是你代码写错了,而是浏览器加载 Shared Worker 的机制根本没把脚本当作模块执行。
为什么 SharedWorker 不认 import/export?
SharedWorker 构造时(new SharedWorker('worker.js'))要求传入一个**普通脚本 URL**,浏览器会以 <script></script> 方式加载它(即 type="text/javascript"),而非 type="module"。这意味着:
- ES 模块语法(
import/export)天然被禁用 -
import.meta.url、动态import()等模块专属特性不可用 - 即使你用 Vite/Webpack 打包成 ESM 输出,只要加载方式不是模块化,就无效
三种真正可行的落地方案
别在 worker.js 里硬写 export,换思路:
-
方案一:改用 importScripts(最兼容)
把依赖提前打包成单个 IIFE 脚本,或拆成多个传统 JS 文件,在worker.js开头用importScripts('lib.js', 'utils.js')加载。所有代码运行在同一个全局作用域(self),变量自然共享。 -
方案二:用构建工具转译为 IIFE(推荐工程化项目)
例如 Vite 配置build.lib模式,入口设为worker.js,输出格式选iife;Webpack 则配output.libraryTarget: 'var'。生成的 bundle 是自执行函数,可直接被importScripts或作为 worker 入口加载。 -
方案三:动态 import + top-level await(仅现代浏览器)
Chrome 120+ / Firefox 115+ / Safari 17.4+ 支持在 SharedWorker 主脚本中使用import()(需确保服务端返回Content-Type: application/javascript)。但注意:await import()必须放在self.onconnect内部,不能在顶层直接 await,否则会阻塞连接建立。
避坑关键细节
- 不要尝试用
type="module"加载 SharedWorker —— 浏览器不支持该属性,new SharedWorker('worker.js', { type: 'module' })是非法 API,会直接抛错 - Vite 中若启用了
worker.plugins,请确认它最终输出的是普通脚本,而非type="module"的 HTML 标签引用 - Webpack 5+ 若启用
experiments.topLevelAwait: true,仍无法让 SharedWorker 解析顶层 await,因加载机制未升级为模块模式 - Safari 对
import()在 SharedWorker 中的支持较晚(iOS 17.4+),生产环境必须做typeof import !== 'undefined'检测并 fallback
本质上,SharedWorker 的模块化困境源于规范滞后——它诞生于 ES6 模块标准化之前,至今未原生支持模块加载语义。务实做法是:接受它“类 script”的本质,用构建链路兜底,而非强求运行时模块化。










