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([
     ...