DRACOLoader fails only on iOS Safari, only in production build

When loading a draco gltf model on a development build, I have no issue anywhere. When loading a draco gltf model on Safari iOS in production, I have a load of errors (THREE.DracoLoader: Unexpected attribute type). It works on any other device/browser, and fails only on my production build.

In my experience, minification and optimization of code for production sometimes produces code that will fail on specific browsers, but I’m a bit clueless for this one. Did anyone ever experience that, and what would be a fix?
The build is made with webpack 4.41.2, and it fails with both wasm and js draco decoders.

Author: Fantashit

1 thought on “DRACOLoader fails only on iOS Safari, only in production build

  1. In any case, glad you got this working!

    Maybe Float32Array did get polyfilled, just to patch some missing behavior, like .fill? Safari still doesn’t have that. I don’t think we use that method, but webpack wouldn’t know.

    Hard to guess exactly what’s happening but if this comes up again, maybe we could try replacing the constants here…

    var WEBGL_COMPONENT_TYPES = {
    5120: Int8Array,
    5121: Uint8Array,
    5122: Int16Array,
    5123: Uint16Array,
    5125: Uint32Array,
    5126: Float32Array
    };

    … with strings, and using a switch block to choose a constructor.

    Actually, doing that an only that (ie. replacing the Constructors with their names as Strings)

    var WEBGL_COMPONENT_TYPES = {
      5120: "Int8Array",
      5121: "Uint8Array",
      5122: "Int16Array",
      5123: "Uint16Array",
      5125: "Uint32Array",
      5126: "Float32Array"
    };

    was enough for me to get the DRACOLoader worker to work on Safari (iOS and desktop).
    In fact, in

    var attributeType = self[ attributeTypes[ attributeName ] ];

    this will be evaluated to the Constructor, even if the passed in value is a String.

    Thanks a lot for the pointer @donmccurdy!

    (background to this is that it seems passing actual JavaScript Objects to the worker doesn’t really work in Safari. The attributeTypes was becoming { position: "", normal: "", uv: "", uv2: "", ... } in the worker context for me)

    EDIT 23.07.20
    I was wrong, just changing WEBGL_COMPONENT_TYPES to contain strings breaks the non-draco loading, specifically at (for example)

    var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];

    which then throws TypedArray is not a constructor error down the line, since it’s now a String.
    To solve this, I had to do what @donmccurdy sugested in the first place (on top of change WEBGL_COMPONENT_TYPES to contain strings) and add the following utility function:

    function getWebglComponentTypeConstructor(componentTypeString) {
      switch (componentTypeString) {
        case "Int8Array":
          return Int8Array;
        case "Uint8Array":
          return Uint8Array;
        case "Int16Array":
          return Int16Array;
        case "Uint16Array":
          return Uint16Array;
        case "Uint32Array":
          return Uint32Array;
        case "Float32Array":
          return Float32Array;
      }
    }

    as well as change a few lines in my GLTFLoader instead

    var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];

    to

    var TypedArray = getWebglComponentTypeConstructor(WEBGL_COMPONENT_TYPES[ accessorDef.componentType ]);

    and

    var TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];

    to

    var TypedArrayIndices = getWebglComponentTypeConstructor(WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ]);

Comments are closed.