fix(excalidraw): use import map to force React 18.3.1 for ALL modules including Excalidraw internals
CI / lint (push) Failing after 10s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Successful in 23s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled

This commit is contained in:
2026-07-29 11:41:30 -04:00
parent 7d8fa18201
commit 8c665fb568
6 changed files with 104 additions and 13 deletions
+3 -3
View File
@@ -19,7 +19,7 @@ function add(msg, cls='') {
add('--- Step 1: Testing esm.sh connectivity ---');
try {
const res = await fetch('https://esm.sh/react@18', { method: 'HEAD' });
const res = await fetch('https://esm.sh/react@18.3.1', { method: 'HEAD' });
add(`✓ esm.sh reachable (HTTP ${res.status})`, 'pass');
} catch(e) {
add(`✗ esm.sh unreachable: ${e.message}`, 'fail');
@@ -27,7 +27,7 @@ try {
add('\n--- Step 2: Importing React ---');
try {
const React = await import('https://esm.sh/react@18');
const React = await import('https://esm.sh/react@18.3.1');
add(`✓ React imported (keys: ${Object.keys(React.default||React).slice(0,5).join(',')})`, 'pass');
window.React = React;
} catch(e) {
@@ -36,7 +36,7 @@ try {
add('\n--- Step 3: Importing ReactDOM ---');
try {
const ReactDOM = await import('https://esm.sh/react-dom@18');
const ReactDOM = await import('https://esm.sh/react-dom@18.3.1');
add(`✓ ReactDOM imported`, 'pass');
window.ReactDOM = ReactDOM;
} catch(e) {
+2 -2
View File
@@ -14,8 +14,8 @@
<div id="app"></div>
<script type="module">
import React from "https://esm.sh/react@18";
import ReactDOM from "https://esm.sh/react-dom@18/client";
import React from "https://esm.sh/react@18.3.1";
import ReactDOM from "https://esm.sh/react-dom@18.3.1/client";
const log = document.getElementById('log');
function add(msg, cls='') { log.innerHTML += `<span class="${cls}">${msg}</span>\n`; }
+6 -3
View File
@@ -1,6 +1,9 @@
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Excalidraw Error Capture</title>
<head><meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0"><title>Excalidraw Error Capture</title>
<style>
body { font-family:monospace; background:#1e1e1e; color:#ddd; padding:20px; }
.pass { color:#4caf50; } .fail { color:#f44336; }
@@ -14,8 +17,8 @@
<div id="app"></div>
<script type="module">
import React from "https://esm.sh/react@18";
import ReactDOM from "https://esm.sh/react-dom@18/client";
import React from "https://esm.sh/react@18.3.1";
import ReactDOM from "https://esm.sh/react-dom@18.3.1/client";
const log = document.getElementById('log');
function add(msg, cls='') { log.innerHTML += `<span class="${cls}">${msg}</span>\n`; }
+74
View File
@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Excalidraw Final Test</title>
<style>
body { font-family:monospace; background:#1e1e1e; color:#ddd; padding:20px; }
.pass { color:#4caf50; } .fail { color:#f44336; }
pre { background:#2d2d2d; padding:10px; border-radius:4px; }
#app { margin-top:20px; border:1px dashed #555; min-height:100px; padding:10px; }
</style>
</head>
<body>
<h2>Excalidraw Final Test (Import Map)</h2>
<pre id="log"></pre>
<div id="app"></div>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/[email protected]",
"react-dom": "https://esm.sh/[email protected]",
"react-dom/": "https://esm.sh/[email protected]/"
}
}
</script>
<script type="module">
import React from "react";
import ReactDOM from "react-dom/client";
const log = document.getElementById('log');
function add(msg, cls='') { log.innerHTML += `<span class="${cls}">${msg}</span>\n`; }
add('React version: ' + React.version, 'info');
class ErrorBoundary extends React.Component {
constructor(props) { super(props); this.state = { error: null }; }
static getDerivedStateFromError(error) { return { error }; }
componentDidCatch(error, info) {
add(`✗ ERROR: ${error.message}`, 'fail');
add(` ${(error.stack||'').split('\n').slice(0,3).join('\n')}`, 'info');
}
render() {
if (this.state.error) return React.createElement('div', {style:{color:'red',padding:'20px'}}, 'Error: '+this.state.error.message);
return this.props.children;
}
}
try {
window.EXCALIDRAW_ASSET_PATH = 'https://esm.sh/@excalidraw/[email protected]/dist/prod/';
const ExcalidrawLib = await import('@excalidraw/[email protected]');
const { Excalidraw } = ExcalidrawLib;
add('Excalidraw loaded', 'pass');
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(
React.createElement(ErrorBoundary, null,
React.createElement(Excalidraw, {
theme: 'dark',
excalidrawRef: (api) => add('✓ EXCALIDRAW MOUNTED!', 'pass'),
onChange: () => {},
})
)
);
add('render() called - waiting for mount...', 'info');
} catch(e) {
add(`✗ ${e.message}`, 'fail');
}
</script>
</body>
</html>
+18 -4
View File
@@ -2,6 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Excalidraw Editor</title>
<style>
@@ -89,11 +92,22 @@
<button id="btn-export-svg" title="Export SVG">📐 SVG</button>
</div>
<!-- Import React, ReactDOM, and Excalidraw in a single module (order matters!) -->
<!-- Import map: force ALL modules (Excalidraw + sub-deps) to use React 18.3.1 -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/[email protected]",
"react-dom": "https://esm.sh/[email protected]",
"react-dom/": "https://esm.sh/[email protected]/"
}
}
</script>
<!-- Single module script -->
<script type="module">
import React from "https://esm.sh/[email protected]";
import ReactDOM from "https://esm.sh/react-dom@18.3.1";
import * as ExcalidrawLib from "https://esm.sh/@excalidraw/[email protected]";
import React from "react";
import ReactDOM from "react-dom";
import * as ExcalidrawLib from "@excalidraw/[email protected]";
window.React = React;
window.ReactDOM = ReactDOM;
+1 -1
View File
@@ -32,7 +32,7 @@ export function renderExcalidraw(container, data, vaultName, filePath, opts = {}
// Build the iframe
const iframe = document.createElement('iframe');
iframe.id = editorId;
iframe.src = '/static/excalidraw-editor.html';
iframe.src = '/static/excalidraw-editor.html?v=' + Date.now();
iframe.sandbox.add('allow-scripts');
iframe.sandbox.add('allow-same-origin');
iframe.style.cssText = 'width:100%;height:100%;border:none;';