Express + SQLite backend with Monaco editor frontend. Supports HTML/CSS/JS, TypeScript, React (JSX/TSX), Vue SFC, and Svelte with live preview, console output, save/fork/share. Includes CSS preprocessors (SCSS, Less), framework-specific compilation (Babel, TypeScript, Svelte compiler), and CDN-loaded runtime libraries for preview rendering.
55 lines
1.5 KiB
JavaScript
55 lines
1.5 KiB
JavaScript
let sassLoaded = false;
|
|
let lessLoaded = false;
|
|
|
|
function loadScript(src) {
|
|
return new Promise((resolve, reject) => {
|
|
if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; }
|
|
const savedDefine = window.define;
|
|
window.define = undefined;
|
|
const s = document.createElement('script');
|
|
s.src = src;
|
|
s.onload = () => { window.define = savedDefine; resolve(); };
|
|
s.onerror = () => { window.define = savedDefine; reject(new Error(`Failed to load ${src}`)); };
|
|
document.head.appendChild(s);
|
|
});
|
|
}
|
|
|
|
async function ensureSass() {
|
|
if (sassLoaded) return;
|
|
await loadScript('https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.11.1/sass.sync.min.js');
|
|
sassLoaded = true;
|
|
}
|
|
|
|
async function ensureLess() {
|
|
if (lessLoaded) return;
|
|
window.less = { env: 'production' };
|
|
await loadScript('https://cdnjs.cloudflare.com/ajax/libs/less.js/4.2.0/less.min.js');
|
|
lessLoaded = true;
|
|
}
|
|
|
|
export async function compileCss(code, type) {
|
|
if (type === 'css') return code;
|
|
|
|
if (type === 'scss') {
|
|
await ensureSass();
|
|
return new Promise((resolve, reject) => {
|
|
Sass.compile(code, (result) => {
|
|
if (result.status === 0) resolve(result.text);
|
|
else reject(new Error(result.formatted || result.message));
|
|
});
|
|
});
|
|
}
|
|
|
|
if (type === 'less') {
|
|
await ensureLess();
|
|
try {
|
|
const result = await less.render(code);
|
|
return result.css;
|
|
} catch (e) {
|
|
throw new Error(e.message);
|
|
}
|
|
}
|
|
|
|
return code;
|
|
}
|