Looking for a way to import modules dynamically

Hello three.js heroes

I should probably start with the fact that I use Three.js in an unusual way
The lib code is inside the script element, without any src attributes, directly.
Don’t ask why, it just has to work this way for this case :nerd_face:

So the question is how to use the modules? What workarounds can we apply? Thanks for any information

Well, if you do one import in some custom unusual way - be prepared that you’ll need to do the rest in the same, unusual way. So if you inline three module, why not just inline other necessary submodules as well?

You may also try using import maps, but hard to say if it’d work with your custom solutions.

1 Like

I’ve tried this, adding ‘FirstPersonControls.js’ as an inline-script
The problem is that from the very beginning the code inside already requires ‘three’ as a module

import {
	MathUtils,
	Spherical,
	Vector3
} from 'three';

Then you can just remove this part - if you’re inlining three, you should have all of these already defined in the same scope :thinking:

I’ve done this before. Not quite proud of it.

Apart from removing the import statement, you also have to remove the export statement as well as to fix all imported names, if needed. For example, in my case I had to rename all usages of Vector3 into THREE.Vector3, all Mesh into THREE.Mesh and so on. But as @mjurczyk, you would have to spend some time manually editing the source code.

Oh, if you import a module that imports other modules, you have to do this recursively for all modules.

Maybe it would be easier to pick a non-moduled version of Three.js and its libraries (e.g. r147). Then you can manually merge all files into one script.

PS. The title of the thread does not correspond to the question in the post.

1 Like

Thanks for the suggestions, I’ll give it a try!

assuming you have <script>your code here</script> situation - yes, you could create the type=module script element, put the code there and append it to document.head or .body

const s = document.createElement('script');
s.type = 'module';
s.textContent = 'import { REVISION } from \'https://threejs.org/build/three.module.js\'; console.log(REVISION);';
document.head.appendChild(s);
1 Like

Deleted import and export from these modules

<script src="Quaternion.js"></script>
<script src="Vector3.js"></script>
<script src="Spherical.js"></script>
<script src="MathUtils.js"></script>
<script src="FirstPersonControls.js"></script>

So far, no errors, and the most interesting thing: I only needed FirstPersonControls.js, which needed 3 other modules, and another one needed another one, you also need to hit the sequence - otherwise it won’t work.

1 Like

it won’t work. modules and IIFE (immediately invoked function expressions) don’t mix. you either use one or the other. it would take you days to manually edit and hack modules back into IIFE and it’s not enough to remove imports/exports, you’d have to prefix every threejs construct with THREE. and make sure they get loaded in specific order, which — considering cyclic dependencies will be a nice puzzle.

IIFE has been abolished a decade ago, threejs has stopped supporting it. it was an anti pattern if there ever was one — why you want to mess that is beyond me, but just use a threejs from a year back and you’ll be OK.

Yeah… I started to write the code and errors appeared, unfortunately I can only use the r149 version, will have to try something else :thinking:

I can’t move to a new blob either, hmm

149 is a module, i’d say chances are slim to none you’d get this converted into IIFE again. it’s kind of awfully specific, why 149, why does it need to work like in the earliest days of computing. i know we’re not supposed to question anything here but did they tell you at the job? :laughing:

Try the demoduler, although it may not work for any file.

so you are basically doing rollup’s work by hand :smiling_face_with_tear:

2 Likes

it seems like it converts just fine, 3js devs just do not want to do it any more. so far the only complaint I saw was about top-level “await” somewhere in webgpu code

How do you convert esm modules to iife? Is it with the tool that @PavelBoytchev made?

Nvm…I agree with the guy above…this post is not about the title

I made an example using COW language before here you can check the source code the entire code (including all the three dependencies) is reduced to uppercase / lowercase character variations of the word “Moo”… at the end of all that i just used

const encodedJs = encodeURIComponent(STDOUT);
const dataUri = 'data:text/javascript;charset=utf-8,' + encodedJs;
import(dataUri);

this will allow you to dynamically import modules without having to use any iife stuff, if i remember rightly the only caveat was that three imports had to be absolute URL paths such as CDN links…

PS: you can decode the COW string in the source code here if you paste the COW sting in the second box…

1 Like

i just realised the question is not really related to the title… did you…

as @mjurczyk suggested? this would surely work for your use case and be a lot easier than converting modules, three has been written in a pretty clever and efficient way…

<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap"> 
  {
    "imports": {
      "three": "../build/three.module.js",
      "three/addons/": "./jsm/"
    }
  }
</script>

<script>

  //your inline code here using import statements...

</script>


still rollup - just tell it you want format = iife and build again.

1 Like

@makc3d
I believe that could work…however I’ve never seen an example of that before…ever