TaskWorklet Demo #2
by Jason Miller
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/codemirror/4.5.0/codemirror.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/developit/39e7a58ed3e8bc5e8eb4/raw/7a98859141909389879aadffaa0a0ebf2437473e/one-dark.css">
<script src="https://cdn.jsdelivr.net/codemirror/4.5.0/codemirror.min.js"></script>
<script src="https://cdn.jsdelivr.net/codemirror/4.5.0/mode/javascript/javascript.js"></script>
<script src="https://cdn.rawgit.com/developit/c33ac5282c1180a06adea2fce954e7d1/raw/0e60e862bfdc806880f5f918869be0cd79ad1db1/task-worklet.js"></script>
<script src="https://not-rawgit.now.sh/gist/developit/c33ac5282c1180a06adea2fce954e7d1/raw/e95792d909a0c55be12b5dfa52459a52edb7a1de/task-worklet.js"></script>
<button id="loadpreact">Load a bunch of code</button>
<div id="error"></div>
<div class="pane">
<textarea id="code">
const life = 42
function foo() {
return bar() + 1
}
function bar() {
return life
}
// comment out to see rollup magic!
export { foo }
</textarea>
</div>
<div class="pane right">
<textarea id="output" readonly></textarea>
</div>
CSS
#loadpreact {
position: fixed;
bottom: 0;
left: 0;
background: #ccc;
color: #555;
padding: 5px 10px;
border: 1px solid #aaa;
box-shadow: 0 1px 3px #000;
border-radius: 3px;
z-index: 999;
}
#error {
position: fixed;
bottom: 0;
left: 50%;
box-sizing: border-box;
min-height: 3em;
max-height: 9em;
padding: 10px 20px;
max-width: 100%;
margin: 0;
background: rgba(50,0,0,0.98);
border-bottom: none;
font-family: monospace;
white-space: pre-wrap;
color: #FFF;
text-align: left;
font-size: 11px;
border-radius: 5px 5px 0 0;
box-shadow: 0 0 5px rgba(0,0,0,0.7), inset 0 .5px 0 rgba(255,255,255,0.4), inset -.5px 0 0 rgba(255,255,255,0.2), inset .5px 0 0 rgba(255,255,255,0.2);
transform: translate(-50%, 120%);
transition: transform 150ms ease;
will-change: transform;
z-index: 500;
}
#error.showing {
transform: translate(-50%, 0%);
}
.pane {
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
width: 50%;
height: 100%;
padding: 0;
border: none;
border-right: 1px solid #999;
overflow: hidden;
}
.pane.right {
left: 50%;
border-right: none;
}
textarea, .CodeMirror {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
outline: none;
}
JavaScript
const mc = {};
function scope(fn) {
const str = typeof fn==='function' ? `(${fn}).call(this)` : String(fn);
return mc[str] || (mc[str] = URL.createObjectURL(new Blob([str])));
};
const q = new TaskQueue({ size: 4 });
const workletReady = q.addModule(scope(() => {
let $import;
if (typeof importScripts === 'function') {
importScripts('https://unpkg.com/shimport@0.0.11/index.js');
$import = x => __shimport__.load(x).then(r=>r.default)
} else {
$import = x => import(x).then(r=>r.default)
}
function importCjs(url, preprocess) {
return fetch(url)
.then(r => r.text())
.then(preprocess || String)
.then(code => {
const scope = { fetch, module:{ exports: {} } };
try {
const fn = new Function('global', 'module', 'exports', 'fetch', 'code', 'scope', code);
fn.call(scope, scope, scope.module, scope.module.exports, scope.fetch);
} catch (e) {
throw Error('Parse failed for ' + url + '\n\n' + e);
}
return scope.module.exports;
});
}
function bublePlugin (buble, options) {
if (!options) options = {};
if (!options.transforms) options.transforms = {};
options.transforms.modules = false;
return {
name: 'buble',
transform (code, id) {
try {
return buble.transform(code, options);
} catch (e) {
e.plugin = 'buble';
if ( !e.loc ) e.loc = {};
e.loc.file = id;
e.frame = e.snippet;
throw e;
}
}
};
}
class BundleTask {
constructor() {
this.memory = $import('https://unpkg.com/rollup-plugin-memory?module');
this.es3 = $import('https://unpkg.com/rollup-plugin-es3?module');
this.rollup = importCjs('https://unpkg.com/rollup@0.66.0/dist/rollup.browser.js');
this.buble = importCjs('https://unpkg.com/buble@0.19.3/dist/buble-browser-deps.umd.js');
}
async process(source) {
const [
memory,
es3,
rollup,
buble
] = await Promise.all([
...