diff --git a/src/livecodes/compiler/compile.worker.ts b/src/livecodes/compiler/compile.worker.ts
index 6dc87c0e64..34180d33f4 100644
--- a/src/livecodes/compiler/compile.worker.ts
+++ b/src/livecodes/compiler/compile.worker.ts
@@ -1,8 +1,15 @@
import type TS from 'typescript';
import { getCompilerOptions } from '../editor/ts-compiler-options';
import { languages, processors } from '../languages';
-import type { CompileOptions, Compilers, Config, EditorLibrary, Language } from '../models';
-import { doOnce, objectFilter } from '../utils/utils';
+import type {
+ CompileOptions,
+ CompileResult,
+ Compilers,
+ Config,
+ EditorLibrary,
+ Language,
+} from '../models';
+import { doOnce, getErrorMessage, objectFilter } from '../utils/utils';
import { codeMirrorBaseUrl, comlinkBaseUrl, vendorsBaseUrl } from '../vendors';
import { getAllCompilers } from './get-all-compilers';
import type { CompilerMessage, CompilerMessageEvent, LanguageOrProcessor } from './models';
@@ -98,13 +105,16 @@ const compile = async (
throw new Error('Failed to load compiler for: ' + language);
}
- let value;
+ let value: string | CompileResult = '';
try {
value = await compiler(content, { config, language, baseUrl, options });
- } catch (err) {
+ } catch (err: unknown) {
// eslint-disable-next-line no-console
console.error('Failed compiling: ' + language, err);
- value = content;
+ value = {
+ code: '',
+ info: { errors: [getErrorMessage(err)] },
+ };
}
return value || '';
};
diff --git a/src/livecodes/core.ts b/src/livecodes/core.ts
index 7bcc96f616..84cd3fb019 100644
--- a/src/livecodes/core.ts
+++ b/src/livecodes/core.ts
@@ -996,7 +996,7 @@ const getResultPage = async ({
},
};
- const compileResults = await Promise.all([
+ const [styleCompileResult, testsCompileResult] = await Promise.all([
compiler.compile(styleContent, styleLanguage, config, {
html: `${compiledMarkup}
`,
@@ -1008,8 +1008,7 @@ const getResultPage = async ({
: compiler.compile(testsContent, testsLanguage, config, {})
: Promise.resolve(getCompileResult(getCache().tests?.compiled || '')),
]);
-
- const [compiledStyle, compiledTests] = compileResults.map((result) => {
+ const [compiledStyle, compiledTests] = [styleCompileResult, testsCompileResult].map((result) => {
const { code, info } = getCompileResult(result);
compileInfo = {
...compileInfo,
@@ -1027,10 +1026,12 @@ const getResultPage = async ({
markup: {
...contentConfig.markup,
compiled: compiledMarkup,
+ modified: compiledMarkup,
},
style: {
...contentConfig.style,
compiled: compiledStyle,
+ modified: compiledStyle,
},
script: {
...contentConfig.script,
@@ -1045,6 +1046,7 @@ const getResultPage = async ({
compiled: compiledTests,
},
};
+ compiledCode.script.modified = compiledCode.script.compiled;
if (scriptType != null && scriptType !== 'module') {
singleFile = true;
@@ -1063,6 +1065,14 @@ const getResultPage = async ({
const styleOnlyUpdate = sourceEditor === 'style' && !compileInfo.cssModules;
+ const logError = (language: Language, errors: string[] = []) => {
+ errors.forEach((err) => toolsPane?.console?.error(`[${getLanguageTitle(language)}] ${err}`));
+ };
+ logError(markupLanguage, markupCompileResult.info?.errors);
+ logError(styleLanguage, styleCompileResult.info?.errors);
+ logError(scriptLanguage, scriptCompileResult.info?.errors);
+ logError(testsLanguage, getCompileResult(testsCompileResult).info?.errors);
+
if (singleFile) {
setCache({
...getCache(),
@@ -1124,17 +1134,9 @@ const flushResult = () => {
wat: ';; loading',
};
- updateCache(
- 'markup',
- compiledLanguages.markup,
- loadingComments[compiledLanguages.markup] || 'html',
- );
- updateCache('style', compiledLanguages.style, loadingComments[compiledLanguages.style] || 'css');
- updateCache(
- 'script',
- compiledLanguages.script,
- loadingComments[compiledLanguages.script] || 'javascript',
- );
+ updateCache('markup', compiledLanguages.markup, loadingComments[compiledLanguages.markup] ?? '');
+ updateCache('style', compiledLanguages.style, loadingComments[compiledLanguages.style] ?? '');
+ updateCache('script', compiledLanguages.script, loadingComments[compiledLanguages.script] ?? '');
setCache({
...getCache(),
tests: {
diff --git a/src/livecodes/languages/gleam/lang-gleam-compiler.ts b/src/livecodes/languages/gleam/lang-gleam-compiler.ts
index 0169309262..6210085474 100644
--- a/src/livecodes/languages/gleam/lang-gleam-compiler.ts
+++ b/src/livecodes/languages/gleam/lang-gleam-compiler.ts
@@ -2,6 +2,7 @@
/* eslint-disable max-classes-per-file */
import type { CompilerFunction } from '../../models';
+import { getErrorMessage } from '../../utils/utils';
import { gleamBaseUrl } from '../../vendors';
import { getLanguageCustomSettings } from '../utils';
import { modules, type Modules } from './gleam-modules';
@@ -193,7 +194,10 @@ import { modules, type Modules } from './gleam-modules';
} catch (error) {
// eslint-disable-next-line no-console
console.warn(error);
- return '';
+ return {
+ code: '',
+ info: { errors: [getErrorMessage(error)] },
+ };
} finally {
project.delete();
}
diff --git a/src/livecodes/languages/svelte/lang-svelte-compiler.ts b/src/livecodes/languages/svelte/lang-svelte-compiler.ts
index ae2f44200c..8151f59fa9 100644
--- a/src/livecodes/languages/svelte/lang-svelte-compiler.ts
+++ b/src/livecodes/languages/svelte/lang-svelte-compiler.ts
@@ -2,6 +2,7 @@ import { compileAllBlocks } from '../../compiler/compile-blocks';
import { createImportMap, replaceSFCImports } from '../../compiler/import-map';
import { getCompileResult } from '../../compiler/utils';
import type { CompilerFunction, Config, Language } from '../../models';
+import { getErrorMessage } from '../../utils/utils';
import { getLanguageByAlias, getLanguageCustomSettings } from '../utils';
(self as any).createSvelteCompiler = (): CompilerFunction => {
@@ -9,6 +10,7 @@ import { getLanguageByAlias, getLanguageCustomSettings } from '../utils';
const SECONDARY_FILE = '__LiveCodes_Component__.svelte';
let importedContent = '';
let imports: Record = {};
+ let errors: string[] = [];
const compileSvelteSFC = async (
code: string,
@@ -42,21 +44,32 @@ import { getLanguageByAlias, getLanguageCustomSettings } from '../utils';
});
const customSettings = getLanguageCustomSettings('svelte', config);
- const { js } = (window as any).svelte.compile(processedCode, {
- css: 'injected',
- filename,
- ...customSettings,
- });
-
if (filename === MAIN_FILE || filename === SECONDARY_FILE) {
imports = createImportMap(importedContent, config);
+ errors = [];
+ }
+
+ let js: { code: string };
+ try {
+ const result = (window as any).svelte.compile(processedCode, {
+ css: 'injected',
+ filename,
+ ...customSettings,
+ });
+ js = result.js;
+ } catch (err) {
+ errors.push(getErrorMessage(err));
+ return {
+ code: '',
+ info: { errors },
+ };
}
const compiledCode = filename === MAIN_FILE ? getMountCode(js.code) : js.code;
return {
code:
language === 'svelte-app' ? `` : compiledCode,
- info: { importedContent, imports },
+ info: { importedContent, imports, errors },
};
};
diff --git a/src/livecodes/languages/vue/lang-vue-compiler.ts b/src/livecodes/languages/vue/lang-vue-compiler.ts
index a7c5f8e5c0..212947a217 100644
--- a/src/livecodes/languages/vue/lang-vue-compiler.ts
+++ b/src/livecodes/languages/vue/lang-vue-compiler.ts
@@ -3,7 +3,7 @@ import { compileInCompiler } from '../../compiler/compile-in-compiler';
import { createImportMap, replaceSFCImports } from '../../compiler/import-map';
import type { LanguageOrProcessor } from '../../compiler/models';
import type { CompilerFunction, Config } from '../../models';
-import { getRandomString, replaceAsync } from '../../utils/utils';
+import { getErrorMessage, getRandomString, replaceAsync } from '../../utils/utils';
import { getLanguageByAlias } from '../utils';
// based on:
@@ -363,35 +363,48 @@ import { getLanguageByAlias } from '../utils';
}
return async (code, { config, language }) => {
- const isMainFile = config.markup.language !== 'vue-app' || language === 'vue-app';
- const filename = isMainFile ? MAIN_FILE : SECONDARY_FILE;
- const result = await compileVueSFC(code, { config, filename });
+ try {
+ const isMainFile = config.markup.language !== 'vue-app' || language === 'vue-app';
+ const filename = isMainFile ? MAIN_FILE : SECONDARY_FILE;
+ const result = await compileVueSFC(code, { config, filename });
- if (result) {
- const { css, js } = result;
+ if (result) {
+ const { css, js } = result;
- const injectCSS = !css.trim()
- ? ''
- : `
+ const injectCSS = !css.trim()
+ ? ''
+ : `
document.head.insertBefore(
Object.assign(document.createElement('style'), { textContent: ${JSON.stringify(css)} }),
document.head.getElementsByTagName('style')[0]
);
`;
- const compiledCode = js + injectCSS;
+ const compiledCode = js + injectCSS;
+
+ return {
+ code:
+ language === 'vue-app'
+ ? ``
+ : compiledCode,
+ info: { importedContent, imports: createImportMap(importedContent, config), errors },
+ };
+ }
+
+ if (errors.length) {
+ // eslint-disable-next-line no-console
+ console.error(...errors);
+ }
+ const empty = `export default () => {}`;
return {
- code:
- language === 'vue-app' ? `` : compiledCode,
- info: { importedContent, imports: createImportMap(importedContent, config) },
+ code: language === 'vue-app' ? `` : empty,
+ info: { errors },
+ };
+ } catch (err) {
+ return {
+ code: '',
+ info: { errors: [...errors, getErrorMessage(err)] },
};
}
-
- if (errors.length) {
- // eslint-disable-next-line no-console
- console.error(...errors);
- }
-
- return '';
};
};
diff --git a/src/livecodes/utils/utils.ts b/src/livecodes/utils/utils.ts
index 518bca4a05..9dc8480396 100644
--- a/src/livecodes/utils/utils.ts
+++ b/src/livecodes/utils/utils.ts
@@ -643,6 +643,15 @@ export const compareObjects = /* @__PURE__ */ (
return diff;
};
+export const getErrorMessage = /* @__PURE__ */ (err: unknown): string => {
+ if (err == null) return '';
+ if (err instanceof Error) return err.message;
+ if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') {
+ return err.message;
+ }
+ return String(err);
+};
+
export const predefinedValues = {
APP_VERSION: process.env.VERSION || '',
SDK_VERSION: process.env.SDK_VERSION || '',
diff --git a/src/sdk/models.ts b/src/sdk/models.ts
index e6bd21a015..50695a9bdd 100644
--- a/src/sdk/models.ts
+++ b/src/sdk/models.ts
@@ -1291,6 +1291,7 @@ export interface CompileInfo {
modifiedHTML?: string;
importedContent?: string;
imports?: Record;
+ errors?: string[];
}
export interface CompileResult {