Kotlin/JS loads JS-library twice

I’m using three.js from Kotlin based on the following configuration setting in build.gradle.kts:

dependencies {

I’m also using the three.js-addon GLTFLoader:


package three.loaders

external class GLTFLoader(manager: LoadingManager = definedExternally) : Loader {

GLTFLoader.js includes three.js via an import-statement:

import {
} from 'three';

This import causes webpack to load the three.js library a second time. As a consequence, the Mesh instances created by the GLTFLoader fail type checking when I try to use them, e.g. val obj = entry as Mesh, which is compiled to var obj = Kotlin.isType(tmp$ = entry, Mesh) ? tmp$ : throwCCE(); throws an IllegalCast exception.

How can I configure my project so GLTFLoader.js does not load three.js a second time?

I have the same issue with Three-js. I tried to figure our why is that, but it seems like the problem occurs only with three-js for some reason.

By the way, do you use some kind of wrapper for three-js? I use a slightly modified version of that was formerly maintained by @laht90. But if there are several users, it is better to have a commonly maintained wrapper.

I tried to figure our why is that

The package.json of three.js tells webpack to use three.cjs when the request is issued from CommonJs/AMD syntax or similar resp. three.module.js when the request is issued from ESM syntax or similar:

"exports": {
    ".": {
      "import": "./build/three.module.js",
      "require": "./build/three.cjs"

see webpack package exports.

Is Kotlin missing a way to instruct the JS compiler to request libraries “from ESM syntax or similar”?
Would you consider this a Kotlin issue?

By the way, do you use some kind of wrapper for three-js?

I use my own handcrafted wrapper.
I also self made a wrapper for Cannon.JS. Let me know, if you’re interested in that one.
Apart from that, I only have some 500 lines of generic three-js related Kotlin code
(which is an indication of the high degree of completeness of three-js IMHO),
including syntactic sugar like

operator fun Vector3.plusAssign(v: Vector3) {

inline infix fun Vector3.apply(quaternion: Quaternion) = applyQuaternion(quaternion)

operator fun Array<Object3D>.get(name: String) = firstOrNull { it.name == name }

val Object3D.geometry
    get() = when (this) {
        is Mesh -> geometry
        is Line -> geometry
        is Sprite -> geometry
        else -> null

some niceties like

fun Object3D.angleDistance(angle: Double) = (boundingSphereWithChildren?.radius ?: .0) / tan(angle / 2)

or BoxWithEdges or a port of DynamicTexture.js (guess why I didn’t include the JS file…).

It doesn’t have the quality to be the core of a Kotlin-extensions library for three-js, but it could be a nice addition to such a library.

Thanks for clarification. It is not critical anyway. Good to know why it happens.