Include examples/js into the new Three.JS module system and rely on tree shaking

Description of the problem

It would be great if we could move a lot of the Three.JS example/js source code into the main /src directory tree and then rely upon the module system/tree shaking to remove the code that is not needed.

This would really make it easier to add code to three.js and also make everyone’s builds small at the same time. 🙂 Basically better in every way.

I guess when one uses ThreeJS in another project one needs to rely upon a global rollup rather than a ThreeJS specific rollup. I guess that can be hard to support.

/ping @Rich-Harris

Three.js version
  • Dev
  • r79
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
  • All of them
  • Windows
  • Linux
  • Android
  • IOS
Hardware Requirements (graphics card, VR Device, …)

Author: Fantashit

5 thoughts on “Include examples/js into the new Three.JS module system and rely on tree shaking

  1. @crabmusket I’ve been looking at this as well, wondering why the simplest, most minimal import of Three.js results in monstrously huge bundles containing essentially every single module. I read through the discussion you pointed to above, performed numerous experiments and went so far as to generate graphs of the Three.js dependency tree to try and get to the bottom of this. Here are a few takeaways from the experience:

    Importing from src is the right way to go. This is your best bet if you are counting on static analysis tools to detect and excise any unused code.

    UglifyJS couldn’t do much here since it does not yet understand es6 modules.

    Babili does understand es6 modules and is capable of finding unused code that can be purged.

    A multi-stage build/bundling process via Webpack, transpiling from TypeScript to es6, performing code elimination via Babili, transpiling to es5 via Babel and finally minifying via UglifyJS turned out to be the most effective strategy and was the only means of making a dent in the final size of the bundle produced by Webpack.

    However, try as I might, after days of trials and experimentation, I can only get the size of the Three.js derived code down to 529.96 KB and when I dig in and take a look at which modules have been included, I still see tons of code that I am not using and should not end up in the final bundle.

    I haven’t done enough detailed analysis to be absolutely sure just why all of the extra modules are getting pulled in, but I have some intuition here. I think this may be caused by the “convenience” exports that can be found in src/Three.js. Every module is brought up to the “surface” of Three.js in an effort to make it easier for developers to import the modules they want to use without a bunch of hunting around in the docs. Unfortunately, this seems to have the undesirable side-effect of forcibly importing all of Three.js my default into your project whether you want it or not. This wouldn’t be too terrible if the uneccessary code could be removed by the usual “tree-shaking” process down the line, but it never does get removed no matter how hard you try. I suspect this is becuase this is becuase all of these pre-emptively imported all depend on one another and there is enough complexity in these dependency relationships to prevent the tree-shaking process from correctly identifying and excising unused code.

    I can’t state this with certainly yet, its just a hunch based on what I’ve observed while playing around with this for a few days. I am hoping to test this theory out soon.

  2. @mrdoob in retrospect what you say makes things completely obvious. Maybe for other confused souls like myself it would be good to have a section in the readme or something? Just prompting people to import modules directly if they only need a subset of features. And reminding them they’ll probably need a loader for .glsl files (e.g. webpack-glsl-loader).

    @mutsys awesome work! Great to see those results and hear that there might be opportunities to improve further. I’ll keep following this thread and will report back on the results of importing directly from src modules instead of Three.js.

    My method will be basically to maintain my own local three.js file. I experimented with this before, but I was still importing everything from Three.js and relying on tree-shaking. Turns out I was putting too much faith in the system haha.

    EDIT: by selectively importing files, I reduced the bundled size of Three.js from 420K to 260K. Not as much as I was hoping for, but not bad either. @mutsys I can’t see where Vector3 is importing Camera?

  3. Related: #14803

    I’m strongly in favor of converting the packages under example/js/* into ES modules and (if needed for backward-compatibility) automatically building UMD modules from those. That’s high priority in my opinion.

    But how would SystemJS contribute? It seems useful for end-users’ applications, or keeping the example demos functional on older browsers, but I’m not sure how it relates to distribution of the threejs library as a download or npm module.

    The idea of moving a majority of examples/js/* into the src/* tree is less of a slam dunk I think. If it’s possible to defer that conversation until the ES module change is settled, let’s go that route.

Comments are closed.