Bug: importmap isn't suppored by Firefox and Safari

I get TypeError: Module specifier, 'three-nodes/core/NodeFrame.js' does not start with "/", "./", or "../".

The following (from your examples) is not suppored by Safari:

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

How can this be fixed?

I think Github repo needs a fix since importmap is not a standard and only Edge and Chrome support it so far: "importmap" | Can I use... Support tables for HTML5, CSS3, etc

I included <script async src="https://ga.jspm.io/npm:es-module-shims@1.5.17/dist/es-module-shims.js"></script> but it still doesn’t work.

My app just doesn’t launch in Safari and Firefox but it works in Edge and Chrome.

I just realized that none of these official demos work in Safari or Firefox.

Example:
https://threejs.org/examples/?q=nodes#webgl_nodes_materials_physical_clearcoat

This shows a black page for me in Firefox:

This is not really a bug, more like a difference between browser implementations. The CanIUse site you linked to also gives the solution to make the Three.js examples you referred to work in Firefox: you simply need to set the dom.importMaps.enabled flag in about:config.

So, just open a new tab in Firefox, type about:config in the address bar, look for importMaps and double click it to set it to true. Refresh the Three.js examples link and it will work - it does for me as well, after setting up Firefox like this.

P.S. I don’t know about Safari, never used it, never owned or will own a Mac, and so on. Maybe someone else could cover this part, if a solution exists in this case, that is.

1 Like
  1. I want to run this on iPhone which doesn’t have about:config.
  2. And it’d be good if I could code an app and have it working for everyone without any special additional config for production website but that’s not the case currently (and the only reason is that THREE decided to make it not work by using unsupported features when they could make it work so it’s a bug to me).
  1. Ah, I see. I have no idea about how to make it work on an iPhone, but I can confirm “some” of the Three.js stuff works on my Android device - didn’t investigate which of them do and which don’t, as I prefer running 3D on my laptop instead.

  2. I’m 95% in agreement with you here. All these obstacles to making something (that should easily function) work are annoying. I even expressed a similar view to yours on StackOverflow when it came to Three.js. I guess they’re just trying to be up to date with the way of dealing with stuff in JS nowadays, but at the cost of making this harder (to put it lightly) than it should be… :thinking:

One more thing, regarding not having about:config on iPhone: if it can be done on Firefox for the iPhone (it certainly can be done on Android), maybe you can request “the desktop version of the page” from the browser’s menu (this is how it’s called, as far as I remember), and there you might be able to have more configuration options, except that the page won’t automatically fit your phone and such since it will run as if on a desktop device.

This doesn’t quite solve the issue, but just in case it helps…

The import map “shim” included on these examples is supposed to make it work in browsers that don’t support import maps… I think there may indeed be a bug, or some other limitation here, it seems to just be affecting the examples using the material nodes system.

In any of my own projects I would use some sort of bundler like Vite, to compile all the imports into a bundle and deploy them together, in that case the browser support for import maps doesn’t matter, I don’t need a shim, and things typically load more quickly.

Thanks for your help.

iPhone has “experimental features” list in “Settings” but “import maps” doesn’t exist at all so it can’t be enabled even then.

iOS/Safari = doesn’t work (can’t be enabled)
iOS/Chrome = doesn’t work (can’t be enabled)
Mac/Safari = doesn’t work (can’t be enabled)
Windows/Firefox = doesn’t work (can be enabled)

Android/Chrome = works
Windows/Chrome = works
Windows/Edge = works

In any of my own projects I would use some sort of bundler like Vite, to compile all the imports into a bundle

I’m currently exploring webpack to generate bundle.js but I also use live reload on every file change and I want to use the Console to debug JavaScript (I need separate files) so such workflow with compiling bundle.js via Node.js is… not very good :frowning: And it’s a lot of complicated additional setup and management :frowning:

I would have to have bundle.js for iPhone and separate files for Windows/Chrome development.

(Also, webpack actually takes like 5-10 seconds to compile bundle.js so I’d lose automatic live reload on both iPhone and Windows/Chrome.)

Some related topics here, here, here (yeah, I know, not that trustworthy, but anyway), or here, in case an answer can be found buried there.

It seems running Three.js on iPhone is a case of some things work, some don’t. Unfortunately I couldn’t find much about the specific iPhone and import maps topic. :confused:

Thanks, so far everything was working fine for me on iPhone until I added “importmap” in <head> which makes the app not open.

The preferred solution would be to remove importmap from github repo and reference everything by relative paths.

That would fix many problems for many people.

Yep, indeed - not sure the devs will share that opinion though. For the record, Three.js itself does work without import maps (last time I checked) if using the Three.js file instead of Three.module.js one and adding it as a separate <script> in the HTML (hopefully I remember correctly that part, since I don’t currently use it anymore). I guess it’s the other additions to Three.js (like the controls, for example) that require ES6 module syntax, and by extension, import maps.

I tried to avoid import maps myself when starting with Three.js but gave up on it. Some of the “solutions” I was reading at the time mentioned rewriting stuff to use require instead of import, or in any case, something similar. It was too much trouble for me to even think about such methods, so between the N workarounds involving CORS and the workarounds related to ES6 module syntax and import maps, here I am. All these little things make it harder for the user / developer, and as a result also prevent a wider adoption of the library (the other being the techincal math involved).

Unfortunately, this causes larger issues with dependencies, build tools, and bundlers.

I strongly encourage using build tooling like Vite.js, for any JavaScript work involving dependencies. Doing so will avoid any need for import maps or modifications to these imports.

For those prefer not to use build tools, you will either need to use an import map, or to modify imports from ‘three’ to relative imports in the files you are depending on.

I would emphasize that import maps do appear to work with all examples except those using material nodes, so there is almost certainly a bug you could report to three.js about those specific examples, and this could likely be fixed. The browser itself does not need to support import maps, the import “shim” handles that.

1 Like

A little question, if I may, since I didn’t work with “bundles”, “shims” and all these “new” ways of making things that used to work fine right off the bat 5 or 10 years ago work again: isn’t bundling or shimming (sorry, not an expert in such semantics) a problem when debugging? I mean, as far as I know, these tools basically “pack” all your JS files / modules / dependencies into a single file / source that can be then used instead of the former multiple file system. While it may be suited for the final version of those JS dependencies, what happens if you still need to modify or develop those dependencies and use the packed result at the same time? Is the bundling / packing instantaneous and happening every time you run your main module in a page or it’s something similar to packing files in a .zip in that it takes time and the result is unintelligible to be edited, developed further, etc? Also, does it need an active internet connection, if by any chance that packing is done on a server, or it can be performed locally / offline?

Sorry for the side question, but I’m just curious. I would have reported the assumed bug myself on GitHub if I had an iPhone or a Mac along with Firefox / Safari in order to replicate the issue, unfortunately I don’t, so it’s up to the OP or someone else running on similar systems.

“bundles”, “shims” and all these “new” ways of making things that used to work fine right off the bat 5 or 10 years ago work again: isn’t bundling or shimming (sorry, not an expert in such semantics) a problem when debugging?

So funny.
:laughing:

Continuation:
I generated bundle.js using Webpack but I didn’t manage to make it work because import { TextGeometry } from './bundle.js' returns that bundle.js doesn’t have such export. So far I gave up after like 6 hours of trying to make it work. And besides all my scripts would have to import from bundle.js so I don’t want that because I’d have to change all import references to bundle.js in all my scripts.

I found that dynamic import() was what was crashing my app so I believe it’ll be working without bundle.js and with “ES Module Shim” polyfill.

Also, it turns out that Mac/Safari console doesn’t actually show all errors related to this and I had to click “All” tab to be able to debug this (took me like 1 hour to figure this out, Chrome and Edge show all errors in the Console by default).

Shims (also called “polyfills”) are not really related to build tools or bundlers. Shims just scripts that “patch” in missing features in old browsers. JavaScript developers have used shims for more than a decade, e.g. to patch missing or broken features in Internet Explorer. If you need a feature like import maps, and your browser doesn’t have it, a shim can add that feature to older browsers. Personally I do not use the import map shim, because I do not use import maps. Using a build tool like Vite (or Webpack or Parcel or Browserify), it packages everything into a single file, and there’s no need for import maps, or even imports in most cases.

Modern build tools like Vite include solutions for the things you’re describing here. Details inline —

isn’t bundling …a problem when debugging

All browsers support sourcemaps, allowing you to view and debug the source files in the browser, even if the files were technically packed into a single file. This does not typically affect debugging.

Is the bundling / packing instantaneous and happening every time you run your main module in a page…

It is practically instantaneous in most projects, although I have worked on a few that were slow (looking at you, Closure Compiler). Newer tools like Vite include Hot Module Replacement (HMR) so you don’t even need to reload the page to see your changes, the updated code is just swapped in on the fly. But even without HMR, updates are very fast.

Also, does it need an active internet connection…

Local, no need for an internet connection once the build tool has been installed.

2 Likes

If you have lots of scripts on the page importing from the bundle, then you’re doing something very different from typical Webpack usage. Typically there is only one script on the page in the end, the bundle, and the bundle does not need to be imported into anything, it just runs. I suppose there are reasons you might do this differently though.

If you prefer to manage dependencies and files separately and not bundle them, that’s fine, but personally I find this makes things much harder. Most JavaScript projects relying on dependencies use some kind of bundler. Webpack is one of the more complex ones, others are simpler.

Oh, well, I’m familiar with polyfills, but I had no idea shims were just that. Thanks for taking the time to point out the details that I mentioned and how they are handled by these tools / methods, that makes it all clear for me. :ok_hand:

I won’t switch from using import maps for now, since my current project involves running the Three.js related code in a desktop application (Rainmeter, though I built it so it can run more or less the same in the browser as well without any problems), and I’d like to avoid increasing its own list of dependencies (e.g. the desktop application, the plugin that allows it to run webpages, Edge’s WebView2 as a platform for that, Node.js to run it through a local server and debug it) to zillions of stuff for every little thing along that process - but this is certainly useful to know, for the future.

What you’re using seems like less trouble than I thought, so I guess there positives exist as well - it’s just that things used to be way simpler than this in the past and it’s a pitty they “evolved” into this labyrinth of “you need this to do that”, that’s all.

1 Like

Yeah, I do agree that JS ecosystem tools have gotten more complicated over the past decade, and the learning curve is steeper than it should be. But I find the pain involved in trying avoid those tools (given where the ecosystem is, and is headed) is even worse at this point. Up front costs aside, these tools do (IMHO) work well once they’re set up. :slight_smile:

1 Like