Transform `examples/js` to support modules

The main source code has recently been ported to ES2015 modules (see #9310); however, some parts are still relying on global namespace pollution and have thus become unusable.

Specifically the things in /examples/js/ haven’t been transformed to support modules yet; this makes them currently unusable from within environments such as webpack or SystemJS.

Edit, 11-20-2016: They can be used, but it requires a lot of setup: SystemJS, webpack. If you need assistance with these: Sorry, but this is the wrong thread to announce it! 😄

Author: Fantashit

16 thoughts on “Transform `examples/js` to support modules

  1. Either things like examples/js/postprocessing/ become a module of themselves or we need to come up with some kind of plugin logic.

    @mrdoob what if github.com/threejs becomes a thing? You can create different repos inside of it which have a similar build system as the current threejs, which can be used via modules or people can just download the legacy code in the build folder. Again with the postprocessing in mind, it will have THREE has a dependency, and it would be both a module or you can use the /build/EffectComposer.js for legacy code?

  2. the idea was to give you and the maintainers more control over the releases, a bit like https://github.com/airbnb or https://github.com/facebook I’m happy to pick up some bits and bobs as I need them but you’ll end up with github.com/randomuser/effectscomposer github.com/randomuser2/orbitcontrols 🙁

  3. We’re not saying we should have the examples as modules. We’re saying that some of the files referenced in the examples folder aren’t yet modularised, like OrbitControls.js or EffectsComposer.js or many others that are very often used in demos, prototypes and even in production. Those files, should be, as I was suggesting, modules of their own, outside of three.js

  4. Yeah exactly. Especially OrbitControls. It might just be me, but I end up including that file a lot.

  5. I find myself in the same position as @satori99, often needing a way to use Projector or CanvasRenderer, both being far from just an “example” with a good 1000 lines each.

    @mrdoob People that don’t use modules could just be pointed to versions of the project that had a pure ES5 codebase, so that they can pull the code via a <script> tag via global namespace pollution.

    Essentially, the jQuery project did the same thing to gradually save themselves from supporting legacy browser versions (i.e. make a cut somewhere, support-wise).

  6. So… maintaining two versions of the same code base?

    My intent was to eventually kill off the way that three.js ships bundles that mess with global namespace. It might be too early for that, given that <script type="module"> and the System global are not quite there yet, but I don’t think that any project should promote this way of shipping code to the user in the future anymore. Hence, what I meant to say was that three.js should eventually just work like so:

    <!--
     Use the bundle if you need this to work with legacy browsers.
     This will inject `window.THREE`.
    
     WARNING: 0.80.2 is the last version that comes with `window.THREE`.
     If you need a newer version, please consider migrating to using modules.
    -->
    <script src="three.js"></script>

    So that in the future, users could migrate to something along the lines of:

    <script type="module">
        /* This would be the version that supports `examples/js` to be consumed */
        import THREE from "./vendor/three/three.min.js";
        import CanvasRenderer from "./vendor/three/examples/js/renderers/CanvasRenderer.js";
    </script>

    Another (maybe cleaner?) approach worth discussing might be to move examples/js into the core.
    Pros:

    • No breaking change in terms of deployment (see outlined approach above)
    • Three can be consumed from bundlers and browsers
    • Full support for import syntax without hacking globals in with something like imports-loader

    Cons:

    • For people using <script> tags only, the consumed bundle size will increase by a lot

    If there’s more cons, feel free to bring them up; but as for the bundle size: This only concerns users that want to inject three into global namespace anyway. If they see that this hurts site performance, it will as well act as an incentive to migrate to a build environment with something like rollup or tree shaking and create personalized bundles themselves.

    @GGAlanSmithee brings up another good idea: With UMD, the bundle size won’t increase for legacy environments, it allows being used with import, allows the examples to be transformed to use ES2015+ and prevents them to be moved to the core. On the other hand, this also makes three.js’s build pipeline a little more complicated.

  7. @andrevenancio If every example becomes its own official npm module written with ES2015 modules, they would essentially all do import THREE from "three"; in order to provide functionality by using what this THREE instance provides it, right? This is both useful as well as dangerous.

    If some guy’s personal three.js project does an import THREE from "three"; too, there is a chance that the versions of his project’s THREE instance and, say his three-canvas-renderer module’s THREE instance are different and not thus not only prevent a proper rollup, but can also introduce weird bugs that are hard to debug (I ran into failing subclass checks before, having introduced two vastly different three.js files by accident via <script>. I’d imagine that the same could happen by dividing the examples into npm modules).

    Wouldn’t it be safer if we could have all that stuff in one place, e.g. something like

    import THREE, { CanvasRenderer } from "three";

    ?

    This would guarantee that the THREE instance for CanvasRenderer also matches the instance of THREE you’re importing, as they both originate from the same npm module. This ensures that the rollup can be fully leveraged and should prevent weird bugs.

    At least, that’s the npm side of it. On the GitHub side, it’s really a matter of personal preference if you want to split the examples up into different repositories.

  8. Again, I never said examples should be their own npm module.
    What I said, and keep trying to explain, is that some utilities that only can be found in examples/js/ should be moved elsewhere.

    Example, OrbitControls, or everything in the postprocessing folder.

    And yes, I agree with you, we should be able to import it such as

    import THREE, { OrbitControls } from 'three'

  9. I’d also really like this to be possible, both via

    require('./node_modules/three/examples/js/controls/VRControls'); 
    

    and via modules:

    import VRControls from './node_modules/three/examples/js/controls/VRControls'
    

    Could either manually add JS boilerplate to the end of each example (doesn’t scale):

    if (module && module.exports) {
      module.exports = ModuleName;
    } else {
      THREE.ModuleName = ModuleName;
    }
    

    Or do something more clever with a build step. Having all of the example code in a unified ‘three’ bundle seems not particularly friendly for non-npm users, unless I’m missing something.

  10. Hello, I’m going to leave my 0.02 here, about the “modularization” of examples. Hate to give negative feedback, but I believe this is feedback I’d like to have if this was my project. I needed a WebGL library for a quick solution, so I fetched Three, with which I had a great experience around 5 years for a different project, where I was able to use it to quickly prototype something and it was all very smooth and one of those great experiences where you find a piece of software that just works and that is a breeze to integrate in your project. Today the examples are using modules and that just made it too cumbersome to use in my particular use case. I struggled with it for an hour. Sure, I could have dedicated some more time to alter my project and make it all work, but in the end I just found it easy to use a different webgl engine that doesn’t use modules and it’s just a bunch of scripts to include and it literally took me minutes to start visualizing my 3d data. This other engine (I don’t want to be rude and mention it) was a wonderful experience compared to fighting modules with Three. Just like Three was for me 5 years ago.

    Just a thought, maybe you really needed to make the examples use modules to make it all work for you, but you definitely lost something valuable here. Very impressed with how far the project has come otherwise.

  11. @Kleenox Thanks for feedback! Unfortunately, this is a topic where we can not please everyone. Most people developing now with npm and a bundler. The focus on modules makes the live for all these people easier. At a certain point examples/js will be completely removed (see #16920 (comment)).

  12. Hence, I think this issue can be closed now since the modularization is actually done and examples/js is going to be removed.

Comments are closed.