vue3 vite打包monaco-editor出现很多不需要的语言文件,打包文件很混乱。monaco-editor打包优化 | 青训营笔记

3,395 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第2天

优化前后对比

这是全量导入Monaco-editor的情况

image.png

这是只导入editor核心的情况

image.png

可以看到全量导入的时候左边很多一小块一小块的都是一些并没有用到的语言

在Monaco-editor github官方“Integrating the ESM version of the Monaco Editor

这篇使用说明中全部都是使用的全量导入。并且也没有说可以使用按需导入。

例如在Vite中使用

image.png

按需导入

直到我发现了这句话

// or import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';

// if shipping only a subset of the features & languages is desired

那就按照他的来试一下

// import * as monaco from 'monaco-editor';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
// if shipping only a subset of the features & languages is desired

monaco.editor.create(document.getElementById('container'), {
	value: 'console.log("Hello, world")',
	language: 'javascript'
});

注意:这样只会导入编辑器核心,就算导入了对应语言的worker也不能进行语法着色,也没有右键,命名面板等功能

所有语言、特性都需要手动启用

image.png

按需启用语言

这里我的需求是启用特定某几个语言和全部的特性

我们可以直接去node_modules下,找到这个json文件

node_modules/monaco-editor/esm/metadata.js

比如我需要启用json、js和ts

image.png

就需要像这样导入

  • entry字段直接import进来就好了
  • worker字段需要导入进来并且注册到getWorker中
/**
 * Using Vite
 * @link https://github.com/microsoft/monaco-editor/blob/main/docs/integrate-esm.md#using-vite
 */
import * as Monaco from 'monaco-editor/esm/vs/editor/editor.api'
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import './use-features'

// 语言
// json
import 'monaco-editor/esm/vs/language/json/monaco.contribution'
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
// js
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
// ts
import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'
import TSWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'

self.MonacoEnvironment = {
  getWorker(_: string, label: string) {
    if (label === 'json') {
      return new JsonWorker()
    }
    if (label === 'typescript' || label === 'javascript') {
      return new TSWorker()
    }
    return new EditorWorker()
  },
}
export default Monaco

启用所有特性

这里如果一个个手写import的话怎么可能。有两百多行。我们写一个函数让他自己生成就好了

image.png

import metadata from 'monaco-editor/esm/metadata'
const prefix = 'monaco-editor/esm/'
const autoImport = metadata.features.map((feat) => {
  let entry =
    Object.prototype.toString.call(feat.entry) === '[object String]'
      ? [feat.entry as string]
      : (feat.entry as string[])
  entry = entry.map((val) => `import '${prefix}${val}'`)
  return `// ${feat.label}
${entry.join('\n')}`
})
console.log(autoImport.join('\n'))

效果如下,直接复制粘贴进代码就成了

image.png

手动分包

这里是默认情况下没有对monaco进行手动分包的打包结果

image.png

monaco-editor和业务代码和在了一个chunk里面,但是我们并不需要页面落地就完成monaco的加载

所以这里需要手动分包一下,让monaco这个庞然巨物自己分一个chunk

在vite.config.ts中

export default defineConfig({
    build: {
      rollupOptions: {
        output: {
          manualChunks: (e) => {
            if (e.includes('/node_modules/monaco-editor/')) return 'monaco'
            else if (...)
              return 'vendor'
          },
        },
      },
    },
})

这下终于齐活了

image.png

worker分包

但是一看日志。为啥worker还是单独的包

image.png

于是去vite官网找了一圈

默认情况下,worker 脚本将在生产构建中编译成单独的 chunk。

image.png

不过这么大的语法解析器内联为base64肯定不行。

所以我们还是得对worker再进行一次分包

worker的可以配置的选项和build的配置一样的。

只不过位置换一个地方而已,位于worker.rollupOptions

Worker 选项 | Vite 官方中文文档 (vitejs.dev)

打包时候给了我一个报错

[vite:worker] Invalid value "iife" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.

image.png

但是我并没有找到解决方案。我还不清楚vite中怎么对worker进行分包