Problems loading babylon via es modules

hello friends! i’m experimenting with the future, today! :sunglasses:

i’m really excited since all the cool browsers support proper es-modules, so i’ve been upgrading my typescript libraries to emit es-modules and umd-modules, and in new projects, i’ve been experimenting with having no build-step at all. it feels very liberating!

so given the following code to load babylon via unpkg (which seems to be an awesome hipster replacement for npm, from the future!) (here’s this example on codepen)

import * as babylon from "https://unpkg.com/@babylonjs/core@4.0.0-beta.1/index.js"
document.body.textContent = "done!"

i’ve found two potential issues:

  1. module specifiers are lacking the required extensions

    • when we look at @babylonjs/core/index.js ( https://unpkg.com/@babylonjs/core@4.0.0-beta.1/index.js ) we can see that the emitted module specifiers do not have extensions

    • omitting the extensions is not valid, however in our example case, unpkg goes one extra step to counteract the problem: it will serve the .js file for any file requested without an extension (eg, “index” becomes “index.js” thanks to the unpkg server, but this is non-standard behavior that should not be relied on) (other npm-cdn’s, like jsdelivr, don’t seem to offer this helpful hack)

    • the lack of extensions causes loading babylon via jsdelivr to fail (which doesn’t have the ?module hack feature) — import * as babylon from "https://cdn.jsdelivr.net/npm/@babylonjs/core@4.0.0-beta.1/index.js"

    • note that there are ongoing debates ( https://github.com/nodejs/modules/issues/293 ) on whether the future of es modules on the web should be expressed as .js or .mjs

    • at first in my own projects, i found this requirement confusing, because typescript doesn’t have a compiler option to emit a particular extension in the module specifiers — however as a solution, i found that typescript seems to be designed, for this purpose, to ignore file extensions in your typescript sourcecode – such that you can tweak all of your module references (in your ts source) to, for example, export * from "./abstractScene.js"; (adding the .js) – and typescript is totally relaxed about it, and will emit the desired extension, and so typescript is smart enough to know that abstractScene.js is the same as abstractScene.ts

    • user workaround: rely on unpkg’s rewriting hack for now

    • inevitable babylon solution: add .js extensions to all module references in babylon’s typescript sourcecode (or otherwise .mjs, if that one floats your boat)

  2. "bare specifier" module references

    • the following error is thrown:

      Uncaught TypeError: Failed to resolve module specifier "tslib". Relative references must start with 
      either "/", "./", or "../".
      
    • there are some bare specifiers in babylon referencing tslib, at least for the decorator function, it looks to me

    • bare specifiers are reserved ( https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier ) for builtin modules, however in the future, we’ll be able to rewrite them via import-maps

    • how to fix it:

      • (future solution) we’ll use import-maps ( https://github.com/WICG/import-maps ) to remap the bare-specifiers

      • (workaround-a) we can use es-module-shims ( https://github.com/guybedford/es-module-shims ) to shim the import maps see the codepen demo ( https://codepen.io/ChaseMoskal/pen/BbqVOr?editors=1010 )

      • (workaround-b) unpkg has a ?module feature which rewrites bare specifiers (see my reply post for more details)

thanks for reading, and of course it goes without saying, i’m no authority on how es modules work — we’re all learning and developing these new ideas together, so if i seem misguided or there’s a different way to think about or avoid these problems, i’d love to discuss it, so please speak up!

if you’d like me to post a github issue, just let me know

cheers everybody, keep making web games :slight_smile:

edit: hmm, this form limits me to two real links, sorry but you’ll have to copy-paste if you want to follow them :wink:

// chase

1 Like

in further experimentation, i have found that the “bare specifier” module references situation is a non-issue for babylon

  • (real solution in the future) import-maps will solve this problem, and is in the standardization process

  • (workaround-a) unpkg has a really cool ?module feature which rewrites bare-specifiers to fully qualified unpkg links: this works today

    import * as babylon from "https://unpkg.com/@babylonjs/core@4.0.0-beta.1/index.js?module"
    
  • (workaround-b) use es-module-shims and use import maps today (codepen example)

    <script defer src="//unpkg.com/es-module-shims@0.2.1/dist/es-module-shims.js"></script>
    
    <script type="importmap-shim">
      {
        "imports": {
          "tslib": "//unpkg.com/tslib@1.9.3/tslib.es6.js"
        }
      }
    </script>
    
    <script type="module-shim">
      import * as babylon from "https://unpkg.com/@babylonjs/core@4.0.0-beta.1/index.js"
      console.log(babylon)
    </script>
    

however the lacking of extensions in module specifiers is a problem that should be addressed

The main issue would be the reference cross packages like materials-library and so on who are referencing the project through node_modules.

We are closely following those issues and won t miss to update as soon as there will be a standardization and agreement in favor of one particular extension.

Despite ts not requiring the extension some other tools associated with the build do not love them a lot at the moment so instead of hacking around those tools at the moment we prefer to wait for a strong standardization agreement.

I hope this will come soon and that the network related issue of unbundled files would also find a solution.

1 Like