Skip to content

Builds: Make three/tsl tree-shakeable. - #34533

Open
monken wants to merge 1 commit into
mrdoob:devfrom
monken:tsl-tree-shakeable
Open

Builds: Make three/tsl tree-shakeable.#34533
monken wants to merge 1 commit into
mrdoob:devfrom
monken:tsl-tree-shakeable

Conversation

@monken

@monken monken commented Sep 10, 2026

Copy link
Copy Markdown

Description

Importing a single function from three/tsl currently keeps the whole TSL namespace in the bundle. Each export reads from that namespace (export const color = TSL.color), so unused nodes and helpers end up in the application's bundle as well.

This PR exposes the TSL functions as named exports from both WebGPU entry points and uses plain re-exports in Three.TSL.js. That allows bundlers to remove the unused exports. The existing TSL namespace is kept for backwards compatibility.

Both core and TSL export log, so the core export keeps its name and the TSL function is exposed as logTSL. It's still exported as log from three/tsl.

I added a Rollup test that imports the renderer from the built three/webgpu file and color from three/tsl. For this example, the bundle sizes are:

Bundle size Before After
Minified 877,680 bytes 769,314 bytes
Gzipped 235,248 bytes 205,950 bytes

This contribution is funded by revanta.bio

@github-actions

Copy link
Copy Markdown

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
Core 389.51
102.17
389.51
102.17
+0 B
+0 B
WebGL 379.11
88.92
379.11
88.92
+0 B
+0 B
WebGPU 711.13
195.69
724.83
200.49
+13.7 kB
+4.79 kB
WebGPU Nodes 709.12
195.38
722.82
200.17
+13.7 kB
+4.79 kB

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 523.73
126.08
523.73
126.08
+0 B
+0 B
WebGPU 765.12
205.27
765.12
205.27
+0 B
+0 B
WebGPU Nodes 711.21
191.93
711.21
191.93
+0 B
+0 B

`three.tsl.js` re-exported every TSL function by reading it off the `TSL`
namespace object of `three/webgpu` (`export const abs = TSL.abs`). A single
import from `three/tsl` therefore kept the whole frozen namespace alive in
the consumer's bundle, and with it every node, lighting model, display pass
and GPGPU helper, whether or not the application used them.

`three/webgpu` now also re-exports the contents of `nodes/TSL.js`
individually, and `Three.TSL.js` becomes plain `export { ... } from
'three/webgpu'`, which bundlers can tree-shake. The `TSL` namespace export
is kept for backwards compatibility. `log` is exported by both
`Three.Core.js` and TSL, so the core export is re-exported explicitly and
the TSL one is exposed as `logTSL` for `three/tsl` to re-export as `log`.

A `test/treeshake/index.webgpu.tsl.js` entry that imports from the built
`three/webgpu` and `three/tsl` files measures the effect:

                   Before              After
  minified / gzip  877,680 / 235,248   769,314 / 205,950  (-108.4 kB / -29.3 kB)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant