Hacker News new | ask | show | jobs
by xscott 605 days ago
> This is what StackOverflow tells me (2020)

Web Workers can't directly access the DOM in JavaScript either. This is not a WebAssembly problem. If you want a Web Worker to manipulate your document, you're going to post events back and forth to the main thread, and Web Assembly could call imported functions to do that too.

I don't even know what he's on about with Preact/React...

Save the following as "ergonomic.html" and you'll see that WebAssembly is manipulating the DOM.

    <!doctype html><title>Not that hard</title> 
    <script type="module"> 
     
    document.addEventListener('DOMContentLoaded', () => { 
        /* Compile this module with wat2wasm to make the binary below: 
     
            (module 
                (import "env" "easy" (func $easy (param i32))) 
                (func $run (param) (result) 
                    (call $easy (i32.const 123)) 
                    (call $easy (i32.const 456)) 
                ) 
                (memory $mem 1) 
                (export "run" (func $run)) 
                (export "mem" (memory $mem))  
            ) 
        */ 
     
        const binary = new Uint8Array([ 
              0,   97,  115,  109,    1,    0,    0,    0,   
              1,    8,    2,   96,    1,  127,    0,   96, 
              0,    0,    2,   12,    1,    3,  101,  110,  
            118,    4,  101,   97,  115,  121,    0,    0,  
              3,    2,    1,    1,    5,    3,    1,    0, 
              1,    7,   13,    2,    3,  114,  117,  110, 
              0,    1,    3,  109,  101,  109,    2,    0, 
             10,   14,    1,   12,    0,   65,  251,    0,  
             16,    0,   65,  200,    3,   16,    0,   11,   
        ]); 
     
        const imports = { 
            easy(arg) { 
                const div = document.createElement("div"); 
                div.textContent = "DOM this: " + String(arg); 
                document.body.appendChild(div); 
            } 
        }; 
     
        const module = new WebAssembly.Module(binary);  
        const instance = new WebAssembly.Instance(module, { env: imports });  
        instance.exports.run(); 
    });
    
    </script>

That `easy(arg)` function could do much more elaborate things, and you could pass lots of data in and out using the memory export.

I'd like to believe a simple standalone example like this would be enough to get people to shutup about the DOM thing, but I know better. It'll be the same people who think you need to link with all of SDL in an Emscripten project in order to draw a line on a canvas.

> This feels like "we can have DOM access at home" meme.

And I'm sure somebody (maybe you) will try to move the goal posts and claim some other meme applies.

3 comments

> I don't even know what he's on about with Preact/React...

Around 10 years ago, I was having lunch in a food court and overheard "Luckily I don't have to use javascript, just jquery".

Around 5 years ago, a co-worker admitted he still had issues distinguishing what functionality was python and what came from Django (web framework), despite having used them both daily for years. He thought it was because he learned both at the same time.

I wouldn't be surprised if this was more of the same, and just getting worse as we pile more and more abstractions on top.

(your example becomes a lot easier to read on a computer instead of a phone) but i'd also like to thank you for patiently answering all the questions (esp here: https://news.ycombinator.com/item?id=41961489 and https://news.ycombinator.com/item?id=41964500 (unfortunately the latter comment has been flagged. turn on showdead to read it)).

but what bothers me a bit is that this example still uses custom javascript code.

i tried to find and answer but essentially what appears to be missing is the ability to access js objects from wasm. to access the document object it looks like i need a wrapper function in js:

    jsdocument(prop, arg){
        document[prop](arg)
    }
so far so good, i can import this jsdocument() function and use it to all any property on the document object, but if document[fun](arg) returns another DOM object, then what?

maybe more elaborate:

    callDOMobj(prop, arg, prop2, arg2){
        document[prop](arg)[prop2](arg2)
    }
i can call this function with the arguments ("getElementById", "foo", "append", "<div>more foo</div>") in any WASM language and it will result in calling document.getElementById("foo").append("<div>more foo</div>"); which allows some basic DOM manipulation already. but then i want to continue with that object so maybe i can do this:

    getDOMobj(prop, arg){
        var len = objlist.push(document[prop](arg))
        return len-1;   
    }

    callDOMobj(pos, prop, arg){
        objlist[pos]["prop"](arg)
    }
can you see what i am getting at here? building up some kind of API that allows me to access and manipulate any DOM object via a set of functions that i can import into WASM to work around the fact that i can't access document and other objects directly. it looks like this is similar to this answer here: https://stackoverflow.com/a/53958939

solving this problem is what i mean when i ask for direct access to the DOM. i believe such an interface should be written only once so that everyone can use it without having to reinvent it like it appears to be necessary at the moment.

> i'd also like to thank you for patiently answering all the questions

It's nice of you to say so. Thank you.

> can you see what i am getting at here?

I mostly can, but I'm not sure we're clear what we're talking about yet.

I see a lot of people who repeat something about "WebAssembly isn't usable because it can't manipulate the DOM". Ok, so I show an example of WebAssembly manipulating the DOM. That should put that to rest, right? If not, I'm curious what they meant.

> building up some kind of API that allows me to access and manipulate any DOM object via a set of functions that i can import into WASM to work around the fact that i can't access document and other objects directly,

This is a shortcoming in the language implementation, or the library for the language. The machinery is already there at the WebAssembly level. If your language is low level (Rust, C, or C++), and doesn't have what you want, you could roll your own. If your language is high level (Python or Lua), you're at the mercy of the person who built your version of Python.

The core of WebAssembly is a lot like a CPU. It's analogous to AMD64 or AArch64. It'd be weird to say you need changes to your CPU just to use a function called `getElementByName()` or `setAttribute()`. Some WebAssembly extensions have added features to make that "CPU" more like a Java style virtual machine. There are (or will be) garbage collected references to strings, arrays, and structs. This might make it better for implementing Go and Java style languages, and it could help with a fresh implementation of Python or Pike too. And maybe some of those changes will give controlled access to JavaScript style objects.

There's a last discussion to be had about performance. Maybe the bridge between WebAssembly imports and exports is too slow for intensive use. That's a debate that should be backed up with benchmarks of creative solutions. Maybe accessing JavaScript strings is so common, so important, and so slow that it really does require an enhancement to the standard.

i am talking about a js library of generic functions that can be imported from wasm to make DOM access easier. handling of string arguments still needs to be solved (i am guessing the shared memory access is the right place for that) and the respective functions on the wasm side need to be implemented for each target language so that DOM access in the target language becomes natural and easy to use.
If you picked a language that gave you low level control, and if you had strong opinions about what you wanted, you could probably write that JS library in a weekend or two. Strings and arrays through shared memory. Maybe use a JS Map of integers to act as handles mapping to JS Objects.
Is this sarcasm I might be missing?

Thanks for confirming that WebAssembly still cannot manipulate DOM in 2024.

It can only call custom javascript functions that manipulate DOM AND I need to write some arcane function signature language for every DOM manipulating function I want to call.

I'll give another 4 years and see if they fixed this.

> I need to write some arcane function signature language for every DOM manipulating function

You really don't know that you can create WebAssembly in other languages?!? I used WAT to keep the example short, but that's clearly lost on you.

> I'll give another 4 years and see if they fixed this.

In that time, there are lot of things you could be learning. Embracing ignorance and belligerence isn't like to serve you well in the long term.