Day6的一个tips:Electron在Monorepo React 渲染错误排查:从 Hook 崩溃到根治

简介: 记录 Monorepo 中 Web 与 Electron 端 React "Invalid hook call" 的完整排查过程,涵盖版本错配、实例混用、CSP 拦截等根因分析与修复方案。

渲染层报错复盘(Web + Electron)

1. 背景

在完成 Zustand Store 迁移后,webdesktop(electron renderer) 先后出现 React 渲染错误,主要表现为:

  • Invalid hook call
  • Cannot read properties of null (reading 'useRef' / 'useState')
  • Incompatible React versions

这些错误会导致页面无法渲染,属于高优先级阻塞问题。


2. 问题现象

2.1 Web 端

关键报错:

  • Invalid hook call. Hooks can only be called inside of the body of a function component.
  • 触发点:<BrowserRouter>main.tsx:9
  • 连带报错:Cannot read properties of null (reading 'useRef')

2.2 Web 端二次报错(修复过程中的中间态)

关键报错:

  • Incompatible React versions
  • react: 19.1.0
  • react-dom: 19.2.5

说明渲染时拿到的 reactreact-dom 不是同一版本。

2.3 Electron 渲染进程

关键报错:

  • Invalid hook call
  • Cannot read properties of null (reading 'useState')
  • 触发组件:Versions.tsx

3. 根因分析

根因 A:Monorepo 下 React 实例混用

在 workspace 场景下,不同 app 的 reactreact-dom 解析路径可能不同,导致:

  • 业务代码使用了一份 react
  • 渲染器(react-dom / router)使用了另一份 react

从而触发 Invalid hook call

根因 B:一次错误修复带来的版本错配

为修复 Web 端 Invalid hook call,曾尝试在 Vite 中把 react alias 到 workspace 根。随后发现根目录实际版本为:

  • root react = 19.1.0
  • root react-dom = 19.2.5

这会直接触发 Incompatible React versions

根因 C:Electron 渲染端依赖归类导致运行时解析不稳定

apps/desktop 初始将 reactreact-dom 放在 devDependencies,配合 monorepo hoist 后,渲染进程更容易解析到非预期位置的包。


4. 排查路径(实际执行)

  1. 定位异常入口:

    • apps/web/src/main.tsx<BrowserRouter>
    • apps/desktop/src/renderer/src/components/Versions.tsx
  2. 检查版本与依赖树:

    • pnpm --filter @aitodos/web why react
    • pnpm --filter @aitodos/store why react
    • pnpm --filter desktop why react
  3. 检查运行时解析路径(关键):

    • require.resolve('react')
    • require.resolve('react-dom')
    • 分别在 apps/webapps/adminapps/desktop 目录执行
  4. 检查本地安装版本:

    • node_modules/react/package.json
    • node_modules/react-dom/package.json

5. 修复动作(按时间顺序)

5.1 Web/Admin 首轮修复

文件:

  • apps/web/vite.config.ts
  • apps/admin/vite.config.ts

动作:

  • 增加 resolve.dedupe: ['react', 'react-dom']

作用:

  • 降低同一应用加载多份 React 的风险。

5.2 修复过程中的错误动作(已回滚)

动作:

  • 在 Web/Admin Vite 里把 react/react-dom alias 到 workspace 根

结果:

  • 命中了 root react=19.1.0react-dom=19.2.5 的版本错配
  • 出现 Incompatible React versions

处理:

  • 回滚该 alias,仅保留 dedupe

5.3 Electron Renderer 修复

文件:

  • apps/desktop/electron.vite.config.ts
  • apps/desktop/package.json

动作 1(解析一致化):

  • renderer.resolve 中保留 dedupe: ['react', 'react-dom']
  • 显式增加:react: resolve('node_modules/react')

动作 2(依赖归类修正):

  • reactreact-domdevDependencies 移到 dependencies

目的:

  • 保证 Electron 渲染进程运行时拿到同一套 React 运行时依赖。

5.4 依赖重装与重启

执行:

pnpm install --filter desktop
pnpm --filter desktop dev

结果:

  • 安装成功(exit code 0)
  • Electron renderer dev server 启动成功

6. 最终状态

  • Web 端渲染恢复正常
  • Electron 渲染进程可启动并进入页面
  • Invalid hook call 链路已完成定向修复

7. 可复用修复模板

当再次出现 Invalid hook call 时,建议按以下顺序:

  1. 先查“版本一致性”

    • reactreact-dom 必须完全同版本
  2. 再查“解析路径一致性”

    • 比较 require.resolve('react')require.resolve('react-dom')
  3. 在 bundler 中启用去重

    • resolve.dedupe: ['react', 'react-dom']
  4. 对 Electron/运行时 app,确保 React 是运行时依赖

    • 放在 dependencies 而非仅 devDependencies
  5. 每次改完配置必须重启进程

    • 停掉旧的 dev 进程
    • 重新启动并强刷页面

8. 备注

  • apps/desktoppnpm.onlyBuiltDependencies 配置警告属于配置位置提示,不是本次渲染错误根因。
  • 若后续仍偶发异常,优先加运行时日志打印 React 解析路径和版本再定位。

9. 补充:Electron 复用 Web 后样式丢失与 CSP 报错

9.1 问题现象 A:页面“有结构、无样式”

现象:

  • Electron 页面能渲染文本和结构,但 Tailwind 视觉样式几乎全部失效。
  • 页面看起来像纯 HTML 默认样式。

关联报错(阶段性):

  • [plugin:vite:import-analysis] Failed to resolve import "@web/index.css"

根因:

  1. main.tsx 直接从 @web/index.css 引入时,CSS alias 在 Electron + Vite 场景下解析不稳定。
  2. apps/desktop 原模板样式文件未显式扫描 apps/web/src,导致 Tailwind 未生成 Web 页面实际使用的 utility class。

修复:

  • apps/desktop/src/renderer/src/main.tsx
    • 使用 desktop 本地样式入口:import './assets/main.css'
  • apps/desktop/src/renderer/src/assets/main.css
    • 保留 @import "tailwindcss";
    • 增加扫描源:
      • @source "../../../../../web/src/**/*.{ts,tsx}";
      • @source "../**/*.{ts,tsx}";
    • 移除 Electron 模板页遗留样式,保留通用基础规则(html/body/#root)。

验证:

  • pnpm --filter desktop build 通过。
  • 构建后的 renderer CSS 体积明显增大(说明 Tailwind utility 已成功生成)。

9.2 问题现象 B:CSP 拒绝 unsafe-eval

关键报错:

  • Uncaught EvalError: Evaluating a string as JavaScript violates CSP ... 'unsafe-eval'
  • 触发点:packages/shared/src/storage.ts

根因:

  • 为了条件加载 Taro/RN 存储实现,代码中使用了 new Function(...) 进行动态导入;
  • Electron 渲染进程默认 CSP 不允许 unsafe-eval,因此直接报错。

修复:

  • packages/shared/src/storage.ts
    • new Function(...) 改为 CSP 安全写法:
      • import(/* @vite-ignore */ modulePath)

验证:

  • pnpm --filter @aitodos/shared type-check 通过。
  • pnpm --filter desktop typecheck 通过。
  • Electron 运行时不再出现 unsafe-eval 相关异常。

9.3 结论

  • 复用 Web 到 Electron 时,样式链路要以 desktop 为入口统一管理;
  • Tailwind v4 需要在 desktop 的 CSS 入口显式声明 @source 扫描 Web 源码;
  • 渲染层共享代码必须避免 eval/new Function,否则容易被 CSP 拦截。
相关文章
|
3月前
|
人工智能 安全 网络虚拟化
为什么总显示请求超时或者一直运行中无反应,卸载重装了好几次,把各种安全软件和vpn等都关了也不行
该问题表现为AI工具频繁超时、卡在“生成中”无响应,强制停止无效甚至导致程序卡死。已尝试重装、关闭安全软件及VPN仍无效,疑似网络连接异常、服务端故障或本地环境兼容性问题。
|
设计模式 前端开发 测试技术
WPF开发之Prism详解【内附源码】
WPF开发之Prism详解【内附源码】
1299 0
|
4月前
|
机器学习/深度学习 人工智能 开发者
AI 编程时代来了!Karpathy 出品「避坑指南」一夜爆火
AI编程时代来临,Karpathy指出四大通病:错误假设、代码臃肿、误改无关代码、缺乏验证标准。开发者Forrest Chang据此推出开源《CLAUDE.md》指南,通过“思考优先、简单优先、精准改动、目标驱动”四原则,让Claude Code更可靠、高效、可控。(239字)
796 1
|
安全 网络安全 数据安全/隐私保护
HTTPS 请求中的证书验证详解(Python版)
HTTPS 请求中的证书验证详解(Python版)
1183 0
|
3月前
|
人工智能 NoSQL API
从 0 到后端闭环: Day2 跑通 Prisma 7 + NestJS + Redis 的实战记录
记录我在 AiTodos Day2 打通后端闭环的过程:完成 Prisma 7 迁移、NestJS + Fastify 接入,以及 AI 资讯/Todo/统计接口和 Redis 日缓存落地。
|
3月前
|
人工智能 缓存 前端开发
从 0 到 1:AI Todos 项目 Day1 实战——用 pnpm + Turbo 搭建可迭代的 Monorepo 基线
记录AI待办(AiTodos)Monorepo项目的首日基础工程搭建全过程,涵盖pnpm工作区配置、目录骨架初始化、Turbo任务编排、TypeScript统一配置、Vite/Fastify应用初始化、跨包共享(shared/api-sdk/store)及标准化脚本建设,完成可运行、可检查、可扩展的现代化前端工程基线。
|
2月前
|
人工智能 前端开发 JavaScript
Vibe Coding 时代,为什么 Tailwind + Shadcn/ui 正在成为现代前端的默认答案
这篇文章想讨论的,不只是 `Tailwind CSS + shadcn/ui` 为什么流行,而是为什么它们会在 Vibe Coding 时代越来越像现代前端的默认组合。相比传统组件库,这套方案把样式、结构与组件源码更直接地暴露在项目本身中,既提升了开发者的控制权,也降低了 AI 理解、修改和协作的成本。
|
3月前
|
人工智能 缓存 前端开发
Day4-5:Web 双端适配与 Admin 系统全栈落地实录
本文档整合了 Day 4 与 Day 5 的开发进展,核心涵盖 Web 端响应式 UI 复现、云端资讯 API 接入,以及 Admin 管理系统的架构设计与模块化开发步骤,打通了从用户体验到后台管理的完整链路。
|
机器学习/深度学习 PyTorch 算法框架/工具
深度学习之格式转换笔记(一):模型文件pt转onnx转tensorrt格式实操成功
关于如何将深度学习模型从PyTorch的.pt格式转换为ONNX格式,然后再转换为TensorRT格式的实操指南。
3631 1
深度学习之格式转换笔记(一):模型文件pt转onnx转tensorrt格式实操成功
|
Java Python
什么是Python中的循环引用(Circular Reference)?如何避免循环引用导致的内存泄漏?
什么是Python中的循环引用(Circular Reference)?如何避免循环引用导致的内存泄漏?
913 0

热门文章

最新文章