simplify viewer

pull/2179/head
Richard Harris 7 years ago
parent 68bc5ee8b5
commit 9c22f6a5bf

@ -12,188 +12,94 @@
export let error; // TODO should this be exposed as a prop? export let error; // TODO should this be exposed as a prop?
export function setProp(prop, value) { export function setProp(prop, value) {
if (!replProxy) return; if (!proxy) return;
replProxy.setProp(prop, value); proxy.setProp(prop, value);
} }
let hasComponent = false;
let iframe; let iframe;
let pendingImports = 0; let pending_imports = 0;
let pending = false; let pending = false;
let replProxy = null; let proxy = null;
let createComponent; let ready = false;
let init;
onMount(() => { onMount(() => {
replProxy = new ReplProxy(iframe); proxy = new ReplProxy(iframe, {
onPropUpdate: (prop, value) => {
iframe.addEventListener('load', () => {
replProxy.onPropUpdate = (prop, value) => {
dispatch('binding', { prop, value }); dispatch('binding', { prop, value });
values.update(values => Object.assign({}, values, { values.update(values => Object.assign({}, values, {
[prop]: value [prop]: value
})); }));
}; },
replProxy.onFetchProgress = (progress) => { onFetchProgress: progress => {
pendingImports = progress pending_imports = progress;
} }
});
replProxy.handleLinks(); iframe.addEventListener('load', () => {
proxy.handleLinks();
let promise = null; ready = true;
let updating = false; });
let toDestroy = null; return () => {
proxy.eval(`if (window.component) window.component.\$destroy();`)
proxy.destroy();
}
});
const init = () => { let current_token;
if ($bundle.error) return;
const removeStyles = () => { async function apply_bundle($bundle) {
replProxy.eval(` if (!$bundle || $bundle.error) return;
const styles = document.querySelectorAll('style.svelte');
let i = styles.length;
while (i--) styles[i].parentNode.removeChild(styles[i]);
`)
};
const destroyComponent = () => { const token = current_token = {};
replProxy.eval(`if (window.component)
window.component.\$destroy();
window.component = null`);
};
const ready = () => { try {
error = null; await proxy.fetchImports($bundle.imports, $bundle.import_map);
if (token !== current_token) return;
if (toDestroy) { await proxy.eval(`
removeStyles(); const styles = document.querySelectorAll('style.svelte');
destroyComponent(); let i = styles.length;
toDestroy = null; while (i--) styles[i].parentNode.removeChild(styles[i]);
} `)
if ($bundle.ssr) { // this only gets generated if component uses lifecycle hooks await proxy.eval(`${$bundle.dom.code}
pending = true; if (window.component) {
createHtml(); try {
} else { window.component.$destroy();
pending = false; } catch (err) {
createComponent(); console.error(err);
} }
} }
const createHtml = () => { document.body.innerHTML = '';
replProxy.eval(`${$bundle.ssr.code} window.location.hash = '';
var rendered = SvelteComponent.render(${JSON.stringify($values)}); window._svelteTransitionManager = null;
if (rendered.css.code) { window.component = new SvelteComponent({
var style = document.createElement('style'); target: document.body,
style.className = 'svelte'; props: ${JSON.stringify($values)}
style.textContent = rendered.css.code; });
document.head.appendChild(style); `);
}
await proxy.bindProps(props);
document.body.innerHTML = rendered.html; } catch (e) {
`) const loc = getLocationFromStack(e.stack, $bundle.dom.map);
.catch( e => { if (loc) {
const loc = getLocationFromStack(e.stack, $bundle.ssr.map); e.filename = loc.source;
if (loc) { e.loc = { line: loc.line, column: loc.column };
e.filename = loc.source;
e.start = { line: loc.line, column: loc.column };
}
error = e;
});
};
const createComponent = () => {
// remove leftover styles from SSR renderer
if ($bundle.ssr) removeStyles();
replProxy.eval(`${$bundle.dom.code}
if (window.component) {
try {
window.component.$destroy();
} catch (err) {
console.error(err);
}
}
document.body.innerHTML = '';
window.location.hash = '';
window._svelteTransitionManager = null;
window.component = new SvelteComponent({
target: document.body,
props: ${JSON.stringify($values)}
});
`)
.then(()=> {
replProxy.bindProps(props);
})
.catch(e => {
// TODO show in UI
hasComponent = false;
const loc = getLocationFromStack(e.stack, $bundle.dom.map);
if (loc) {
e.filename = loc.source;
e.loc = { line: loc.line, column: loc.column };
}
error = e;
});
};
// Download the imports (sets them on iframe window when complete)
{
let cancelled = false;
promise = replProxy.fetchImports($bundle.imports, $bundle.import_map);
promise.cancel = () => { cancelled = true };
promise.then(() => {
if (cancelled) return;
ready()
}).catch(e => {
if (cancelled) return;
error = e;
});
}
run = () => {
pending = false;
// TODO do we need to clear out SSR HTML?
createComponent();
props_handler = props => {
replProxy.bindProps(props)
};
replProxy.bindProps(props);
};
} }
bundle_handler = $bundle => { console.error(e);
if (!$bundle) return; // TODO can this ever happen?
if (promise) promise.cancel();
toDestroy = hasComponent;
hasComponent = false;
init();
};
});
return () => replProxy.destroy(); error = e;
}); }
}
function noop(){}
let run = noop;
let bundle_handler = noop;
let props_handler = noop;
$: bundle_handler($bundle); $: if (ready) apply_bundle($bundle);
$: props_handler(props);
</script> </script>
<style> <style>
@ -245,7 +151,7 @@
</style> </style>
<div class="iframe-container"> <div class="iframe-container">
<iframe title="Result" bind:this={iframe} sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals" class="{error || pending || pendingImports ? 'greyed-out' : ''}" srcdoc=' <iframe title="Result" bind:this={iframe} sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals" class="{error || pending || pending_imports ? 'greyed-out' : ''}" srcdoc='
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
@ -264,8 +170,8 @@
<Message kind="error" details={error}/> <Message kind="error" details={error}/>
{:else if !$bundle} {:else if !$bundle}
<Message kind="info">loading Svelte compiler...</Message> <Message kind="info">loading Svelte compiler...</Message>
{:else if pendingImports} {:else if pending_imports}
<Message kind="info">loading {pendingImports} {pendingImports === 1 ? 'dependency' : 'dependencies'} from <Message kind="info">loading {pending_imports} {pending_imports === 1 ? 'dependency' : 'dependencies'} from
https://bundle.run</Message> https://bundle.run</Message>
{/if} {/if}
</div> </div>

@ -1,10 +1,11 @@
export default class ReplProxy { export default class ReplProxy {
constructor(iframe) { constructor(iframe, handlers) {
this.iframe = iframe; this.iframe = iframe;
this.handlers = handlers;
this.cmdId = 1; this.cmdId = 1;
this.pendingCmds = new Map(); this.pendingCmds = new Map();
this.onPropUpdate = null;
this.onFetchProgress = null;
this.handle_event = (ev) => this.handleReplMessage(ev); this.handle_event = (ev) => this.handleReplMessage(ev);
window.addEventListener("message", this.handle_event, false); window.addEventListener("message", this.handle_event, false);
} }
@ -57,13 +58,11 @@ export default class ReplProxy {
if (action == "prop_update") { if (action == "prop_update") {
let { prop, value } = ev.data.args; let { prop, value } = ev.data.args;
if (this.onPropUpdate) this.handlers.onPropUpdate(prop, value)
this.onPropUpdate(prop, value)
} }
if (action == "fetch_progress") { if (action == "fetch_progress") {
if (this.onFetchProgress) this.handlers.onFetchProgress(ev.data.args.remaining)
this.onFetchProgress(ev.data.args.remaining)
} }
} }

Loading…
Cancel
Save