From c4a400e292ae5c2df7b763e85fb8dfa136140aae Mon Sep 17 00:00:00 2001 From: Qb Date: Sat, 25 Jun 2022 08:09:00 +0200 Subject: [PATCH] Fallback when Monaco load fails (#1278) --- renderer/src/modules/dommanager.js | 3 +- renderer/src/modules/editor.js | 26 +++++++--- renderer/src/styles/builtins/customcss.css | 10 +++- renderer/src/ui/customcss/editor.jsx | 56 +++++++++++++++------- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/renderer/src/modules/dommanager.js b/renderer/src/modules/dommanager.js index ff3ba711..3f69d407 100644 --- a/renderer/src/modules/dommanager.js +++ b/renderer/src/modules/dommanager.js @@ -91,10 +91,11 @@ export default class DOMManager { static injectScript(id, url) { id = this.escapeID(id); - return new Promise(resolve => { + return new Promise((resolve, reject) => { const script = this.getElement(`#${id}`, this.bdScripts) || this.createElement("script", {id}); script.src = url; script.onload = resolve; + script.onerror = reject; this.bdScripts.append(script); }); } diff --git a/renderer/src/modules/editor.js b/renderer/src/modules/editor.js index 3fb2ca7b..02a26980 100644 --- a/renderer/src/modules/editor.js +++ b/renderer/src/modules/editor.js @@ -1,3 +1,4 @@ +import Logger from "../../../common/logger"; import DOMManager from "./dommanager"; export default new class Editor { @@ -22,12 +23,23 @@ export default new class Editor { delete window.module; // Make monaco think this isn't a local node script or else it freaks out DOMManager.linkStyle("monaco-style", `${baseUrl}/vs/editor/editor.main.min.css`, {documentHead: true}); - await DOMManager.injectScript("monaco-script", `${baseUrl}/vs/loader.min.js`); - - const amdLoader = window.require; // Grab Monaco's amd loader - window.require = commonjsLoader; // Revert to commonjs - // this.log(amdLoader, window.require); - amdLoader.config({paths: {vs: `${baseUrl}/vs`}}); - amdLoader(["vs/editor/editor.main"], () => {}); // exposes the monaco global + + try { + await DOMManager.injectScript("monaco-script", `${baseUrl}/vs/loader.min.js`); + + const amdLoader = window.require; // Grab Monaco's amd loader + window.require = commonjsLoader; // Revert to commonjs + + // Configure Monaco's AMD loader + amdLoader.config({paths: {vs: `${baseUrl}/vs`}}); + amdLoader(["vs/editor/editor.main"], () => {}); // exposes the monaco global + } + catch (e) { + Logger.error("Editor", "Failed to load monaco editor", e); + } + finally { + // Revert the global require to CommonJS + window.require = commonjsLoader; + } } }; \ No newline at end of file diff --git a/renderer/src/styles/builtins/customcss.css b/renderer/src/styles/builtins/customcss.css index ce5210ea..d8351128 100644 --- a/renderer/src/styles/builtins/customcss.css +++ b/renderer/src/styles/builtins/customcss.css @@ -97,4 +97,12 @@ .monaco-editor .view-overlays .current-line { width: 1e+06px !important; -} \ No newline at end of file +} + +.bd-fallback-editor { + height: 100%; + width: 100%; + resize: none; + overflow: auto; + white-space: nowrap; +} diff --git a/renderer/src/ui/customcss/editor.jsx b/renderer/src/ui/customcss/editor.jsx index daf83b90..14828043 100644 --- a/renderer/src/ui/customcss/editor.jsx +++ b/renderer/src/ui/customcss/editor.jsx @@ -32,25 +32,45 @@ export default class CodeEditor extends React.Component { } componentDidMount() { - this.editor = window.monaco.editor.create(document.getElementById(this.props.id), { - value: this.props.value, - language: this.props.language, - theme: DiscordModules.UserSettingsStore.theme == "light" ? "vs" : "vs-dark", - fontSize: Settings.get("settings", "editor", "fontSize"), - lineNumbers: Settings.get("settings", "editor", "lineNumbers"), - minimap: {enabled: Settings.get("settings", "editor", "minimap")}, - hover: {enabled: Settings.get("settings", "editor", "hover")}, - quickSuggestions: { - other: Settings.get("settings", "editor", "quickSuggestions"), - comments: Settings.get("settings", "editor", "quickSuggestions"), - strings: Settings.get("settings", "editor", "quickSuggestions") - }, - renderWhitespace: Settings.get("settings", "editor", "renderWhitespace") - }); + if (window.monaco?.editor) { + this.editor = window.monaco.editor.create(document.getElementById(this.props.id), { + value: this.props.value, + language: this.props.language, + theme: DiscordModules.UserSettingsStore.theme == "light" ? "vs" : "vs-dark", + fontSize: Settings.get("settings", "editor", "fontSize"), + lineNumbers: Settings.get("settings", "editor", "lineNumbers"), + minimap: {enabled: Settings.get("settings", "editor", "minimap")}, + hover: {enabled: Settings.get("settings", "editor", "hover")}, + quickSuggestions: { + other: Settings.get("settings", "editor", "quickSuggestions"), + comments: Settings.get("settings", "editor", "quickSuggestions"), + strings: Settings.get("settings", "editor", "quickSuggestions") + }, + renderWhitespace: Settings.get("settings", "editor", "renderWhitespace") + }); + + this.bindings.push(this.editor.onDidChangeModelContent(this.onChange)); + } + else { + + const textarea = document.createElement("textarea"); + textarea.className = "bd-fallback-editor"; + textarea.value = this.props.value; + textarea.onchange = (e) => this.onChange(e.target.value); + textarea.oninput = (e) => this.onChange(e.target.value); + + this.editor = { + dispose: () => textarea.remove(), + getValue: () => textarea.value, + setValue: (value) => textarea.value = value, + layout: () => {}, + }; + + document.getElementById(this.props.id).appendChild(textarea); + } - window.addEventListener("resize", this.resize); if (DiscordModules.UserSettingsStore) DiscordModules.UserSettingsStore.addChangeListener(this.onThemeChange); - this.bindings.push(this.editor.onDidChangeModelContent(this.onChange)); + window.addEventListener("resize", this.resize); } componentWillUnmount() { @@ -64,7 +84,7 @@ export default class CodeEditor extends React.Component { const newTheme = DiscordModules.UserSettingsStore.theme === "light" ? "vs" : "vs-dark"; if (newTheme === this.props.theme) return; this.props.theme = newTheme; - window.monaco.editor.setTheme(this.props.theme); + if (window.monaco?.editor) window.monaco.editor.setTheme(this.props.theme); } get value() {return this.editor.getValue();}