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。

相关推荐
世俗ˊ23 分钟前
CSS入门笔记
前端·css·笔记
子非鱼92124 分钟前
【前端】ES6:Set与Map
前端·javascript·es6
6230_28 分钟前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人37 分钟前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js
加勒比海涛1 小时前
HTML 揭秘:HTML 编码快速入门
前端·html
啥子花道1 小时前
Vue3.4 中 v-model 双向数据绑定新玩法详解
前端·javascript·vue.js
麒麟而非淇淋1 小时前
AJAX 入门 day3
前端·javascript·ajax
茶茶只知道学习1 小时前
通过鼠标移动来调整两个盒子的宽度(响应式)
前端·javascript·css
清汤饺子1 小时前
实践指南之网页转PDF
前端·javascript·react.js
蒟蒻的贤1 小时前
Web APIs 第二天
开发语言·前端·javascript