背景
我们的项目框架使用 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",
},
});
但我们很快就抛弃了这个方案。原因有两点:
@monaco-editor/react
需要加载的配置文件数量有上百个,全部存放于项目的代码仓库中显得太过于臃肿- 难以维护。
monaco
的相关文件会一直更新,我们不可能在需要更新时手动删除文件,然后再下载新的文件复制到public
目录下
方案二
@monaco-editor/react
加载的配置文件就是 monaco-editor
这个 npm 包下的文件。那么我们只需要编写一个脚本,在本地开发和编译发布时将对应的文件拷贝到 public
目录下即可解决方案一的问题 2。然后在 .gitignore
和 .eslinttrc.json
等文件中忽略对应的文件即可解决方案一的问题 1。
- 首先在
package.json
中配置安装monaco-editor
和@monaco-editor/react
。
json
"dependencies": {
...
"@monaco-editor/react": "^4.6.0",
...
},
"peerDependencies": {
"monaco-editor": "0.44.0"
},
- 编写脚本
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}`);
-
配置
.gitignore
和.eslinttrc.json
等文件,忽略public/monaco-assets/vs
目录下相关文件。配置eslint
是因为monaco-editor
的代码风格可能与你项目本身区别很大。 -
配置
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.json
中 monaco-editor
版本,重新 npm install
和 npm prepareDev
。
欢迎各位交流指正,也欢迎各位了解我们面向超算使用者和管理员的,基于Web的超算门户和管理系统 ------ SCOW。