Skip to content

Commit b2c3443

Browse files
committed
fix a few double render bugs
1 parent 6cf6f38 commit b2c3443

File tree

8 files changed

+194
-145
lines changed

8 files changed

+194
-145
lines changed

packages/playground/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
"jsxImportSource": "solid-js",
1818
"types": ["vite/client"]
1919
},
20-
"include": ["./src/**/*", "./playground/**/*", "repl/**/*"],
20+
"include": ["./src/**/*"],
2121
"exclude": ["node_modules/"]
2222
}

packages/solid-repl/package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,40 @@
1717
"build": "tsc -p tsconfig.build.json && unocss \"./src/**\" && jiti build.ts",
1818
"tsc": "tsc"
1919
},
20+
"peerDependencies": {
21+
"solid-js": ">=1.7.0"
22+
},
2023
"devDependencies": {
2124
"@babel/core": "^7.22.11",
2225
"@babel/plugin-syntax-jsx": "^7.22.5",
2326
"@babel/preset-typescript": "^7.22.11",
27+
"@babel/standalone": "^7.22.12",
2428
"@babel/types": "^7.22.11",
2529
"@types/babel__standalone": "^7.1.4",
2630
"@types/dedent": "^0.7.0",
2731
"@types/fs-extra": "^11.0.1",
2832
"@unocss/cli": "^0.55.3",
2933
"@unocss/preset-wind": "^0.55.3",
34+
"@unocss/reset": "^0.55.3",
35+
"babel-preset-solid": "1.7.7",
3036
"esbuild": "^0.19.2",
37+
"eslint-solid-standalone": "^0.13.0",
3138
"fs-extra": "^11.1.1",
3239
"jiti": "^1.19.3",
3340
"monaco-editor": "~0.40.0",
41+
"prettier": "^3.0.2",
42+
"solid-js": "1.7.11",
3443
"typescript": "^5.2.2",
3544
"unocss": "^0.55.3"
3645
},
3746
"dependencies": {
38-
"@babel/standalone": "^7.22.12",
3947
"@solid-primitives/media": "^2.2.4",
4048
"@solid-primitives/scheduled": "^1.4.1",
41-
"@unocss/reset": "^0.55.3",
42-
"babel-preset-solid": "1.7.7",
4349
"dedent": "^1.5.1",
44-
"eslint-solid-standalone": "^0.13.0",
4550
"monaco-editor-textmate": "^4.0.0",
4651
"monaco-textmate": "^3.0.1",
4752
"onigasm": "^2.2.5",
48-
"prettier": "^3.0.2",
4953
"solid-dismiss": "^1.7.121",
50-
"solid-heroicons": "^3.2.4",
51-
"solid-js": "1.7.11"
54+
"solid-heroicons": "^3.2.4"
5255
}
5356
}

packages/solid-repl/src/components/editor/index.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useZoom } from '../../hooks/useZoom';
55
import { throttle } from '@solid-primitives/scheduled';
66

77
const Editor: Component<{
8-
url: string;
8+
model: mEditor.ITextModel;
99
disabled?: true;
1010
isDark?: boolean;
1111
withMinimap?: boolean;
@@ -26,8 +26,6 @@ const Editor: Component<{
2626

2727
const { zoomState } = useZoom();
2828

29-
const model = () => mEditor.getModel(Uri.parse(props.url));
30-
3129
if (props.formatter) {
3230
languages.registerDocumentFormattingEditProvider('typescript', {
3331
async provideDocumentFormattingEdits(model) {
@@ -59,12 +57,10 @@ const Editor: Component<{
5957
if (props.displayErrors) {
6058
const { event } = data;
6159
if (event === 'LINT') {
62-
const m = model();
63-
m && mEditor.setModelMarkers(m, 'eslint', data.markers);
60+
mEditor.setModelMarkers(props.model, 'eslint', data.markers);
6461
} else if (event === 'FIX') {
65-
const m = model();
66-
m && mEditor.setModelMarkers(m, 'eslint', data.markers);
67-
data.fixed && model()?.setValue(data.output);
62+
mEditor.setModelMarkers(props.model, 'eslint', data.markers);
63+
data.fixed && props.model.setValue(data.output);
6864
}
6965
}
7066
};
@@ -97,8 +93,7 @@ const Editor: Component<{
9793
});
9894

9995
createEffect(() => {
100-
const disabled = props.disabled == true ? true : false;
101-
editor.updateOptions({ readOnly: disabled });
96+
editor.updateOptions({ readOnly: !!props.disabled });
10297
});
10398

10499
if (props.linter) {
@@ -136,7 +131,7 @@ const Editor: Component<{
136131
onCleanup(() => editor.dispose());
137132

138133
createEffect(() => {
139-
editor.setModel(model());
134+
editor.setModel(props.model);
140135
liftOff();
141136
});
142137

@@ -162,8 +157,7 @@ const Editor: Component<{
162157
runLinter(editor.getValue());
163158
} else {
164159
// reset eslint markers when displayLintMessages is turned off
165-
const m = model();
166-
m && mEditor.setModelMarkers(m, 'eslint', []);
160+
mEditor.setModelMarkers(props.model, 'eslint', []);
167161
}
168162
});
169163

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,36 @@
1-
import { Component, createEffect, onCleanup, untrack } from 'solid-js';
1+
import { createMemo, onCleanup } from 'solid-js';
22
import type { Tab } from 'solid-repl';
33
import { Uri, editor, IDisposable } from 'monaco-editor';
44

5-
const MonacoTabs: Component<{ folder: string; tabs: Tab[] }> = (props) => {
6-
const key = (tab: Tab) => `file:///${props.folder}/${tab.name}`;
7-
let currentTabs = new Map<string, { model: editor.ITextModel; watcher: IDisposable }>();
8-
let syncing = false;
9-
createEffect(() => {
5+
export const createMonacoTabs = (folder: string, tabs: () => Tab[]) => {
6+
const currentTabs = createMemo<Map<string, { model: editor.ITextModel; watcher: IDisposable }>>((prevTabs) => {
107
const newTabs = new Map<string, { model: editor.ITextModel; watcher: IDisposable }>();
11-
syncing = true;
12-
for (const tab of props.tabs) {
13-
const keyValue = key(tab);
14-
const lookup = currentTabs.get(keyValue);
15-
const source = untrack(() => tab.source);
8+
for (const tab of tabs()) {
9+
const url = `file:///${folder}/${tab.name}`;
10+
const lookup = prevTabs?.get(url);
1611
if (!lookup) {
17-
const uri = Uri.parse(keyValue);
18-
const model = editor.createModel(source, undefined, uri);
19-
const watcher = model.onDidChangeContent(() => {
20-
if (!syncing) tab.source = model.getValue();
21-
});
22-
newTabs.set(keyValue, { model, watcher });
12+
const uri = Uri.parse(url);
13+
const model = editor.createModel(tab.source, undefined, uri);
14+
const watcher = model.onDidChangeContent(() => (tab.source = model.getValue()));
15+
newTabs.set(url, { model, watcher });
2316
} else {
24-
lookup.model.setValue(source);
17+
lookup.model.setValue(tab.source);
2518
lookup.watcher.dispose();
26-
lookup.watcher = lookup.model.onDidChangeContent(() => {
27-
if (!syncing) tab.source = lookup.model.getValue();
28-
});
29-
newTabs.set(keyValue, lookup);
19+
lookup.watcher = lookup.model.onDidChangeContent(() => (tab.source = lookup.model.getValue()));
20+
newTabs.set(url, lookup);
3021
}
3122
}
32-
syncing = false;
3323

34-
for (const [old, lookup] of currentTabs) {
35-
if (!newTabs.has(old)) lookup.model.dispose();
24+
if (prevTabs) {
25+
for (const [old, lookup] of prevTabs) {
26+
if (!newTabs.has(old)) lookup.model.dispose();
27+
}
3628
}
37-
currentTabs = newTabs;
29+
return newTabs;
3830
});
3931
onCleanup(() => {
40-
for (const lookup of currentTabs.values()) lookup.model.dispose();
32+
for (const lookup of currentTabs().values()) lookup.model.dispose();
4133
});
4234

43-
return <></>;
35+
return currentTabs;
4436
};
45-
export default MonacoTabs;

packages/solid-repl/src/components/preview.tsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,28 +64,42 @@ const generateHTML = (isDark: boolean, importMap: string) => `
6464
<script type="importmap">${importMap}</script>
6565
<script src="https://cdn.jsdelivr.net/npm/chobitsu"></script>
6666
<script type="module">
67-
window.addEventListener('message', async ({ data }) => {
67+
let finisher = undefined;
68+
window.addEventListener('message', ({ data }) => {
6869
const { event, value } = data;
6970
7071
if (event !== 'CODE_UPDATE') return;
7172
72-
window.dispose?.();
73-
window.dispose = undefined;
73+
const next = () => {
74+
window.dispose?.();
75+
window.dispose = undefined;
7476
75-
document.getElementById('app').innerHTML = "";
77+
document.getElementById('app').innerHTML = "";
7678
77-
console.clear();
79+
console.clear();
7880
79-
document.getElementById('appsrc')?.remove();
80-
const script = document.createElement('script');
81-
script.src = value;
82-
script.id = 'appsrc';
83-
script.type = 'module';
84-
document.body.appendChild(script);
81+
document.getElementById('appsrc')?.remove();
82+
const script = document.createElement('script');
83+
script.id = 'appsrc';
84+
script.type = 'module';
85+
finisher = () => {};
86+
script.onload = () => {
87+
if (finisher) finisher();
88+
finisher = undefined;
89+
};
90+
script.src = value;
91+
document.body.appendChild(script);
8592
86-
const load = document.getElementById('load');
87-
if (load) load.remove();
93+
const load = document.getElementById('load');
94+
if (load) load.remove();
95+
}
96+
if (finisher !== undefined) {
97+
finisher = next;
98+
} else {
99+
next();
100+
}
88101
});
102+
89103
const sendToDevtools = (message) => {
90104
window.parent.postMessage(JSON.stringify(message), '*');
91105
};
@@ -265,7 +279,7 @@ export const Preview: Component<Props> = (props) => {
265279
isIframeReady = true;
266280

267281
if (devtoolsLoaded) iframe.contentWindow!.postMessage({ event: 'LOADED' }, '*');
268-
iframe.contentWindow!.postMessage({ event: 'CODE_UPDATE', value: props.code }, '*');
282+
if (props.code) iframe.contentWindow!.postMessage({ event: 'CODE_UPDATE', value: props.code }, '*');
269283
iframe.contentDocument!.documentElement.classList.toggle('dark', props.isDark);
270284
}}
271285
// @ts-ignore

0 commit comments

Comments
 (0)