satoshinm / WebSandboxMC

Bukkit plugin providing a web-based interface with an interactive WebGL 3D preview or glimpse of your server 🕷⏳📦 ⛺
https://www.spigotmc.org/resources/websandboxmc.39415/
MIT License
19 stars 5 forks source link

By default serve WebAssembly build to client, with an asmjs fallback #57

Closed satoshinm closed 7 years ago

satoshinm commented 7 years ago

Currently WebSandboxMC ships the release-build-js version of https://github.com/satoshinm/NetCraft which is optimized JavaScript, essentially asmjs, but the wasm-build (WebAssembly) is smaller so should load/download faster, best serve it by default if possible.

release-build-js $ ls -lh craft.*
-rw-r--r--  1 admin  staff   101K May 15 21:53 craft.html
-rw-r--r--  1 admin  staff    61K May 15 21:53 craft.html.mem
-rw-r--r--  1 admin  staff   3.7M May 15 21:53 craft.js

wasm-build $ ls -lh craft.*
-rw-r--r--  1 admin  staff   100K May 15 21:53 craft.html
-rw-r--r--  1 admin  staff   1.1M May 15 21:53 craft.js
-rw-r--r--  1 admin  staff   1.4M May 15 21:53 craft.wasm

The only complication is providing a non-WebAssembly fallback. There are polyfills but probably better to bundle both sets of source files, and choose wasm-build/craft.js if WebAssembly, otherwise release-build-js/craft.js.

satoshinm commented 7 years ago

To check if the browser supports wasm, if (window.WebAssembly)


There is a difference in shell.html, but seems to be only for the memory initializer:

wasm-build $ diff -ur ../release-build-js/craft.html ../wasm-build/craft.html 
--- ../release-build-js/craft.html  2017-05-20 21:20:02.000000000 -0700
+++ ../wasm-build/craft.html    2017-05-22 21:57:20.000000000 -0700
@@ -1291,25 +1291,6 @@
         };
       };
     </script>
-    <script>
-
-          (function() {
-            var memoryInitializer = 'craft.html.mem';
-            if (typeof Module['locateFile'] === 'function') {
-              memoryInitializer = Module['locateFile'](memoryInitializer);
-            } else if (Module['memoryInitializerPrefixURL']) {
-              memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
-            }
-            var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest();
-            meminitXHR.open('GET', memoryInitializer, true);
-            meminitXHR.responseType = 'arraybuffer';
-            meminitXHR.send(null);
-          })();
-
-          var script = document.createElement('script');
-          script.src = "craft.js";
-          document.body.appendChild(script);
-
-</script>
+    <script async type="text/javascript" src="craft.js"></script>
   </body>
 </html>

This is from --memory-init-file 1

satoshinm commented 7 years ago

From https://github.com/kripken/emscripten/wiki/WebAssembly:

Note that the methods you specify affect what is emmitted. For example, -s "BINARYEN_METHOD='native-wasm,asmjs'" will try native support, and if that fails, will use asm.js.

but it says this generates a "compromise" build, and recommends:

if you want maximal performance, instead of using native-wasm,asmjs (which would try WebAssembly and fall back to asm.js if necessary), you can create two separate builds as described earlier, and run the asm.js one if WebAssembly is not present in the user's browser.

satoshinm commented 7 years ago

Something like this works (manually edited craft.html output, two builds side-by-side):

    <script>
          var script = document.createElement('script');
          if (window.WebAssembly) {
              (function() {
                var memoryInitializer = 'craft.html.mem';
                if (typeof Module['locateFile'] === 'function') {
                  memoryInitializer = Module['locateFile'](memoryInitializer);
                } else if (Module['memoryInitializerPrefixURL']) {
                  memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
                }
                var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest();
                meminitXHR.open('GET', memoryInitializer, true);
                meminitXHR.responseType = 'arraybuffer';
                meminitXHR.send(null);
              })();

              script.src = "craftw.js";
          } else {
              script.src = "craft.js";
          }
          document.body.appendChild(script);

</script>

is there any loss of not having the <script async> attribute? https://www.w3schools.com/tags/att_script_async.asp says "If async is present: The script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing)" - this may not apply to document.createElement('script')?