You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展Manifest V3导入socket.io-client报错求助

Chrome扩展Manifest V3 + TypeScript导入socket.io-client报错解决

问题现象

加载已解压的扩展时,控制台抛出错误:

Uncaught TypeError: Failed to resolve module specifier "socket.io-client". Relative references must start with either "/", "./", or "../".

背景配置

manifest.json

{
  "name": "__MSG_extensionName__",
  "description": "__MSG_extensionDescription__",
  "version": "1.0",
  "manifest_version": 3,
  "default_locale": "fr",
  "host_permissions": ["*://*/*"],
  "background": {
    "service_worker": "background/index.js",
    "type": "module"
  },
  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": {
      "16": "img/default_16.png",
      "32": "img/default_32.png",
      "48": "img/default_48.png",
      "128": "img/default_128.png",
      "256": "img/default_256.png"
    }
  },
  "permissions": [
    "background",
    "tabs",
    "unlimitedStorage",
    "notifications"
  ]
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "declaration": false,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "resolveJsonModule": true,
    "allowJs": true,
    "allowUmdGlobalAccess": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "moduleResolution": "Node",
    "baseUrl": "./",
    "outDir": "dist",
    "paths": {},
    "typeRoots": ["node_modules/@types"],
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react",
    "allowSyntheticDefaultImports": true
  },
  "include": [
    "src/**/*"
  ]
}

解决方案

方案1:直接引用ES模块版socket.io-client文件

Chrome扩展的Service Worker是纯ES模块环境,不支持Node.js的裸模块解析逻辑,需改用相对路径导入:

  1. 从node_modules/socket.io-client/dist/复制socket.io.esm.min.js到源码目录(比如src/dependencies/)
  2. 修改src/dependencies/index.ts的导入语句:
export * as io from "./socket.io.esm.min.js";
  1. 在同一目录添加类型声明文件socket.io.esm.min.d.ts,确保TypeScript识别类型:
declare module "./socket.io.esm.min.js" {
  export * from "socket.io-client";
}

方案2:用打包工具将依赖打包进输出文件

使用Vite、Webpack等工具把socket.io-client打包到代码中,避免裸模块导入:

  1. 安装打包工具及对应插件(比如Vite的@crxjs/vite-plugin)
  2. 配置打包工具指向入口文件,以Vite为例:
// vite.config.ts
import { defineConfig } from 'vite';
import { crx } from '@crxjs/vite-plugin';
import manifest from './manifest.json';

export default defineConfig({
  plugins: [crx({ manifest })],
  build: {
    outDir: 'dist',
    rollupOptions: {
      input: {
        background: './src/background/index.ts',
      },
    },
  },
});
  1. 执行打包命令后,加载dist目录下的已解压扩展,此时所有依赖都被整合到输出文件中,不会触发模块解析错误。

方案3:使用Import Maps(Chrome 89+)

通过Import Maps映射裸模块到本地文件路径:

  1. 创建importmap.json文件:
{
  "imports": {
    "socket.io-client": "./dependencies/socket.io.esm.min.js"
  }
}
  1. 在Service Worker入口文件顶部添加:
import "./importmap.json" assert { type: "json" };
const importMap = await import("./importmap.json");
self.importMaps = importMap;

注意:该方案兼容性有限,部分Chrome版本可能存在Service Worker中Import Maps的支持问题,建议优先考虑前两种方案。

方案4:调整TypeScript编译配置

当前moduleResolution设为Node,会导致TypeScript按Node.js逻辑解析模块,不符合Chrome的ES模块要求:

  1. 将tsconfig.json中的moduleResolution改为Bundler(TypeScript 5.0+)或ESNext
  2. 确保outDir路径正确,编译后的文件相对引用无误
  3. 编译后检查dist/dependencies/index.js的导入语句,确认是相对路径而非裸模块名。

内容的提问来源于stack exchange,提问作者samuel beslot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:31:00