Skip to content

Commit 3d218cc

Browse files
committed
feat(vuepress-plugin-sandbox,vue-playground): init vuepress-plugin-sandbox, add life cycle supports
1 parent ad261f8 commit 3d218cc

File tree

30 files changed

+578
-95
lines changed

30 files changed

+578
-95
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {defineClientAppEnhance} from '@vuepress/client'
2+
import {configLoadSandbox} from 'vuepress-plugin-sandbox/client'
3+
4+
export default defineClientAppEnhance(() => {
5+
configLoadSandbox(preOptions => {
6+
return {
7+
...preOptions,
8+
lifeCycle: {
9+
loadWorkers: async () => {
10+
await Promise.all([
11+
// load workers
12+
(async () => {
13+
const [
14+
{default: EditorWorker},
15+
{default: JsonWorker},
16+
{default: HtmlWorker},
17+
{default: TsWorker},
18+
{default: CssWorker}
19+
] = await Promise.all([
20+
import('monaco-editor/esm/vs/editor/editor.worker?worker'),
21+
import('monaco-editor/esm/vs/language/json/json.worker?worker'),
22+
import('monaco-editor/esm/vs/language/html/html.worker?worker'),
23+
import('monaco-editor/esm/vs/language/typescript/ts.worker?worker'),
24+
import('monaco-editor/esm/vs/language/css/css.worker?worker')
25+
])
26+
27+
self.MonacoEnvironment = {
28+
getWorker: function (workerId, label) {
29+
switch (label) {
30+
case 'json':
31+
return new JsonWorker()
32+
case 'css':
33+
case 'scss':
34+
case 'less':
35+
return new CssWorker()
36+
case 'html':
37+
case 'handlebars':
38+
case 'razor':
39+
return new HtmlWorker()
40+
case 'typescript':
41+
case 'javascript':
42+
return new TsWorker()
43+
default:
44+
return new EditorWorker()
45+
}
46+
}
47+
}
48+
})()
49+
])
50+
}
51+
}
52+
}
53+
}, self)
54+
})

packages/doc-site/.vuepress/plugins/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {ShikiPluginOptions} from '@vuepress/plugin-shiki'
55
import {path} from '@vuepress/utils'
66
import {PluginConfig} from 'vuepress'
77
import {isProd} from '../utils/common'
8-
import {demoPlugin} from './vuepress-plugin-demo'
8+
// import {demoPlugin} from './vuepress-plugin-demo'
99

1010
const pathResolve = (..._path: string[]) => path.resolve(__dirname, ..._path)
1111

@@ -81,7 +81,8 @@ const vuepressPlugins: PluginConfig[] = [
8181
componentsDir: pathResolve('../components')
8282
}
8383
],
84-
demoPlugin()
84+
// demoPlugin()
85+
['vuepress-plugin-sandbox', {}]
8586
]
8687

8788
if (isProd) {

packages/doc-site/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"path-browserify": "^1.0.1",
2727
"sucrase": "^3.21.0",
2828
"theme-vitesse": "^0.4.9",
29-
"vue-router": "^4.0.15"
29+
"vue-router": "^4.0.15",
30+
"vuepress-plugin-sandbox": "workspace:*"
3031
},
3132
"devDependencies": {
3233
"@vuepress/bundler-vite": "2.0.0-beta.39",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './playground'
2+
export * from './core/store'

packages/vue-playground/src/playground/components/editor.vue

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,55 @@ export default defineComponent({
55
</script>
66
<script setup lang="ts">
77
/* eslint-disable @typescript-eslint/no-explicit-any */
8-
import {ref, defineComponent, inject, computed} from 'vue'
9-
import {debounce} from '../../core'
8+
import {ref, defineComponent, inject, computed, PropType, toRefs} from 'vue'
9+
import {debounce, File} from '../../core'
1010
import {STORE_INJECT_KEY} from '../constants'
1111
import {useMonaco} from '../hooks/useMonaco'
12+
import {EditorExpose, PlaygroundLifeCycle} from '../utils/types-helper'
1213
import FileManageBar from './file-manage-bar.vue'
1314
import Message from './message.vue'
1415
16+
const props = defineProps({
17+
lifeCycle: {
18+
type: Object as PropType<PlaygroundLifeCycle>
19+
}
20+
})
21+
1522
interface Emits {
1623
(e: 'change', value: string): void
1724
}
1825
1926
const emit = defineEmits<Emits>()
2027
28+
const {lifeCycle} = toRefs(props)
2129
const store = inject(STORE_INJECT_KEY)!
2230
2331
const editorEl = ref<HTMLElement>()
2432
const files = computed(() => Object.values(store.state.files))
2533
const activeFile = computed(() => store.state.activeFile)
2634
27-
const {getEditor, onChange, isDark, toggleDark} = useMonaco(editorEl, {
35+
const {getEditor, onChange, isDark, toggleDark, disposeEditor} = useMonaco(editorEl, {
36+
lifeCycle,
2837
files,
2938
activeFile
3039
})
3140
3241
const handleChange = debounce(({newCode, activeFile}: {newCode: string; activeFile: File}) => {
3342
store.state.activeFile.code = newCode
43+
lifeCycle?.value?.onCodeChange?.({
44+
newCode,
45+
activeFile
46+
})
3447
emit('change', newCode)
3548
}, 250)
3649
50+
defineExpose({
51+
getEditor,
52+
isDark,
53+
toggleDark,
54+
disposeEditor
55+
} as EditorExpose)
56+
3757
onChange(handleChange)
3858
</script>
3959

packages/vue-playground/src/playground/components/preview.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from 'vue'
2020
import {Preview, PreviewProxy} from '../../core/'
2121
import {CLEAR_CONSOLE_INJECT_KEY, STORE_INJECT_KEY} from '../constants'
22+
import {PreviewExpose} from '../utils/types-helper'
2223
2324
const store = inject(STORE_INJECT_KEY)!
2425
const clearConsole = computed(() => unref(inject(CLEAR_CONSOLE_INJECT_KEY)))
@@ -85,6 +86,11 @@ watch(
8586
onUnmounted(() => {
8687
proxy.destroy()
8788
})
89+
90+
defineExpose({
91+
container,
92+
sandboxIframe: preview.sandboxEl
93+
} as PreviewExpose)
8894
</script>
8995

9096
<template>

packages/vue-playground/src/playground/constants.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import {MaybeRef} from '@vueuse/core'
22
import {InjectionKey} from 'vue'
33
import {Store} from '../core'
44

5-
export const FILE_BASE_URL = 'file:///root/'
6-
export const PROJECT_ID_PREFIX = 'project'
7-
export const DEFAULT_FILE_NAME = 'comp.vue'
8-
export const IMPORT_JSON_NAME = 'import-map.json'
5+
export const PLAYGROUND_COMPONENT_NAME = 'Playground' as const
6+
export const FILE_BASE_URL = 'file:///root/' as const
7+
export const PROJECT_ID_PREFIX = 'project' as const
8+
export const DEFAULT_FILE_NAME = 'comp.vue' as const
9+
export const IMPORT_JSON_NAME = 'import-map.json' as const
910
export const STORE_INJECT_KEY = '__store__' as unknown as InjectionKey<Store>
1011
export const CLEAR_CONSOLE_INJECT_KEY = '__clear_console__' as unknown as InjectionKey<MaybeRef<boolean>>
1112
export const SHOW_IMPORT_MAP_INJECT_KEY = '__show_import_map__' as unknown as InjectionKey<MaybeRef<boolean>>

packages/vue-playground/src/playground/hooks/useMonaco.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {generateProjectId, mustBeRef} from './../utils/common'
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
22
/* eslint-disable @typescript-eslint/no-empty-function */
33
import {ref, Ref, unref, watch} from 'vue'
44
import {tryOnScopeDispose, MaybeRef, createEventHook, tryOnUnmounted, EventHookOn} from '@vueuse/core'
@@ -9,10 +9,11 @@ import {setupMonaco} from '../monaco'
99
import {File} from '../../core'
1010
import {useMonacoModels} from './useMonacoModels'
1111
import {toggleDark, isDark} from './index'
12-
13-
import {MonacoEditor} from '../utils/types-helper'
12+
import {CreateEditorOptions, MonacoEditor, PlaygroundLifeCycle} from '../utils/types-helper'
13+
import {generateProjectId, mustBeRef} from '../utils/common'
1414

1515
export interface UseMonacoOptions {
16+
lifeCycle?: MaybeRef<PlaygroundLifeCycle | undefined>
1617
activeFile: MaybeRef<File>
1718
files: MaybeRef<File[]>
1819
}
@@ -35,9 +36,15 @@ export function useMonaco(target: Ref<HTMLElement | undefined>, options: UseMona
3536
const getEditor = () => editor
3637

3738
const init = async () => {
38-
const {monaco} = await setupMonaco()
39+
const lifeCycle = unref(options.lifeCycle)
40+
41+
await lifeCycle?.beforeLoadMonaco?.()
42+
43+
const {monaco} = await setupMonaco(lifeCycle)
3944
if (!monaco) return
4045

46+
await lifeCycle?.afterLoadMonaco?.(monaco)
47+
4148
monaco.editor.defineTheme('vitesse-dark', darkTheme as unknown as MonacoEditor.IStandaloneThemeData)
4249
monaco.editor.defineTheme('vitesse-light', lightTheme as unknown as MonacoEditor.IStandaloneThemeData)
4350
const {getModels, modelUpdateId} = useMonacoModels({
@@ -51,11 +58,13 @@ export function useMonaco(target: Ref<HTMLElement | undefined>, options: UseMona
5158

5259
watch(
5360
target,
54-
() => {
61+
async () => {
5562
const el = unref(target)
5663
if (!el) return
5764

58-
editor = monaco.editor.create(el, {
65+
await lifeCycle?.beforeCreateEditor?.(monaco)
66+
67+
const defaultEditorOptions: CreateEditorOptions = {
5968
tabSize: 2,
6069
insertSpaces: true,
6170
autoClosingQuotes: 'always',
@@ -67,12 +76,25 @@ export function useMonaco(target: Ref<HTMLElement | undefined>, options: UseMona
6776
minimap: {
6877
enabled: true
6978
}
70-
}) as MonacoEditor.IStandaloneCodeEditor
79+
}
80+
81+
const editorOptions =
82+
(await lifeCycle?.loadEditorOption?.(monaco, defaultEditorOptions)) || defaultEditorOptions
83+
84+
editor = monaco.editor.create(el, editorOptions) as MonacoEditor.IStandaloneCodeEditor
85+
86+
const _destroyEditor = addEditor(editor)
87+
disposeEditor.value = async () => {
88+
await lifeCycle?.beforeDestroyEditor?.(monaco, editor as any)
89+
_destroyEditor()
90+
await lifeCycle?.afterDestroyEditor?.(monaco)
91+
}
7192

72-
disposeEditor.value = addEditor(editor)
7393
isSetup.value = true
7494
editorUpdateId.value++
7595

96+
await lifeCycle?.afterCreateEditor?.(monaco, editor as any)
97+
7698
// editor.value.onDidFocusEditorText(() => {
7799
// editor.value?.updateOptions({
78100
// scrollbar: {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export {default as Playground} from './playground.vue'
22
export * from './constants'
3+
export * from './utils/types-helper'

packages/vue-playground/src/playground/monaco/language.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import {FILE_BASE_URL} from '../constants'
3-
import {Monaco} from '../utils/types-helper'
3+
import {Monaco, PlaygroundLifeCycle, Tsconfig, TsLib} from '../utils/types-helper'
44

5-
interface TsLib {
6-
content: string
7-
filePath?: string
8-
}
9-
10-
type Tsconfig = Parameters<typeof monaco.languages.typescript.typescriptDefaults.setCompilerOptions>[0]
11-
12-
export async function setLanguage(monaco: Monaco) {
13-
const tsconfig: Tsconfig = {
5+
export async function setLanguage(monaco: Monaco, lifeCycle?: PlaygroundLifeCycle) {
6+
const defaultTsconfig: Tsconfig = {
147
...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(),
158
target: monaco.languages.typescript.ScriptTarget.ESNext,
169
baseUrl: FILE_BASE_URL,
@@ -37,6 +30,8 @@ export async function setLanguage(monaco: Monaco) {
3730
typeRoots: ['node_modules/@types']
3831
}
3932

33+
const tsconfig = (await lifeCycle?.loadTsconfig?.(monaco, defaultTsconfig)) || defaultTsconfig
34+
4035
// ts
4136
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(tsconfig)
4237

@@ -71,7 +66,7 @@ export async function setLanguage(monaco: Monaco) {
7166
import('./runtime.d.ts?raw')
7267
])
7368

74-
const tsLibs: TsLib[] = [
69+
const defaultTsLibs: TsLib[] = [
7570
{content: runtimeTypes},
7671
{content: `declare module '@vue/shared' { ${vueSharedTypes} }`},
7772
{content: `declare module '@vue/runtime-core' { ${vueRuntimeCoreTypes} }`},
@@ -80,6 +75,8 @@ export async function setLanguage(monaco: Monaco) {
8075
{content: `declare module 'vue' { ${vueTypes} }`}
8176
]
8277

78+
const tsLibs = (await lifeCycle?.loadTsLibs?.(monaco, defaultTsLibs)) || defaultTsLibs
79+
8380
tsLibs.forEach(lib => {
8481
monaco.languages.typescript.typescriptDefaults.addExtraLib(lib.content, lib.filePath)
8582
})

0 commit comments

Comments
 (0)