-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow async loading of aframe library and interoperation with ES module libraries #5419
Conversation
@@ -11,6 +11,17 @@ var MULTIPLE_COMPONENT_DELIMITER = '__'; | |||
var OBJECT3D_COMPONENTS = ['position', 'rotation', 'scale', 'visible']; | |||
var ONCE = {once: true}; | |||
|
|||
var _resolveReadyPromise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can name just resolveReadyPromise
. We don't use ampersand
Thanks so much! @vincentfretin @diarmidmackenzie what do you think? Sorry for the ping. Have the feeling you know more about this than me :) At first glance it feels weird tying the logic to the Entity load when async is supposed to be at library level. But maybe. Not sure yet. |
The changes looks ok. I don't really have better. I guess this PR fixes this old issue #4038 |
Just curious how a complete example would look like?
I'm still getting familiar with ES6 modules. Would be nice to see one full basic example: https://glitch.com/~aframe |
You need to define the importmap. In his linked example, this is defined: <script type="importmap">
{
"imports": {
"@lookingglass/webxr": "./lib/webxr.module.js",
"aframe": "./lib/aframe-master.js"
}
}
</script> You can replace the path by a jsdelivr url. |
Wouldn't be better to tie the promise to A-Frame loading as a whole vs when the first entity connects? For example here: https://github.com/aframevr/aframe/blob/master/src/index.js#L95 |
You could use the importmaps or, more typically, It'd look like the full JS url: await import("https://aframe.io/releases/1.5.0/aframe.min.js") The
Ah, the change I'm proposing is to run the entity connectedCallback after A-Frame loading has completed. That said, the problem it works around is that the connectedCallback expect that the A-Frame loaded has completed, but these connectedCallback are being run during registerElement because the DOM is already available during the async loading. Typically, the steps look like:
However, in the async/module flow, the steps look like:
The problem is that in Step 3, not all of the aframe code has executed. So things like the camera weren't registered. This is only a problem because the connectedCallback was called during parsing/execution of the aframe script. Hope this provides an explanation of what's going on. |
There is already logic in place to defer the initialization till the As for the magic
This example doesn't work in Firefox for me, but does on Chrome. Didn't dive into the cause, but it seems there is some difference in execution order between the two. As an aside, the way I generally workaround the issue is by placing the scene in a template and adding it to the DOM after loading and registering all dependencies: <html>
<head>
<script type="importmap">
(...)
</script>
<script type="module">
await import("aframe");
// Load dependencies
const sceneTemplate = document.getElementById('scene');
document.body.appendChild(sceneTemplate.content)
</script>
</head>
<body>
<template id="scene">
<a-scene>
<a-box id="box" color="red" position="0 1.6 -2"></a-box>
</a-scene>
</template>
</body>
</html> |
var _resolveReadyPromise; | ||
var isReady = false; | ||
var isReadyPromise = new Promise(function (resolve) { | ||
_resolveReadyPromise = resolve; | ||
}); | ||
|
||
function ready () { | ||
isReady = true; | ||
_resolveReadyPromise(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this again, it might make more sense for this "ready" logic to live in its own file/module that just governs whether the entire aframe library is ready. I can tidy this up.
This initial PR was only to gather and understand if there's interest/appetite for such a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good. thanks. In an ideal world we would have a single build that can be loaded via modules (export, import) or script tag. As far as I know that's not possible, right?
Nice workaround. Hopefully we can find a way for A-Frame to work seamlessly with both modules and script tags. I would like to also avoid two separate builds (aframe.js, aframe.module.js) but not sure if possible. Biggest downside of ES6 modules is that how it seems to split JS space in two: pre and post modules. Also I think there's still valuable simplicity on loading JS with just a <script> tag and no additional incantations. |
not sure where the problem is at the moment what still works is |
i think a good example is model-viewer https://modelviewer.dev/ |
Let me know if you need help or any questions to move this along. Thanks! |
@arpu In your glitch example you don't async load any new component, so of course you don't have any issue. @chrisirhc on my comment #5419 (comment) need to test to async load a system. |
Thanks @vincentfretin you are right not trying to load second componet, and now i see the problem |
Hi, do you mind sharing an example on how I can do this? |
You can try loading the uvscroll.js as a module, that includes a uv-scroll system and uv-scroll component, see c-frame/sponsorship#15 |
There are some pending changes here |
I created a glitch with the same example as @chrisirhc and the uv-scroll system/component, it's working properly as far as I can tell. |
@chrisirhc There are few pending changes from the review (e.g underscore on name variables). Do you want to finish it up? Thanks so much! |
Hi there, apologies for the radio silence. I was stuck on a blurness issue ( mkkellogg/GaussianSplats3D#65 (comment) ) after finding out that aframe using a pretty old/forked version of ThreeJS so I've had to look elsewhere despite hacking this fix together. I might not get back to this in the near future. Feel free to close this out. |
@chrisirhc FYI A-Frame master is on latest THREE r162. Can use builds linked in commits https://github.com/aframevr/aframe/commits/master/ |
Also you can close this PR now that #5481 is merged. |
Got it! Thanks @mrxz for getting the change to the finish line! |
Description:
This allows interop with ES module libraries such as webxr.
ES modules are a part of the Web Component spec but it's a bit surprising that aframe doesn't play well with other Web Components that rely on ES modules.
It allows aframe to be loaded as a module or deferred on page load.
Currently, aframe needs to be loaded synchronously. Adding
async
ordefer
ortype="module"
can causeaframe
library to fail in many different ways such as:a-scene
is registered and connectedCallback hook does not find the camera component as it hasn't been registereda-entity
's connectedCallback hook unable to find thata-scene
is initializedThese proposed changes allow the following code snippet to run:
Note that
new LookingGlassWebXRPolyfill()
needs to run before importing aframe in order to polyfill/override webxr for looking glass capabilities.Example of this working is at https://chrisirhc.github.io/looking-glass-viewer-experiments/aframe.html .
Changes proposed:
doConnectedCallback
untilready
is called ifwindow.AFRAME_ASYNC
is set to a truthy valueThis is a strawman implementation. I'm not sure how to name these API surfaces and open to suggestions.
Alternatives considered