This commit is contained in:
Michael Zhang 2020-02-11 22:42:58 -06:00
parent 6d7436e829
commit a70ccbd4a5
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
5 changed files with 692 additions and 14 deletions

View file

@ -1,14 +0,0 @@
+++
title = "enterprise: a new ui framework"
date = 2020-02-11
draft = true
[taxonomies]
tags = []
+++
This past weekend, while on my trip to Minneapolis, I completed a very early prototype of "enterprise", a new UI framework I've been kind of envisioning over the past couple of weeks. While the UI framework is mainly targeted at web apps, the hope is that with a bit more effort, native UIs can be produced with almost no changes to existing applications. Before I begin to describe how it works, I'd like to acknowledge [Nathan Ringo][1] for his massively helpful feedback in both the ideation and the implementation process.
## Goals of the project
[1]: https://remexre.xyz

View file

@ -0,0 +1,639 @@
"use strict";
if( typeof Rust === "undefined" ) {
var Rust = {};
}
(function( root, factory ) {
if( typeof define === "function" && define.amd ) {
define( [], factory );
} else if( typeof module === "object" && module.exports ) {
module.exports = factory();
} else {
Rust.helloworld = factory();
}
}( this, function() {
return (function( module_factory ) {
var instance = module_factory();
if( typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string" ) {
var fs = require( "fs" );
var path = require( "path" );
var wasm_path = path.join( __dirname, "helloworld.wasm" );
var buffer = fs.readFileSync( wasm_path );
var mod = new WebAssembly.Module( buffer );
var wasm_instance = new WebAssembly.Instance( mod, instance.imports );
return instance.initialize( wasm_instance );
} else {
var file = fetch( "helloworld.wasm", {credentials: "same-origin"} );
var wasm_instance = ( typeof WebAssembly.instantiateStreaming === "function"
? WebAssembly.instantiateStreaming( file, instance.imports )
.then( function( result ) { return result.instance; } )
: file
.then( function( response ) { return response.arrayBuffer(); } )
.then( function( bytes ) { return WebAssembly.compile( bytes ); } )
.then( function( mod ) { return WebAssembly.instantiate( mod, instance.imports ) } ) );
return wasm_instance
.then( function( wasm_instance ) {
var exports = instance.initialize( wasm_instance );
console.log( "Finished loading Rust wasm module 'helloworld'" );
return exports;
})
.catch( function( error ) {
console.log( "Error loading Rust wasm module 'helloworld':", error );
throw error;
});
}
}( function() {
var Module = {};
Module.STDWEB_PRIVATE = {};
// This is based on code from Emscripten's preamble.js.
Module.STDWEB_PRIVATE.to_utf8 = function to_utf8( str, addr ) {
var HEAPU8 = Module.HEAPU8;
for( var i = 0; i < str.length; ++i ) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
// For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
var u = str.charCodeAt( i ); // possibly a lead surrogate
if( u >= 0xD800 && u <= 0xDFFF ) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt( ++i ) & 0x3FF);
}
if( u <= 0x7F ) {
HEAPU8[ addr++ ] = u;
} else if( u <= 0x7FF ) {
HEAPU8[ addr++ ] = 0xC0 | (u >> 6);
HEAPU8[ addr++ ] = 0x80 | (u & 63);
} else if( u <= 0xFFFF ) {
HEAPU8[ addr++ ] = 0xE0 | (u >> 12);
HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63);
HEAPU8[ addr++ ] = 0x80 | (u & 63);
} else if( u <= 0x1FFFFF ) {
HEAPU8[ addr++ ] = 0xF0 | (u >> 18);
HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63);
HEAPU8[ addr++ ] = 0x80 | (u & 63);
} else if( u <= 0x3FFFFFF ) {
HEAPU8[ addr++ ] = 0xF8 | (u >> 24);
HEAPU8[ addr++ ] = 0x80 | ((u >> 18) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63);
HEAPU8[ addr++ ] = 0x80 | (u & 63);
} else {
HEAPU8[ addr++ ] = 0xFC | (u >> 30);
HEAPU8[ addr++ ] = 0x80 | ((u >> 24) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 18) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63);
HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63);
HEAPU8[ addr++ ] = 0x80 | (u & 63);
}
}
};
Module.STDWEB_PRIVATE.noop = function() {};
Module.STDWEB_PRIVATE.to_js = function to_js( address ) {
var kind = Module.HEAPU8[ address + 12 ];
if( kind === 0 ) {
return undefined;
} else if( kind === 1 ) {
return null;
} else if( kind === 2 ) {
return Module.HEAP32[ address / 4 ];
} else if( kind === 3 ) {
return Module.HEAPF64[ address / 8 ];
} else if( kind === 4 ) {
var pointer = Module.HEAPU32[ address / 4 ];
var length = Module.HEAPU32[ (address + 4) / 4 ];
return Module.STDWEB_PRIVATE.to_js_string( pointer, length );
} else if( kind === 5 ) {
return false;
} else if( kind === 6 ) {
return true;
} else if( kind === 7 ) {
var pointer = Module.STDWEB_PRIVATE.arena + Module.HEAPU32[ address / 4 ];
var length = Module.HEAPU32[ (address + 4) / 4 ];
var output = [];
for( var i = 0; i < length; ++i ) {
output.push( Module.STDWEB_PRIVATE.to_js( pointer + i * 16 ) );
}
return output;
} else if( kind === 8 ) {
var arena = Module.STDWEB_PRIVATE.arena;
var value_array_pointer = arena + Module.HEAPU32[ address / 4 ];
var length = Module.HEAPU32[ (address + 4) / 4 ];
var key_array_pointer = arena + Module.HEAPU32[ (address + 8) / 4 ];
var output = {};
for( var i = 0; i < length; ++i ) {
var key_pointer = Module.HEAPU32[ (key_array_pointer + i * 8) / 4 ];
var key_length = Module.HEAPU32[ (key_array_pointer + 4 + i * 8) / 4 ];
var key = Module.STDWEB_PRIVATE.to_js_string( key_pointer, key_length );
var value = Module.STDWEB_PRIVATE.to_js( value_array_pointer + i * 16 );
output[ key ] = value;
}
return output;
} else if( kind === 9 ) {
return Module.STDWEB_PRIVATE.acquire_js_reference( Module.HEAP32[ address / 4 ] );
} else if( kind === 10 || kind === 12 || kind === 13 ) {
var adapter_pointer = Module.HEAPU32[ address / 4 ];
var pointer = Module.HEAPU32[ (address + 4) / 4 ];
var deallocator_pointer = Module.HEAPU32[ (address + 8) / 4 ];
var num_ongoing_calls = 0;
var drop_queued = false;
var output = function() {
if( pointer === 0 || drop_queued === true ) {
if (kind === 10) {
throw new ReferenceError( "Already dropped Rust function called!" );
} else if (kind === 12) {
throw new ReferenceError( "Already dropped FnMut function called!" );
} else {
throw new ReferenceError( "Already called or dropped FnOnce function called!" );
}
}
var function_pointer = pointer;
if (kind === 13) {
output.drop = Module.STDWEB_PRIVATE.noop;
pointer = 0;
}
if (num_ongoing_calls !== 0) {
if (kind === 12 || kind === 13) {
throw new ReferenceError( "FnMut function called multiple times concurrently!" );
}
}
var args = Module.STDWEB_PRIVATE.alloc( 16 );
Module.STDWEB_PRIVATE.serialize_array( args, arguments );
try {
num_ongoing_calls += 1;
Module.STDWEB_PRIVATE.dyncall( "vii", adapter_pointer, [function_pointer, args] );
var result = Module.STDWEB_PRIVATE.tmp;
Module.STDWEB_PRIVATE.tmp = null;
} finally {
num_ongoing_calls -= 1;
}
if( drop_queued === true && num_ongoing_calls === 0 ) {
output.drop();
}
return result;
};
output.drop = function() {
if (num_ongoing_calls !== 0) {
drop_queued = true;
return;
}
output.drop = Module.STDWEB_PRIVATE.noop;
var function_pointer = pointer;
pointer = 0;
if (function_pointer != 0) {
Module.STDWEB_PRIVATE.dyncall( "vi", deallocator_pointer, [function_pointer] );
}
};
return output;
} else if( kind === 14 ) {
var pointer = Module.HEAPU32[ address / 4 ];
var length = Module.HEAPU32[ (address + 4) / 4 ];
var array_kind = Module.HEAPU32[ (address + 8) / 4 ];
var pointer_end = pointer + length;
switch( array_kind ) {
case 0:
return Module.HEAPU8.subarray( pointer, pointer_end );
case 1:
return Module.HEAP8.subarray( pointer, pointer_end );
case 2:
return Module.HEAPU16.subarray( pointer, pointer_end );
case 3:
return Module.HEAP16.subarray( pointer, pointer_end );
case 4:
return Module.HEAPU32.subarray( pointer, pointer_end );
case 5:
return Module.HEAP32.subarray( pointer, pointer_end );
case 6:
return Module.HEAPF32.subarray( pointer, pointer_end );
case 7:
return Module.HEAPF64.subarray( pointer, pointer_end );
}
} else if( kind === 15 ) {
return Module.STDWEB_PRIVATE.get_raw_value( Module.HEAPU32[ address / 4 ] );
}
};
Module.STDWEB_PRIVATE.serialize_object = function serialize_object( address, value ) {
var keys = Object.keys( value );
var length = keys.length;
var key_array_pointer = Module.STDWEB_PRIVATE.alloc( length * 8 );
var value_array_pointer = Module.STDWEB_PRIVATE.alloc( length * 16 );
Module.HEAPU8[ address + 12 ] = 8;
Module.HEAPU32[ address / 4 ] = value_array_pointer;
Module.HEAPU32[ (address + 4) / 4 ] = length;
Module.HEAPU32[ (address + 8) / 4 ] = key_array_pointer;
for( var i = 0; i < length; ++i ) {
var key = keys[ i ];
var key_address = key_array_pointer + i * 8;
Module.STDWEB_PRIVATE.to_utf8_string( key_address, key );
Module.STDWEB_PRIVATE.from_js( value_array_pointer + i * 16, value[ key ] );
}
};
Module.STDWEB_PRIVATE.serialize_array = function serialize_array( address, value ) {
var length = value.length;
var pointer = Module.STDWEB_PRIVATE.alloc( length * 16 );
Module.HEAPU8[ address + 12 ] = 7;
Module.HEAPU32[ address / 4 ] = pointer;
Module.HEAPU32[ (address + 4) / 4 ] = length;
for( var i = 0; i < length; ++i ) {
Module.STDWEB_PRIVATE.from_js( pointer + i * 16, value[ i ] );
}
};
// New browsers and recent Node
var cachedEncoder = ( typeof TextEncoder === "function"
? new TextEncoder( "utf-8" )
// Old Node (before v11)
: ( typeof util === "object" && util && typeof util.TextEncoder === "function"
? new util.TextEncoder( "utf-8" )
// Old browsers
: null ) );
if ( cachedEncoder != null ) {
Module.STDWEB_PRIVATE.to_utf8_string = function to_utf8_string( address, value ) {
var buffer = cachedEncoder.encode( value );
var length = buffer.length;
var pointer = 0;
if ( length > 0 ) {
pointer = Module.STDWEB_PRIVATE.alloc( length );
Module.HEAPU8.set( buffer, pointer );
}
Module.HEAPU32[ address / 4 ] = pointer;
Module.HEAPU32[ (address + 4) / 4 ] = length;
};
} else {
Module.STDWEB_PRIVATE.to_utf8_string = function to_utf8_string( address, value ) {
var length = Module.STDWEB_PRIVATE.utf8_len( value );
var pointer = 0;
if ( length > 0 ) {
pointer = Module.STDWEB_PRIVATE.alloc( length );
Module.STDWEB_PRIVATE.to_utf8( value, pointer );
}
Module.HEAPU32[ address / 4 ] = pointer;
Module.HEAPU32[ (address + 4) / 4 ] = length;
};
}
Module.STDWEB_PRIVATE.from_js = function from_js( address, value ) {
var kind = Object.prototype.toString.call( value );
if( kind === "[object String]" ) {
Module.HEAPU8[ address + 12 ] = 4;
Module.STDWEB_PRIVATE.to_utf8_string( address, value );
} else if( kind === "[object Number]" ) {
if( value === (value|0) ) {
Module.HEAPU8[ address + 12 ] = 2;
Module.HEAP32[ address / 4 ] = value;
} else {
Module.HEAPU8[ address + 12 ] = 3;
Module.HEAPF64[ address / 8 ] = value;
}
} else if( value === null ) {
Module.HEAPU8[ address + 12 ] = 1;
} else if( value === undefined ) {
Module.HEAPU8[ address + 12 ] = 0;
} else if( value === false ) {
Module.HEAPU8[ address + 12 ] = 5;
} else if( value === true ) {
Module.HEAPU8[ address + 12 ] = 6;
} else if( kind === "[object Symbol]" ) {
var id = Module.STDWEB_PRIVATE.register_raw_value( value );
Module.HEAPU8[ address + 12 ] = 15;
Module.HEAP32[ address / 4 ] = id;
} else {
var refid = Module.STDWEB_PRIVATE.acquire_rust_reference( value );
Module.HEAPU8[ address + 12 ] = 9;
Module.HEAP32[ address / 4 ] = refid;
}
};
// New browsers and recent Node
var cachedDecoder = ( typeof TextDecoder === "function"
? new TextDecoder( "utf-8" )
// Old Node (before v11)
: ( typeof util === "object" && util && typeof util.TextDecoder === "function"
? new util.TextDecoder( "utf-8" )
// Old browsers
: null ) );
if ( cachedDecoder != null ) {
Module.STDWEB_PRIVATE.to_js_string = function to_js_string( index, length ) {
return cachedDecoder.decode( Module.HEAPU8.subarray( index, index + length ) );
};
} else {
// This is ported from Rust's stdlib; it's faster than
// the string conversion from Emscripten.
Module.STDWEB_PRIVATE.to_js_string = function to_js_string( index, length ) {
var HEAPU8 = Module.HEAPU8;
index = index|0;
length = length|0;
var end = (index|0) + (length|0);
var output = "";
while( index < end ) {
var x = HEAPU8[ index++ ];
if( x < 128 ) {
output += String.fromCharCode( x );
continue;
}
var init = (x & (0x7F >> 2));
var y = 0;
if( index < end ) {
y = HEAPU8[ index++ ];
}
var ch = (init << 6) | (y & 63);
if( x >= 0xE0 ) {
var z = 0;
if( index < end ) {
z = HEAPU8[ index++ ];
}
var y_z = ((y & 63) << 6) | (z & 63);
ch = init << 12 | y_z;
if( x >= 0xF0 ) {
var w = 0;
if( index < end ) {
w = HEAPU8[ index++ ];
}
ch = (init & 7) << 18 | ((y_z << 6) | (w & 63));
output += String.fromCharCode( 0xD7C0 + (ch >> 10) );
ch = 0xDC00 + (ch & 0x3FF);
}
}
output += String.fromCharCode( ch );
continue;
}
return output;
};
}
Module.STDWEB_PRIVATE.id_to_ref_map = {};
Module.STDWEB_PRIVATE.id_to_refcount_map = {};
Module.STDWEB_PRIVATE.ref_to_id_map = new WeakMap();
// Not all types can be stored in a WeakMap
Module.STDWEB_PRIVATE.ref_to_id_map_fallback = new Map();
Module.STDWEB_PRIVATE.last_refid = 1;
Module.STDWEB_PRIVATE.id_to_raw_value_map = {};
Module.STDWEB_PRIVATE.last_raw_value_id = 1;
Module.STDWEB_PRIVATE.acquire_rust_reference = function( reference ) {
if( reference === undefined || reference === null ) {
return 0;
}
var id_to_refcount_map = Module.STDWEB_PRIVATE.id_to_refcount_map;
var id_to_ref_map = Module.STDWEB_PRIVATE.id_to_ref_map;
var ref_to_id_map = Module.STDWEB_PRIVATE.ref_to_id_map;
var ref_to_id_map_fallback = Module.STDWEB_PRIVATE.ref_to_id_map_fallback;
var refid = ref_to_id_map.get( reference );
if( refid === undefined ) {
refid = ref_to_id_map_fallback.get( reference );
}
if( refid === undefined ) {
refid = Module.STDWEB_PRIVATE.last_refid++;
try {
ref_to_id_map.set( reference, refid );
} catch (e) {
ref_to_id_map_fallback.set( reference, refid );
}
}
if( refid in id_to_ref_map ) {
id_to_refcount_map[ refid ]++;
} else {
id_to_ref_map[ refid ] = reference;
id_to_refcount_map[ refid ] = 1;
}
return refid;
};
Module.STDWEB_PRIVATE.acquire_js_reference = function( refid ) {
return Module.STDWEB_PRIVATE.id_to_ref_map[ refid ];
};
Module.STDWEB_PRIVATE.increment_refcount = function( refid ) {
Module.STDWEB_PRIVATE.id_to_refcount_map[ refid ]++;
};
Module.STDWEB_PRIVATE.decrement_refcount = function( refid ) {
var id_to_refcount_map = Module.STDWEB_PRIVATE.id_to_refcount_map;
if( 0 == --id_to_refcount_map[ refid ] ) {
var id_to_ref_map = Module.STDWEB_PRIVATE.id_to_ref_map;
var ref_to_id_map_fallback = Module.STDWEB_PRIVATE.ref_to_id_map_fallback;
var reference = id_to_ref_map[ refid ];
delete id_to_ref_map[ refid ];
delete id_to_refcount_map[ refid ];
ref_to_id_map_fallback.delete(reference);
}
};
Module.STDWEB_PRIVATE.register_raw_value = function( value ) {
var id = Module.STDWEB_PRIVATE.last_raw_value_id++;
Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ] = value;
return id;
};
Module.STDWEB_PRIVATE.unregister_raw_value = function( id ) {
delete Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ];
};
Module.STDWEB_PRIVATE.get_raw_value = function( id ) {
return Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ];
};
Module.STDWEB_PRIVATE.alloc = function alloc( size ) {
return Module.web_malloc( size );
};
Module.STDWEB_PRIVATE.dyncall = function( signature, ptr, args ) {
return Module.web_table.get( ptr ).apply( null, args );
};
// This is based on code from Emscripten's preamble.js.
Module.STDWEB_PRIVATE.utf8_len = function utf8_len( str ) {
var len = 0;
for( var i = 0; i < str.length; ++i ) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
var u = str.charCodeAt( i ); // possibly a lead surrogate
if( u >= 0xD800 && u <= 0xDFFF ) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt( ++i ) & 0x3FF);
}
if( u <= 0x7F ) {
++len;
} else if( u <= 0x7FF ) {
len += 2;
} else if( u <= 0xFFFF ) {
len += 3;
} else if( u <= 0x1FFFFF ) {
len += 4;
} else if( u <= 0x3FFFFFF ) {
len += 5;
} else {
len += 6;
}
}
return len;
};
Module.STDWEB_PRIVATE.prepare_any_arg = function( value ) {
var arg = Module.STDWEB_PRIVATE.alloc( 16 );
Module.STDWEB_PRIVATE.from_js( arg, value );
return arg;
};
Module.STDWEB_PRIVATE.acquire_tmp = function( dummy ) {
var value = Module.STDWEB_PRIVATE.tmp;
Module.STDWEB_PRIVATE.tmp = null;
return value;
};
var HEAP8 = null;
var HEAP16 = null;
var HEAP32 = null;
var HEAPU8 = null;
var HEAPU16 = null;
var HEAPU32 = null;
var HEAPF32 = null;
var HEAPF64 = null;
Object.defineProperty( Module, 'exports', { value: {} } );
function __web_on_grow() {
var buffer = Module.instance.exports.memory.buffer;
HEAP8 = new Int8Array( buffer );
HEAP16 = new Int16Array( buffer );
HEAP32 = new Int32Array( buffer );
HEAPU8 = new Uint8Array( buffer );
HEAPU16 = new Uint16Array( buffer );
HEAPU32 = new Uint32Array( buffer );
HEAPF32 = new Float32Array( buffer );
HEAPF64 = new Float64Array( buffer );
Module.HEAP8 = HEAP8;
Module.HEAP16 = HEAP16;
Module.HEAP32 = HEAP32;
Module.HEAPU8 = HEAPU8;
Module.HEAPU16 = HEAPU16;
Module.HEAPU32 = HEAPU32;
Module.HEAPF32 = HEAPF32;
Module.HEAPF64 = HEAPF64;
}
return {
imports: {
env: {
"__cargo_web_snippet_09675c7ed2827e045dc760aeac3d286437cfbe5e": function($0, $1, $2, $3) {
$1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);$3 = Module.STDWEB_PRIVATE.to_js($3);Module.STDWEB_PRIVATE.from_js($0, (function(){try{return{value:function(){return($1).setAttribute(($2),($3));}(),success:true};}catch(error){return{error:error,success:false};}})());
},
"__cargo_web_snippet_0e54fd9c163fcf648ce0a395fde4500fd167a40b": function($0) {
var r = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (r instanceof DOMException) && (r.name === "InvalidCharacterError");
},
"__cargo_web_snippet_1edaec034bdcb0a749c6d5de76c29f6371afb5a0": function($0) {
var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof Event && o.type === "input");
},
"__cargo_web_snippet_2908dbb08792df5e699e324eec3e29fd6a57c2c9": function($0) {
var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof HTMLInputElement);
},
"__cargo_web_snippet_3c5e83d16a83fc7147ec91e2506438012952f55a": function($0) {
var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof Element);
},
"__cargo_web_snippet_614a3dd2adb7e9eac4a0ec6e59d37f87e0521c3b": function($0, $1) {
$1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).error;})());
},
"__cargo_web_snippet_6fcce0aae651e2d748e085ff1f800f87625ff8c8": function($0) {
Module.STDWEB_PRIVATE.from_js($0, (function(){return document;})());
},
"__cargo_web_snippet_72fc447820458c720c68d0d8e078ede631edd723": function($0, $1, $2) {
console.error( 'Panic location:', Module.STDWEB_PRIVATE.to_js_string( $0, $1 ) + ':' + $2 );
},
"__cargo_web_snippet_80d6d56760c65e49b7be8b6b01c1ea861b046bf0": function($0) {
Module.STDWEB_PRIVATE.decrement_refcount( $0 );
},
"__cargo_web_snippet_91749aeb589cd0f9b17cbc01b2872ba709817982": function($0, $1, $2) {
$1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){try{return{value:function(){return($1).createElement(($2));}(),success:true};}catch(error){return{error:error,success:false};}})());
},
"__cargo_web_snippet_97495987af1720d8a9a923fa4683a7b683e3acd6": function($0, $1) {
console.error( 'Panic error message:', Module.STDWEB_PRIVATE.to_js_string( $0, $1 ) );
},
"__cargo_web_snippet_99c4eefdc8d4cc724135163b8c8665a1f3de99e4": function($0, $1, $2, $3) {
$1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);$3 = Module.STDWEB_PRIVATE.to_js($3);Module.STDWEB_PRIVATE.from_js($0, (function(){var listener=($1);($2).addEventListener(($3),listener);return listener;})());
},
"__cargo_web_snippet_9f22d4ca7bc938409787341b7db181f8dd41e6df": function($0) {
Module.STDWEB_PRIVATE.increment_refcount( $0 );
},
"__cargo_web_snippet_ab05f53189dacccf2d365ad26daa407d4f7abea9": function($0, $1) {
$1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).value;})());
},
"__cargo_web_snippet_afafe9a462a05084fec65cacc7d6598e145ff3e3": function($0, $1, $2) {
$1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).createTextNode(($2));})());
},
"__cargo_web_snippet_b06dde4acf09433b5190a4b001259fe5d4abcbc2": function($0, $1) {
$1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).success;})());
},
"__cargo_web_snippet_d5e30f74cb752784e06bd97a37b1f89b6c3433a7": function($0, $1, $2) {
$1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).getElementById(($2));})());
},
"__cargo_web_snippet_dc2fd915bd92f9e9c6a3bd15174f1414eee3dbaf": function() {
console.error( 'Encountered a panic!' );
},
"__cargo_web_snippet_e741b9d9071097746386b2c2ec044a2bc73e688c": function($0, $1) {
$0 = Module.STDWEB_PRIVATE.to_js($0);$1 = Module.STDWEB_PRIVATE.to_js($1);($0).appendChild(($1));
},
"__cargo_web_snippet_e9638d6405ab65f78daf4a5af9c9de14ecf1e2ec": function($0) {
$0 = Module.STDWEB_PRIVATE.to_js($0);Module.STDWEB_PRIVATE.unregister_raw_value(($0));
},
"__cargo_web_snippet_f765b15a1a1b5cd266e922e6fca98dd570f17edc": function($0, $1) {
$0 = Module.STDWEB_PRIVATE.to_js($0);$1 = Module.STDWEB_PRIVATE.to_js($1);($0).textContent=($1);
},
"__cargo_web_snippet_ff5103e6cc179d13b4c7a785bdce2708fd559fc0": function($0) {
Module.STDWEB_PRIVATE.tmp = Module.STDWEB_PRIVATE.to_js( $0 );
},
"__web_on_grow": __web_on_grow
}
},
initialize: function( instance ) {
Object.defineProperty( Module, 'instance', { value: instance } );
Object.defineProperty( Module, 'web_malloc', { value: Module.instance.exports.__web_malloc } );
Object.defineProperty( Module, 'web_free', { value: Module.instance.exports.__web_free } );
Object.defineProperty( Module, 'web_table', { value: Module.instance.exports.__indirect_function_table } );
__web_on_grow();
Module.instance.exports.main();
return Module.exports;
}
};
}
));
}));

Binary file not shown.

View file

@ -0,0 +1,52 @@
+++
title = "enterprise: a new ui framework"
date = 2020-02-11
draft = true
template = "post.html"
[taxonomies]
tags = []
[extra]
toc = true
+++
This past weekend, while on my trip to Minneapolis, I completed a very early prototype of "enterprise", a new UI framework I've been kind of envisioning over the past couple of weeks. While the UI framework is mainly targeted at web apps, the hope is that with a bit more effort, native UIs can be produced with almost no changes to existing applications. Before I begin to describe how it works, I'd like to acknowledge [Nathan Ringo][1] for his massively helpful feedback in both the ideation and the implementation process.
## Goals of the project
* **Complete separation of business logic from UI.** Theoretically, one could completely retarget the application to a completely different platform (mobile, web, native, something new that will pop up in 5 years), without changing any of the core logic. As enterprise grows to include a backend, this should be true of the backend as well. It does this by introducing [DSL][2]s that are completely architecture-independent.
* **Frontend relationships should be as static as possible.**
## Prototype
The prototype for experimenting is a simple "Hello, world" application. If you've looked at any web framework before, this is probably one of the simplest examples of bindings: type something into a box and watch as the text magically populates with whatever you wrote in the box. If you're using a WASM-compatible browser with JavaScript enabled, you should be able to try out the demo in real-time:
<div id="app"></div>
<script type="text/javascript" src="helloworld.js"></script>
OK, you say, but I could implement this in 3 lines of JavaScript.
```js
inputEl.addEventListener("change", () => {
spanEl.innerText = inputEl.value;
});
```
Surely, this works, but it doesn't scale. If you try to write a page full of these kind of bindings directly using JavaScript, you're either going to start running into bugs or building up a pile of unmaintainable spaghetti code.
So how does enterprise represent this? Well, the enterprise DSL has no concrete syntax yet, but if it did, it would look something like this:
```
model {
name: String,
}
view {
<TextBox bind:value="name" />
Hello, {name}!
}
```
[1]: https://remexre.xyz
[2]: https://en.wikipedia.org/wiki/Domain-specific_language

View file

@ -15,6 +15,7 @@
Posted Posted
{% if page.extra.author %}by {{ page.extra.author }}{% endif %} {% if page.extra.author %}by {{ page.extra.author }}{% endif %}
on {{ page.date }} on {{ page.date }}
- {{ page.reading_time }} min read
</small> </small>
{% endif %} {% endif %}