起因
因为工作需要,我需要和我的学员在钉钉上面分享代码。
当有人给我分享了一段代码后,我得把这段代码拷贝下来,然后在本地创建一个 HTML 文件跑起来,才能看到效果。相当麻烦。
我在想怎么样能够一键分享代码呢?
于是我花了一天时间在网站上增加了一个代码分享的功能。
长下面这样:
然后学员只需要发送给我一个链接,我就可以直接在浏览器里面打开,并且立马可以调试和预览效果。
一切似乎很顺利,但是过了几天,学员告诉我他打开这个页面的时候,编辑器加载非常久。
编辑器是使用 Monaco Editor 开发的。很久之前我也碰到过 Monaco Editor 加载非常慢的情况,原因就是 CDN 的锅,不使用 CDN 就可以了。
在 React 中怎么使用 Monaco Editor?
通常有两种方案,一是使用官方包自己折腾。monaco-editor。这种做法必须使用编译插件,比较麻烦,而且 API 也不好用,不推荐这种做法。
二是使用 monaco 官方维护的 @monaco-editor/react,用法非常简单。
为什么用到了 CDN?
nonaco-editor/react 并没有将 monaco-editor 作为 peer 依赖,也没有把 monaco-editor 打包到源代码里。它采用的做法是通过 CDN 去加载打包好的 monaco-editor。
nonaco-editor/react 提供了 loader 方法,我们可以传递一个 config 方法,来指定 monaco 对象的来源。
它有一段默认的配置,我们可以对他进行修改。
const config = { paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs', }, } export default config;
这段配置就是从 jsdelivr 上面加载 CDN。
如何避免 CDN?
避免 CDN 非常简单。
把 monaco-editor 安装到本地,并且配置 loader 的 config 就可以了。
import * as monaco from "monaco-editor"; import { loader } from "@monaco-editor/react"; loader.config({ monaco });
服务端渲染?monaco 该怎么办?
以上方法在没有服务端渲染的情况下可以用。
但是 monaco-editor 不支持服务端渲染。
比如我使用 blitz 框架,它底层是 nextjs,属于服务端框架。这时也有办法,可以动态加载。
import dynamic from "next/dynamic"; const MonacoEditor = dynamic(import("react-monaco-editor"), { ssr: false });
在很早之前这样用是没问题的,我也这么用过,但是现在不行了。
Nextjs 不支持第三方包中导入 css,该怎么办?
monaco 导入了第三方 css。
但是 Nextjs 不支持第三方包中导入 css,官方文档有说明: CSS Imported by a Dependency。
也有很多人提了 issues,讨论比较多的是:issues 19936,维护者针对这个 issues 开了一个 RFC: Global CSS Imports #27953。但是目前仍然没有结论。
在这个问题彻底解决之前,可以使用 next-global-css。
但是必须把 nextjs 的编译工具从 SWC 切换到 webpack。
最新版本的 Nextjs 现在还有办法这么玩吗?
切换到 webpack 很简单,只需要添加一行配置就可以了。
const config = { webpack: (config, options) => { config.plugins.push(newMonacoWebpackPlugin()) returnconfig } }
由于 monaco 必须使用 monaco-editor-webpack-plugin 这个 webpack 插件。
而这个插件必须运行在 webpack 4 版本中。原来有个 webpack5 配置项,把它设置为 false 就可以使用。
但是最新版 nextjs 不支持 webpack4 了,只支持 webpack5。
所以这个方法也不能用了。
怎么样把 jsdelivr 上面的代码下载下来?
于是我又想到,能不能把 CDN 代码下载到本地来用呢?
MonacoEditor 在 jsdelivr 上的地址:cdn.jsdelivr.net/npm/monaco-…。
可是我发现它没有办法一键下载。恰巧 Monaco 的文件实在太多了,上百个,我逐一复制不知道要到什么时候。
于是我又准备搞一个工具,输入一个 url,可以一键下载该目录下所有的文件。
思路也很简单,通过 url 获取 DOM,解析 DOM,如果是文件夹则递归执行。正在我写了一半的时候,突然想到 unpkg 上面不也有 MonacoEditor 编译后的代码吗?
我又找到了 unpkg 上面 MonacoEditor 的代码地址:unpkg.com/browse/mona…。
但是 unpkg 也没有一键下载功能,我想肯定有人想过如何一键下载 unpkg 上面的文件吧?
果不其然,我在 github 上面找到了一个库:github.com/TMaize/go-u…。
当我把它下载下来,但是运行不起来的时候......
聪明反被聪明误
正当我准备回去继续写 jsdelivr 一键下载工具的时候,突然想到,我只要把 monoco editor 装到本地,node_module 里面不就有源代码了吗?
于是,我花了大概 1 分钟,搞定了。
现在 monaco editor 基本可以做到秒加载。
从一个灵感,到实现 MVP 版本非常快,但是在 MVP 版本增强用户体验的时候,就开始变复杂了。一个很简单的优化,却花了半天时间去折腾,最后发现走弯路了,正确的解法只需要 1 分钟而已。
其实我从一开始就应该想到的,只是因为自己对技术过于自信,导致错过了最佳方式,反而绕进了一个无底洞。
从这一点也可以看出,思考远比行动重要的多。