Tree Shaking Three.js

Hi!

I just want to share our experience with treeshaking a project using three and GSAP. We’re bundling with Rollup and our solution at the moment sounds somewhat similar to what @yushijinhun’s plugin is supposed to do, but still a bit different:

  • rollup treeshake:
    add treeshake: { moduleSideEffects: false } to Rollup config. If this is not done GSAP and THREE will be fully added including all modules and plugins even if you just import / use one of them (notice: this will happen with all namespaced libraries like ‘three’ or ‘gsap’). See rollup treeshake docs

  • three as npm dependency:
    import { Foo } from 'three', means from 'node_modules/three/build/three.module.js' does NOT treeshake, you have to import from 'src': e.g. import { Foo } from '../../node_modules/three/src/Three'. To achieve this easily we write from 'three' in our code and use the @rollup/plugin-alias to replace all 'three' entries accordingly when bundling, like this:

plugins: [
alias({
            entries: [
                {
                    find: 'three',
                    replacement: __dirname + '/node_modules/three/src/Three'
                }
            ],
        })
]

The above method works / treeshakes perfectly if you use modules from inside 'three/src' folder ONLY. As soon as you import something from the 'three/examples' folder, e.g. 'import { Foo } from '../../node_modules/three/examples/jsm/loaders/Foo', full three is going to be added to the bundle ADDITIONALLY because (as it seems) modules inside 'three/examples/jsm' import from 'three/build/three.module.js'. I’m not quite sure why exactly this is happening, but we’ve found a solution (not sure if best) which works:

At the moment we only need the GLTFLoader and the DRACOLoader both inside 'three/examples/jsm/loaders'. We copied them to the 'three/src/loaders' and changed the imports inside them accordingly + added corresponding exports to 'three/src/Three.js' & 'three/src/Three.d.ts'. See here Move GLTF & DRACO Loaders from 'examples' to 'src' · cream-gmbh/three-116-1@9c2b1d3 · GitHub

This way the Loaders get also treeshaked & we get the smallest possible bundle size, I guess… well, let’s say I’m pretty sure. :wink: check out https://cream.gmbh/ to see what I’m talking about (bundle size 840 KB / 273 KB gzipped incl. three, gsap, svelte & website-engine / animations). (notice: GLTFLoader is importing A LOT of modules, so without it, the bundle size would be even smaller.)

I’m not sure though if this is the best, most elegant way to do this :thinking:, means maybe there are some other Rollup config tweaks we didn’t figure out by now + this way any 'three/examples/jsm'-modules you might need would have to be copied and changed like the both Loaders mentioned above.

I hope this helps & please feel free to correct me / propose a better solution! :grin:

3 Likes