Next.js 中使用 @monaco-editor/react:解决 CDN 加载资源问题

背景

我们的项目框架使用 Next.js。其中有个文件管理页面需要加上文件编辑的功能,主要想对一些脚本或代码做一些简单的修改。经过对比后考虑使用为 VS Code 提供支持的代码编辑器 Monaco Editor 作为我们的 web 编辑器。

在项目中,由于历史原因我们使用的是 page router 而没有使用最新的 app router(划重点)。另外为了在 React 中使用 Monaco Editor,我们调研了两个 npm 包:react-monaco-editor@monaco-editor/react。两个包在 Github 上的 star 数差不多,都是 3k 左右。但在 npm 上 @monaco-editor/react 的下载量比 react-monaco-editor 高 4 倍还要多。

此外,react-monaco-editor 需要对 webpack 进行配置,比较麻烦。综合考虑,我们打算采用 monaco-editor/react

问题描述

@monaco-editor/react 默认情况下会从 CDN 中加载相关配置文件,并提供了方法修改加载文件的方式:

但我们并不考虑在项目运行时从 CDN 加载文件。为什么?

因为在本地开发时,已经多次遇到了 CDN 文件无法加载的情况,有可能是网络问题,也可能是其他问题。但总归是一个不稳定的因素。所以我们打算修改加载文件的方式。

如果使用了 4.4.0 以上版本的 @monaco-editor/react 的话,允许使用以下方式修改加载文件的方式。

这种方法还是很优雅的,所以打算试一下。 但当我在项目中尝试使用上图方式修改加载文件的方式时,出现了如下报错:

意思是不让使用全局 CSS,这是 Next Page Router 的限制。但是再 App Router 下不会有这个问题

解决方案

方案一

一种很朴素的解决方案是直接将需要加载的配置文件全部下载到本地,存放在项目的 public 目录下。然后设置 monaco loader 加载本地的文件:

tsx 复制代码
import Editor, { loader } from "@monaco-editor/react";

loader.config({
  paths: {
    vs: publicConfig.BASE_PATH + "monaco-assets/vs",
  },
});

但我们很快就抛弃了这个方案。原因有两点:

  1. @monaco-editor/react 需要加载的配置文件数量有上百个,全部存放于项目的代码仓库中显得太过于臃肿
  2. 难以维护。monaco 的相关文件会一直更新,我们不可能在需要更新时手动删除文件,然后再下载新的文件复制到 public 目录下

方案二

@monaco-editor/react 加载的配置文件就是 monaco-editor 这个 npm 包下的文件。那么我们只需要编写一个脚本,在本地开发和编译发布时将对应的文件拷贝到 public 目录下即可解决方案一的问题 2。然后在 .gitignore.eslinttrc.json 等文件中忽略对应的文件即可解决方案一的问题 1。

  1. 首先在 package.json 中配置安装 monaco-editor@monaco-editor/react
json 复制代码
"dependencies": {
  ...
  "@monaco-editor/react": "^4.6.0",
  ...
},
"peerDependencies": {
  "monaco-editor": "0.44.0"
},
  1. 编写脚本 copyMonacoToPublic.js 拷贝 monaco-editor 相关文件到 public/monaco-assets/vs
javascript 复制代码
const fs = require("fs-extra");
const path = require("path");

const sourcePath = path.join(__dirname, "../node_modules/monaco-editor/min/vs");
const targetPath = path.join(__dirname, "../public/monaco-assets/vs");

// Check if the source directory exists
if (!fs.existsSync(sourcePath)) {
  console.error(
    `Error: Source directory ${sourcePath} does not exist. Ensure the target package is correctly installed.`);
  process.exit(1);
}

// Ensure the target path exists, if not, create it
fs.ensureDirSync(targetPath);

// Attempt to copy
try {
  fs.copySync(sourcePath, targetPath, {
    overwrite: true,
    errorOnExist: false,
  });
  console.log(`Success: Copied from ${sourcePath} to ${targetPath}.`);
} catch (error) {
  console.error(`Error: An issue occurred during the copy process. Details: ${error.message}`);
  process.exit(1);
}

console.log(`Copied files from ${sourcePath} to ${targetPath}`);
  1. 配置 .gitignore.eslinttrc.json 等文件,忽略 public/monaco-assets/vs 目录下相关文件。配置 eslint 是因为 monaco-editor 的代码风格可能与你项目本身区别很大。

  2. 配置 package.json,使项目在本地开发和编译发布时能执行 copyMonacoToPublic.js。在本地开发时执行 npm prepareDev,打包时执行 npm build 即可将 monaco-editor 相关配置打包。

json 复制代码
"scripts": {
    "build": "node scripts/copyMonacoToPublic.js && [其他编译命令]",
    ...
    "prepareDev": "node scripts/copyMonacoToPublic.js"
},

如果需要更新 monaco-editor 相关文件,只需要修改 package.jsonmonaco-editor 版本,重新 npm installnpm prepareDev

完整代码可以查看我们的项目: SCOW 的文件编辑 PR

欢迎各位交流指正,也欢迎各位了解我们面向超算使用者和管理员的,基于Web的超算门户和管理系统 ------ SCOW。

相关推荐
Myli_ing17 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风19 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave26 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟28 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue