Skip to content

Commit 761ffe7

Browse files
committed
feat: intergrate chii into playground
1 parent 81f8130 commit 761ffe7

File tree

4 files changed

+32
-185
lines changed

4 files changed

+32
-185
lines changed

packages/repl/src/lib/Output/PaneWithPanel.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
88
export let panel: string;
99
10+
export let header = true;
11+
1012
export let pos: Exclude<ComponentProps<SplitPane>['pos'], undefined> = '90%';
1113
1214
$: previous_pos = Math.min(+pos.replace(UNIT_REGEX, '$1'), 70);

packages/repl/src/lib/Output/ReplProxy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default class ReplProxy {
8181
handler.resolve(cmd_data.args);
8282
}
8383
} else {
84+
debugger
8485
console.error('command not found', id, cmd_data, [...this.pending_cmds.keys()]);
8586
}
8687
}

packages/repl/src/lib/Output/Viewer.svelte

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import type { CompileError } from 'svelte/compiler';
1313
import type { Bundle } from '../types';
1414
import type { Writable } from 'svelte/store';
15+
import DevTools from './devtools/DevTools.svelte';
1516
1617
export let error: Error | null;
1718
/** status by Bundler class instance */
@@ -110,6 +111,10 @@
110111
await proxy?.eval(`
111112
${injectedJS}
112113
114+
const chobitsu_scr = document.createElement('script');
115+
chobitsu_scr.src = 'https://cdn.jsdelivr.net/npm/chobitsu';
116+
document.body.appendChild(chobitsu_scr);
117+
113118
if (!window.__setup_focus_handling) {
114119
let can_focus = false;
115120
@@ -157,30 +162,28 @@
157162
158163
const __repl_exports = ${$bundle.client?.code};
159164
{
160-
const { mount, unmount, App, untrack } = __repl_exports;
165+
const { mount, unmount, App } = __repl_exports;
161166
162-
const console_methods = ['log', 'error', 'trace', 'assert', 'warn', 'table', 'group'];
163167
164-
// The REPL hooks up to the console to provide a virtual console. However, the implementation
165-
// needs to stringify the console to pass over a MessageChannel, which means that the object
166-
// can get deeply read and tracked by accident when using the console. We can avoid this by
167-
// ensuring we untrack the main console methods.
168+
window.initialize = (target_src) => {
169+
var script = document.createElement('script');
170+
script.src = target_src;
171+
script.setAttribute('embedded', 'true');
172+
script.setAttribute('cdn', 'https://cdn.jsdelivr.net/npm/chii/public');
173+
document.head.appendChild(script);
168174
169-
const original = {};
175+
script.onload = () => {
176+
const component = mount(App, { target: document.body });
170177
171-
for (const method of console_methods) {
172-
original[method] = console[method];
173-
console[method] = function (...v) {
174-
return untrack(() => original[method].apply(this, v));
175-
}
176-
}
177-
const component = mount(App, { target: document.body });
178-
window.__unmount_previous = () => {
179-
for (const method of console_methods) {
180-
console[method] = original[method];
181-
}
182-
unmount(component);
183-
}
178+
window.__unmount_previous = () => {
179+
unmount(component);
180+
}
181+
};
182+
};
183+
184+
setTimeout(() => {
185+
window.dispatchEvent(new Event('devtools_ready'));
186+
}, 0);
184187
}
185188
//# sourceURL=playground:output
186189
`);
@@ -282,7 +285,7 @@
282285
'allow-pointer-lock',
283286
'allow-modals',
284287
can_escape ? 'allow-popups-to-escape-sandbox' : '',
285-
relaxed ? 'allow-same-origin' : ''
288+
'allow-same-origin'
286289
].join(' ')}
287290
class={error || pending || pending_imports ? 'greyed-out' : ''}
288291
srcdoc={BROWSER ? srcdoc : ''}
@@ -295,22 +298,13 @@
295298

296299
<div class="iframe-container">
297300
{#if !onLog}
298-
<PaneWithPanel pos="90%" panel="Console">
301+
<PaneWithPanel pos="80%" panel="DevTools">
299302
<div slot="main">
300303
{@render main()}
301304
</div>
302305

303-
<div slot="panel-header">
304-
<button class="raised" disabled={logs.length === 0} on:click|stopPropagation={clear_logs}>
305-
{#if logs.length > 0}
306-
({logs.length})
307-
{/if}
308-
Clear
309-
</button>
310-
</div>
311-
312306
<section slot="panel-body">
313-
<Console {logs} />
307+
<DevTools iframe={iframe} />
314308
</section>
315309
</PaneWithPanel>
316310
{:else}

packages/repl/src/lib/Output/srcdoc/index.html

Lines changed: 3 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@
132132
});
133133
}
134134

135-
reply({ action: 'cmd_ok' });
135+
if (action !== undefined) {
136+
reply({ action: 'cmd_ok' });
137+
}
136138
} catch ({ message, stack }) {
137139
reply({ action: 'cmd_error', message, stack });
138140
}
@@ -146,159 +148,7 @@
146148
send({ action: 'unhandledrejection', value: event.reason });
147149
});
148150

149-
// Intercept console methods
150-
const timers = new Map();
151-
const counters = new Map();
152-
153-
function log(command, opts) {
154-
try {
155-
send({ action: 'console', command, ...opts });
156-
} catch {
157-
send({ action: 'console', command: 'unclonable' });
158-
}
159-
}
160-
161-
function stringify(args) {
162-
try {
163-
return JSON.stringify(args, (key, value) => {
164-
// if we don't do this, our Set/Map from svelte/reactivity would show up wrong in the console
165-
if (value instanceof Map) {
166-
return { type: 'Map', value };
167-
}
168-
169-
if (value instanceof Set) {
170-
return { type: 'Set', value };
171-
}
172151

173-
// if we don't handle bigints separately, they will cause JSON.stringify to blow up
174-
if (typeof value === 'bigint') {
175-
return { type: 'BigInt', value: value + '' };
176-
}
177-
178-
return value;
179-
});
180-
} catch (error) {
181-
return null;
182-
}
183-
}
184-
185-
/** @param {string} method */
186-
function stack(method) {
187-
return new Error().stack
188-
.split('\n')
189-
.filter((line) => {
190-
if (/[(@]about:srcdoc/.test(line)) return false;
191-
return true;
192-
})
193-
.slice(1)
194-
.map((line) => {
195-
line = line
196-
.replace('console[method]', `console.${method}`)
197-
.replace(/console\.<computed> \[as \w+\]/, `console.${method}`);
198-
199-
let match =
200-
/^\s+at (.+) \((.+:\d+:\d+)\)/.exec(line) || /^(.+)@(.+:\d+:\d+)?/.exec(line);
201-
202-
if (match) {
203-
return {
204-
label: match[1],
205-
location: match[2]
206-
};
207-
}
208-
209-
return null;
210-
})
211-
.filter((x) => x);
212-
}
213-
214-
const can_dedupe = ['log', 'info', 'dir', 'warn', 'error', 'assert', 'trace'];
215-
216-
const methods = {
217-
clear: () => log('clear'),
218-
// TODO make the command 'push' and the level/type 'info'
219-
log: (...args) => log('info', { args }),
220-
info: (...args) => log('info', { args }),
221-
dir: (...args) => log('info', { args: [args[0]], expanded: true }),
222-
warn: (...args) => log('warn', { args, stack: stack('warn'), collapsed: true }),
223-
error: (...args) => log('error', { args, stack: stack('error'), collapsed: true }),
224-
assert: (condition, ...args) => {
225-
if (condition) return;
226-
log('error', {
227-
args: ['Assertion failed:', ...args],
228-
stack: stack('assert'),
229-
collapsed: true
230-
});
231-
},
232-
group: (...args) => log('group', { args, collapsed: false }),
233-
groupCollapsed: (...args) => log('group', { args, collapsed: true }),
234-
groupEnd: () => log('groupEnd'),
235-
table: (...args) => {
236-
const data = args[0];
237-
if (data && typeof data === 'object') {
238-
log('table', { data, columns: args[1] });
239-
} else {
240-
log('info', { args });
241-
}
242-
},
243-
time: (label = 'default') => timers.set(label, performance.now()),
244-
timeLog: (label = 'default') => {
245-
const now = performance.now();
246-
if (timers.has(label)) {
247-
log('info', { args: [`${label}: ${now - timers.get(label)}ms`] });
248-
} else {
249-
log('warn', { args: [`Timer '${label}' does not exist`] });
250-
}
251-
},
252-
timeEnd: (label = 'default') => {
253-
const now = performance.now();
254-
if (timers.has(label)) {
255-
log('info', { args: [`${label}: ${now - timers.get(label)}ms`] });
256-
} else {
257-
log('warn', { args: [`Timer '${label}' does not exist`] });
258-
}
259-
timers.delete(label);
260-
},
261-
count: (label = 'default') => {
262-
counters.set(label, (counters.get(label) || 0) + 1);
263-
log('info', { args: [`${label}: ${counters.get(label)}`] });
264-
},
265-
countReset: (label = 'default') => {
266-
if (counters.has(label)) {
267-
counters.set(label, 0);
268-
} else {
269-
log('warn', { args: [`Count for '${label}' does not exist`] });
270-
}
271-
},
272-
trace: (...args) => {
273-
log('info', {
274-
args: args.length === 0 ? ['console.trace'] : args,
275-
stack: stack('trace'),
276-
collapsed: false
277-
});
278-
}
279-
};
280-
281-
let previous = '';
282-
283-
for (const method in methods) {
284-
const original = console[method];
285-
286-
console[method] = (...args) => {
287-
const stack = new Error().stack;
288-
289-
if (
290-
previous === (previous = stringify({ method, args, stack })) &&
291-
can_dedupe.includes(method) &&
292-
args.every((arg) => !arg || typeof arg !== 'object')
293-
) {
294-
send({ action: 'console', command: 'duplicate' });
295-
} else {
296-
methods[method](...args);
297-
}
298-
299-
original(...args);
300-
};
301-
}
302152
})();
303153
</script>
304154
</head>

0 commit comments

Comments
 (0)