DEV Community

Cover image for Self-host your Draco decoder - the 600ms CDN tax on Three.js configurators
Dominik
Dominik

Posted on

Self-host your Draco decoder - the 600ms CDN tax on Three.js configurators

Draco compression is the difference between a 90MB glTF export and a 3MB one. For CAD-heavy product models it is not optional. But there is a trap in the standard setup that quietly costs you half a second on first paint.

The default that looks fine

Most examples point the decoder at Google's CDN:

const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/')
Enter fullscreen mode Exit fullscreen mode

It works. It also means every first-time visitor makes a cross-origin trip to fetch the WASM decoder before a single triangle appears. In my measurements on real configurators that added around 600ms to first paint on a cold cache, right at the moment the user is staring at an empty canvas deciding whether to wait.

The fix: self-host the decoder

Copy the decoder out of the Three.js package you already have installed:

node_modules/three/examples/jsm/libs/draco/
Enter fullscreen mode Exit fullscreen mode

Drop it in your public/ folder and point at it:

const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco/')   // served from your own origin

const loader = new GLTFLoader()
loader.setDRACOLoader(dracoLoader)
Enter fullscreen mode Exit fullscreen mode

Now the decoder loads from the same origin, in parallel with the rest of your assets, cached by the same CDN or server rules as everything else. No extra cross-origin handshake on the critical path.

Two things people miss

  1. The decoder is WASM plus a JS wrapper. Copy the whole draco/ folder, not just one file, or you get a confusing "failed to load" with no stack trace.
  2. Set the right cache headers. The decoder never changes between builds. Give it a long Cache-Control: max-age so returning visitors pay nothing. First visit is the only one that touches it.

Small change, measurable win, and it lives on the critical path so it punches above its weight. The pool configurator at basen3d.grodev.pl serves its decoder this way.

I am Dominik Groński / GroDev, a studio in Poznan, Poland building custom 3D configurators and Laravel back-ends for manufacturers.

Top comments (0)