Resolve "Monaco Playground Typing and Rollup Bundles"

This commit is contained in:
2025-07-13 06:17:53 +00:00
committed by Jim Hamill
parent 50fb4020b6
commit aa3967a060
14 changed files with 572 additions and 225 deletions
@@ -0,0 +1,140 @@
<template>
<div class="code-editor">
<div ref="editorContainer" class="code-editor" />
<slot />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import loader, { Monaco } from '@monaco-editor/loader';
import { ImportedLib } from '../utils/useXOCashLibs';
export type CodeEditorProps = {
// List of .d.ts files to import into the editor.
libs?: Record<string, ImportedLib>;
// Color scheme of the editor
isDark?: boolean;
}
const props = withDefaults(defineProps<CodeEditorProps>(), {
libs: () => ({}),
isDark: false,
});
const code = defineModel<string>();
const monacoInstance = ref<Monaco | null>(null);
const editorContainer = ref<HTMLElement | null>(null);
const emit = defineEmits<{
(e: 'execute'): void;
}>();
watch(() => props.libs, async () => {
updateEditorTypes();
});
function updateEditorTypes() {
monacoInstance.value?.languages.typescript.typescriptDefaults.setExtraLibs(
Object.entries(props.libs).map(([name, content]) => {
// Dont add the library if it is empty
if (!content) return null;
const moduleContent = `declare module "${name}" { ${content.libTypes} }`;
return { uri: `inmemory://model/${name}.d.ts`, content: moduleContent };
}).filter((lib) => lib !== null)
);
}
onMounted(() => {
// Load Monaco Editor
loader.init().then((monaco) => {
monacoInstance.value = monaco;
// Throw if our editor container is not found
if (!editorContainer.value) {
throw new Error('Editor container not found');
}
// Disable unnecessary validations
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
diagnosticCodesToIgnore: [ 1375 ] // Ignore "top-level await" error
});
// Add our typescript compiler options
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ESNext,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.ESNext,
noEmit: true,
lib: ["esnext", "dom"],
checkJs: true,
isolatedModules: true,
allowSyntheticDefaultImports: true
});
// Enable eager mode. Tries to move LSP on worker thread
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
// Add extra libs to the editor
updateEditorTypes();
// Define a theme to change the background color of the editor
monaco.editor.defineTheme('xo-sandbox', {
base: props.isDark ? 'vs-dark' : 'vs',
inherit: true,
rules: [],
colors: {
"editor.background": props.isDark ? '#161618' : '#f5f5f5'
}
});
// Create our editor into the container
const editor = monaco.editor.create(editorContainer.value, {
value: code.value,
language: 'typescript',
theme: 'xo-sandbox',
automaticLayout: true,
scrollBeyondLastLine: false,
suggest: {
showClasses: true,
showFunctions: true,
showVariables: true,
showModules: true,
showProperties: true,
showWords: true,
},
});
// Add control + S keybinding to execute code
editor.addAction({
id: `execute-code`,
label: 'Execute Code',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
run: () => {
emit('execute')
}
});
// Update the code value when the editor content changes
editor.onDidChangeModelContent(() => {
code.value = editor.getValue();
});
});
})
</script>
<style scoped>
.code-editor {
height: 100%;
width: 100%;
}
</style>