Await rhino3dm.js wasm import

By design, the rhino3dm javascript package has to be initialized (rhino3dm().then(rhino => { // do rhino stuff })) before being used. This is a wasm limitation and is all fine. You can even store the value in the .then ‘callback’ to run wasm functionality synchronously afterwards.

I have been suffering in silence, though, because the emscripten tool generates a promise-like module that you cannot await.

Finally came across this issue and wanted to share a workaround that just made my day.

import rhino3dm from 'rhino3dm'

// In some async context
await rhino3dm().then(rhino => {
    // Do something with rhino
    delete rhino['then']
}

This feels like the most sinful javascript I’ve ever seen but it works, even after multiple calls. I store the rhino module somewhere and run things synchronously from there.

2 Likes

Thanks for the tip @Chuck_Driesler! I ran into this myself and it’s frustrating! We’ll have to experiment with the latest version of emscripten to see if it’ll resolve these issues for us as promised

For sure! They actually just recently merged a fix for this. I’m not sure what it changes on your end, or if it’s live yet, but it looks promising.

Perfect, thanks! I was now struggling with this for days! Every time I tried to use await, it got stuck in limbo, but now it finally resolves!

Since I’m using SvleteKit with dynamic routes, I wasn’t able to make it work with the npm package, but if someone comes over the same problem, here was my solution with the help of @Chuck_Driesler s input, hope it might help someone

function initRhino() {
		// ref: https://github.com/mcneel/rhino3dm/blob/main/docs/javascript/RHINO3DM.JS.md
		// ref: https://discourse.mcneel.com/t/await-rhino3dm-js-wasm-import/101585

		return new Promise((resolve, reject) => {
			// Check if Rhino3dm is already loaded
			if (window.Rhino3dm) {
				console.log('Rhino3dm is already loaded.');
				resolve(window.Rhino3dm);
				return;
			}

			// Create and append the script
			const script = document.createElement('script');
			script.src = 'https://files.mcneel.com/rhino3dm/js/latest/rhino3dm.js';
			document.head.appendChild(script);

			script.onerror = () => {
				console.error('Failed to load the Rhino3dm script');
				reject(new Error('Failed to load the Rhino3dm script'));
			};

			script.onload = () => {
				console.log('Rhino3dm script loaded.');

				if (typeof window.rhino3dm !== 'function') {
					console.error('rhino3dm initialization function not found');
					reject(new Error('rhino3dm initialization function not found'));
					return;
				}

				let modulePromise = window.rhino3dm();
				if (modulePromise && modulePromise.then) {
					modulePromise.then((module) => {
						console.log('Rhino3dm module loaded.', module);
						delete module['then'];
						resolve(module); // Resolve the promise with the Rhino3dm module
					});
				} else {
					console.error('window.rhino3dm did not return a promise.');
					reject(new Error('window.rhino3dm did not return a promise.'));
				}
			};
		});
	}
1 Like