fix: monaco-editor offline

This commit is contained in:
tao.chen
2026-08-20 20:11:06 +08:00
parent d3259ba452
commit 6a8bdf6b16
4 changed files with 29 additions and 15 deletions
+4
View File
@@ -5,3 +5,7 @@
# React Router
/.react-router/
/build/
# monaco-editor 预构建 min/vs(由 scripts/copy-monaco.mjs 在 postinstall 时
# 从 node_modules/monaco-editor/min/vs 复制生成,不要提交)
/public/monaco/vs/
+20 -14
View File
@@ -1,21 +1,27 @@
// Monaco 本地加载配置
//
// @monaco-editor/react 默认从 jsDelivr CDN 异步加载 monaco-editor 的核心
// 脚本与 Worker(见 @monaco-editor/loader 默认 paths:
// https://cdn.jsdelivr.net/npm/monaco-editor@.../min/vs)。
// 离线 / 内网环境下 CDN 不可达时,<Editor> 初始化失败,控制台报
// "Monaco initialization: error",编辑器永远停在 loading 状态
// (Python 编辑与预览都依赖 <Editor>,因此全部打不开)。
// 离线 / 内网环境下,@monaco-editor/react 默认从 jsDelivr CDN 加载 monaco
// (见 @monaco-editor/loader 默认 paths: jsdelivr 的 monaco-editor min/vs),
// CDN 不可达时控制台报 "Monaco initialization: error",<Editor> 永远停在
// 内部 loading 状态(Python 编辑与预览都依赖 <Editor>,全部打不开)。
//
// 这里把本地 node_modules 中的 monaco-editor 交给 Vite 打包,并在任何
// <Editor> 挂载前通过 loader.config 注入,彻底断开 CDN 依赖。
// 必须在 root.tsx 顶部 import,保证先于编辑器渲染执行。
// 早期尝试:import * as monaco from "monaco-editor" 让 Vite 把 monaco ESM 打
// 进 client bundle + loader.config({ monaco })。但 monaco ESM 内部用
// new URL('./xxx/webWorkerBootstrap.js?esm', import.meta.url)
// 这种深嵌套相对路径 bootstrap worker,Vite 8 / Rolldown 不会把它们改写成
// 产物的 hash asset URL,运行时 fallback 成 blob URL,浏览器解析相对
// specifier 直接抛 "Failed to resolve module specifier ...webWorkerBootstrap.js"。
// 此外手动 import '...editor.worker?worker' 也会被 Rolldown 报
// "failed to resolve import"。这是 Vite/Rolldown 与 monaco ESM 的兼容坑。
//
// 注意:不配置独立 worker(monaco 会自动 fallback 到主线程,离线可用,
// 仅有一条无害的 console warning)。Vite 8 / Rolldown 对 `?worker` 后缀
// 解析不兼容,强行配置反而会打挂构建。
// 最终方案:用 monaco 自带的预构建 `min/vs`(IIFE/AMD 分布),通过
// loader.config({ paths }) 自托管到 /monaco/vs。预构建版自带 worker
// 加载(路径相对于 vs 根),完全不依赖 bundler 的 ?worker 行为,行为与
// 原 CDN 模式一一对应,自包含离线。min/vs 由 postinstall 脚本从
// node_modules/monaco-editor/min/vs 复制到 frontend/public/monaco/vs。
//
// 必须用 .client 后缀:SPA 构建的 server 预渲染阶段不会执行该模块。
import { loader } from "@monaco-editor/react";
import * as monaco from "monaco-editor";
loader.config({ monaco });
loader.config({ paths: { vs: "/monaco/vs" } });
+5 -1
View File
@@ -6,7 +6,11 @@
"build": "react-router build",
"dev": "react-router dev",
"start": "react-router-serve ./build/server/index.js",
"typecheck": "react-router typegen && tsc"
"typecheck": "react-router typegen && tsc",
"copy:monaco": "node scripts/copy-monaco.mjs",
"postinstall": "node scripts/copy-monaco.mjs",
"predev": "node scripts/copy-monaco.mjs",
"prebuild": "node scripts/copy-monaco.mjs"
},
"dependencies": {
"@monaco-editor/react": "^4.7.0",
View File