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。

相关推荐
web行路人8 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱0019 分钟前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
子非鱼92127 分钟前
【Ajax】跨域
javascript·ajax·cors·jsonp
超雄代码狂30 分钟前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石38 分钟前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程40 分钟前
【前端基础】CSS基础
前端·css
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
周亚鑫1 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
落魄小二1 小时前
el-table 表格索引不展示问题
javascript·vue.js·elementui
y5236481 小时前
Javascript监控元素样式变化
开发语言·javascript·ecmascript