配置

Props

/**
 * 这是 props 类型
 */
interface PlaygroundOptions {
  /**
   * 标题
   */
  title?: string

  /**
   * 文件列表
   */
  files?: File[]

  /**
   * 生命周期钩子
   */
  lifeCycle?: PlaygroundLifeCycle

  /**
   * 主题列表
   */
  themes?: PlaygroundThemes

  /**
   * import 映射
   */
  importMap?: ImportMap

  /**
   * 修改内置包的 cdn
   */
  pkgCdn?: PlaygroundPkgCdn
}

示例:

<script setup lang="ts">
import {PlaygroundOptions} from 'vue-playground'
const options: PlaygroundOptions = {
  title: '我的 demo',
  files: []
}
</script>
<template>
  <vue-playground v-bind="options" />
</template>

文件类

/**
 * 文件类
 */
class File {
  /**
   * 文件名
   */
  filename: string

  /**
   * 文件内容
   */
  code: string

  /**
   * 是否隐藏
   */
  hidden: boolean

  /**
   * 储存编译结果
   */
  compiled = {
    js: '',
    css: '',
    ssr: ''
  }

  constructor(filename: string, code = '', hidden = false) {
    this.filename = filename
    this.code = code
    this.hidden = hidden
  }
}

示例:

import {File} from 'vue-playground'
const file = new File('test.ts', 'console.log("aaa")')

生命周期钩子

interface PlaygroundLifeCycle {
  /**
   * monaco 加载之前会执这个函数
   */
  beforeLoadMonaco?: () => MaybePromise<void>

  /**
   * monaco 加载之后会执这个函数
   * @param monaco monaco 对象
   */
  afterLoadMonaco?: (monaco: Monaco) => MaybePromise<void>

  /**
   * 拦截加载 tsconfig
   * @param monaco monaco 对象
   * @param defaultTsconfig 默认 tsconfig
   * @returns 需要返回一个 tsconfig
   */
  loadTsconfig?: (monaco: Monaco, defaultTsconfig: Tsconfig) => MaybePromise<Tsconfig>

  /**
   * 拦截加载 dts 文件列表
   * @param monaco monaco 对象
   * @param defaultDtsFiles 默认 dts 文件列表
   * @returns 需要返回一个 dts 文件列表
   */
  loadTsLibs?: (monaco: Monaco, defaultTsLibs: TsLib[]) => MaybePromise<TsLib[]>

  /**
   * 在 monaco 设置完 language 之后会执行这个函数
   * @param monaco monaco 对象
   */
  afterSetLanguage?: (monaco: Monaco) => MaybePromise<void>

  /**
   * 拦截加载 monaco worker(需要在这里面自己手动加载 worker)
   * @param monaco monaco 对象
   * @param self monaco 所处的 window
   */
  loadWorkers?: (monaco: Monaco, self: Window) => MaybePromise<void>

  /**
   * 在 monaco editor 实例化之前会执行这个函数
   * @param monaco monaco 对象
   */
  beforeCreateEditor?: (monaco: Monaco) => MaybePromise<void>

  /**
   * 拦截加载 monaco editor 实例化构造参数
   * @param monaco monaco 对象
   * @param defaultOptions 默认 monaco editor 构造参数
   * @returns 需要返回 monaco editor 构造参数
   */
  loadEditorOption?: (monaco: Monaco, defaultOptions: CreateEditorOptions) => MaybePromise<CreateEditorOptions>

  /**
   * 在 monaco editor 实例化之后会执行这个函数
   * @param monaco monaco 对象
   * @param editor monaco editor 实例化对象
   */
  afterCreateEditor?: (monaco: Monaco, editor: IStandaloneCodeEditor) => MaybePromise<void>

  /**
   * 文件代码编辑后会执行这个函数
   * @param event.activeFile 当前编辑的文件对象
   * @param event.newCode 当前编辑的文件代码
   */
  onCodeChange?: (event: {activeFile: File; newCode: string}) => MaybePromise<void>

  /**
   * monaco editor 销毁之前会执行这个函数
   * @param monaco monaco 对象
   * @param editor monaco editor 实例化对象
   */
  beforeDestroyEditor?: (monaco: Monaco, editor: IStandaloneCodeEditor) => MaybePromise<void>

  /**
   * monaco editor 销毁之后会执行这个函数
   * @param monaco monaco 对象
   */
  afterDestroyEditor?: (monaco: Monaco) => MaybePromise<void>

  /**
   * 暗黑模式变更时会执行这个函数
   * @param darkMode 当前 monaco editor 是否为暗黑模式
   */
  onDarkModeChange?: (darkMode: boolean) => MaybePromise<void>
}

示例:

import {PlaygroundLifeCycle} from 'vue-playground'
import vueXrenderTypes from 'vue-xrender/dist/index.d.ts?raw'
import classMockTypes from 'class-mock/dist/index.d.ts?raw'

const lifeCycle: PlaygroundLifeCycle = {
  loadTsLibs(monaco, defaultTsLibs) {
    const tsLibs = [
      {content: `declare module 'vue-xrender' { ${vueXrenderTypes} }`},
      {content: `declare module 'class-mock' { ${classMockTypes} }`}
    ]
    return [...defaultTsLibs, ...tsLibs]
  },
  loadWorkers: async () => {
    await Promise.all([
      // load workers
      (async () => {
        const [
          {default: EditorWorker},
          {default: JsonWorker},
          {default: HtmlWorker},
          {default: TsWorker},
          {default: CssWorker}
        ] = await Promise.all([
          import('monaco-editor/esm/vs/editor/editor.worker?worker'),
          import('monaco-editor/esm/vs/language/json/json.worker?worker'),
          import('monaco-editor/esm/vs/language/html/html.worker?worker'),
          import('monaco-editor/esm/vs/language/typescript/ts.worker?worker'),
          import('monaco-editor/esm/vs/language/css/css.worker?worker')
        ])

        self.MonacoEnvironment = {
          getWorker: function (workerId, label) {
            switch (label) {
              case 'json':
                return new JsonWorker()
              case 'css':
              case 'scss':
              case 'less':
                return new CssWorker()
              case 'html':
              case 'handlebars':
              case 'razor':
                return new HtmlWorker()
              case 'typescript':
              case 'javascript':
                return new TsWorker()
              default:
                return new EditorWorker()
            }
          }
        }
      })()
    ])
  }
}

主题定制

interface PlaygroundTheme {
  /**
   * monaco editor 主题名字,内置几个
   * 'vitesse-light': 默认白色主题
   * 'vitesse-dark': 默认黑色主题
   * 'vs': vscode 白色主题
   * 'vs-dark': vscode 暗黑主题
   */
  '--editor-theme-name'?: string

  /**
   * 主题颜色
   */
  '--theme-color'?: string

  /**
   * 边框颜色
   */
  '--border-color'?: string

  /**
   * 背景颜色
   */
  '--bg-color'?: string

  /**
   * 工具栏标题颜色
   */
  '--toolbar-title-color'?: string

  /**
   * 工具栏背景颜色
   */
  '--toolbar-bg-color'?: string

  /**
   * 工具栏文字颜色
   */
  '--toolbar-text-color'?: string

  /**
   * 工具栏 icon 背景颜色
   */
  '--toolbar-icon-bg-color'?: string

  /**
   * 工具栏 icon 颜色
   */
  '--toolbar-icon-color'?: string

  /**
   * 工具栏 icon 聚焦时的颜色
   */
  '--toolbar-icon-active-color'?: string

  /**
   * 预览区域背景颜色
   */
  '--preview-bg-color'?: string

  /**
   * 预览区域文字颜色
   */
  '--preview-text-color'?: string

  /**
   * 文件管理条背景颜色
   */
  '--file-manager-bg-color'?: string

  /**
   * 文件管理条文字颜色
   */
  '--file-manager-text-color'?: string

  /**
   * 文件管理条聚焦的文件的背景颜色
   */
  '--file-manager-active-bg-color'?: string

  /**
   * 文件管理条聚焦的文件的文字颜色
   */
  '--file-manager-active-text-color'?: string

  /**
   * 文件管理条右边 import map 的背景
   */
  '--file-manager-right-float-bg'?: string

  /**
   * 编译警告信息文字颜色
   */
  '--message-warn-text-color'?: string

  /**
   * 编译警告信息背景颜色
   */
  '--message-warn-bg-color'?: string

  /**
   * 编译警告信息边框颜色
   */
  '--message-warn-border-color'?: string

  /**
   * 编译错误信息文字颜色
   */
  '--message-error-text-color'?: string

  /**
   * 编译错误信息背景颜色
   */
  '--message-error-bg-color'?: string

  /**
   * 编译错误信息边框颜色
   */
  '--message-error-border-color'?: string

  /**
   * 编译警告错误信息的 close 按钮颜色
   */
  '--message-dismiss-text-color'?: string

  /**
   * 编译警告错误信息的 close 按钮背景颜色
   */
  '--message-dismiss-bg-color'?: string
}

interface PlaygroundThemes {
  /**
   * 白色主题
   */
  light?: PlaygroundTheme

  /**
   * 黑色主题
   */
  dark?: PlaygroundTheme
}

示例:

import {PlaygroundThemes} from 'vue-playground'

const themes: PlaygroundThemes = {
  light: {
    '--theme-color': '#ff7299',
    '--editor-theme-name': 'vs'
  },
  dark: {
    '--theme-color': '#ff7299',
    '--editor-theme-name': 'vs-dark'
  }
}

包映射

interface ImportMap {
  imports: Record<string, string>
}

示例:

import {ImportMap} from 'vue-playground'

const getPkgUrl = (name: string, version = 'latest', ending = '') => `https://unpkg.com/${name}@${version}${ending}`

const importMap: ImportMap = {
  imports: {
    'vue-xrender': getPkgUrl('vue-xrender', pkg.version, '/dist/index.mjs'),
    'class-mock': getPkgUrl('class-mock', pkg.version, '/dist/index.mjs')
  }
}

内置包的 cdn 覆盖

interface PlaygroundPkgCdn {
  '@vue/runtime-dom'?: (version: string, ending: string) => string
  '@vue/compiler-sfc'?: (version: string, ending: string) => string
  'es-module-shims'?: (version: string, ending: string) => string
}

示例:

import {PlaygroundPkgCdn} from 'vue-playground'

const pkgCdn: PlaygroundPkgCdn = {
  '@vue/runtime-dom'(version) {
    return `https://unpkg.com/vue@${version}/dist/vue.esm-browser.js`
  }
}