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

React与Express共享代码的ES版本适配问题求助

解决Monorepo中共享包同时支持React(ESNext)和Express(CommonJS)的方案

核心思路是让共享包同时编译输出ES模块(ESM)和CommonJS(CJS)两种格式,让前端和后端各自读取对应格式的文件,彻底解决模块系统冲突问题。

1. 重构共享包的TypeScript配置

在shared目录下拆分出基础配置+两个环境专属配置,分别对应ESM和CJS:

shared/tsconfig.base.json(公共基础配置)

抽离所有环境通用的编译选项:

{
  "compilerOptions": {
    "baseUrl": "../",
    "rootDir": "./src",
    "composite": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationDir": "./dist/types"
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules", "./dist/**/*"]
}

shared/tsconfig.esm.json(给React前端用)

继承基础配置,指定ES模块编译规则:

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "module": "ESNext",
    "target": "ESNext",
    "outDir": "./dist/esm",
    "moduleResolution": "NodeNext"
  }
}

shared/tsconfig.cjs.json(给Express后端用)

继承基础配置,指定CommonJS编译规则:

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2016",
    "outDir": "./dist/cjs",
    "moduleResolution": "Node",
    "esModuleInterop": true
  }
}

2. 修改共享包的package.json

配置多模块入口,让Node和打包工具自动匹配对应格式:

{
  "name": "@your-project/shared",
  "version": "1.0.0",
  "main": "./dist/cjs/index.js", // CommonJS入口
  "module": "./dist/esm/index.js", // ES模块入口
  "types": "./dist/types/index.d.ts", // 统一类型定义入口
  "scripts": {
    "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json" // 同时编译两种格式
  }
}

3. 调整前端(React/Vite)的配置

更新frontend/tsconfig.json,指向共享包的ESM配置:

{
  "compilerOptions": {
    // 保留原有配置
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "NodeNext",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": false
  },
  "include": ["src"],
  "references": [
    { "path": "./tsconfig.node.json" },
    { "path": "../shared/tsconfig.esm.json" }
  ]
}

可选:在Vite配置中添加共享包优化,提升开发体验:

// frontend/vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  optimizeDeps: {
    include: ['@your-project/shared']
  }
})

4. 调整后端(Express)的配置

更新backend/tsconfig.json,指向共享包的CJS配置:

{
  "compilerOptions": {
    // 保留原有配置
    "target": "es2016",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "./dist",
    "esModuleInterop": true
  },
  "references": [
    { "path": "../shared/tsconfig.cjs.json" }
  ]
}

5. 验证解决方案

  1. 进入shared目录执行npm run build,确认生成dist/cjs、dist/esm、dist/types三个目录
  2. 启动前端项目,验证共享包模块导入正常,无导出错误
  3. 启动后端项目,验证共享包模块导入正常,无SyntaxError: Unexpected token 'export'错误

关键注意事项

  • 共享包源码统一放在shared/src目录,避免编译后文件路径混乱
  • 开启declaration: true保证前后端都能获取完整的TypeScript类型提示
  • 前端esModuleInterop设为false时,确保共享包导出符合ES模块规范(如export default或export const)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:45:41