# \`import from 'three/tsl'\`, WARNING: Multiple instances of Three.js being imported

**URL:** <https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303>\
**Category:** Questions\
**Created:** [September 5, 2024, 12:37am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303 "2024-09-05T00:37:32Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 12:37am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/1 "2024-09-05T00:37:32Z")

</div>

Shipping both `three.webgl.js` and `three.module.js` with duplicate Three.js code causes a duplicate-threejs hazard when any projects import both.

It is too easy for one library to import `from 'three'` and some other library to import from `three/tsl` or `three/webgpu`. One or more of the following warning may appear in console:

```javascript
WARNING: Multiple instances of Three.js being imported.

```

When this happens, there are a couple ways to fix it:

- vanilla browser ESM users can easily modify their `importmap`
- people with a build, especially people new to web development, may have a harder time trying to figure how to alias their tooling to the correct paths.
- some people may be oblivous, and their app accidentally works (later it may break)

The original philosophy of Three.js is to keep things as simple as possible. For example that’s why TypeScript is not part of core, because it adds complexity that the main maintainers don’t want.

Likewise, the current Rollup build and the Node-specific `exports` field in package.json add a barrier of complexity for people who don’t know web tooling, or for people who are not into Node.js but trying to consume code written with Node.js standards (which are not web standards).

My thought is that the duplicate problem can be eliminated at least in the `build/` folder.

Here’s my suggestion:

- make `src/Three.WebGPU.js` re-export stuff from `./Three.js` instead of duplicating the exports
- then build `three.module.js` the same as usual
- then build `three.webgpu.js` with `three.module.js` as an external module (f.e. `three.webgpu.js` will have `export * from 'three'` or `export * from './three.module.js'`, I think the last one is better for plain ESM, plus either one can be overriden in an `importmap`).

**Downside (worst case):** two files are downloaded for Three.js for vanilla JSM users instead of one, the second file now provides extra WebGPU stuff. Two files instead of one is not a bad compromise for the overall gain:

**Upside:** the duplicate Three.js problem will be eliminated, and the setup made overall simpler with less likely of tooling issues needing to be configured. Libraries can freely import from `three`, `three/tsl`, or `three/webgpu` without causing tooling conflicts or duplicate Three.js instances. With this simpler setup, existing projects could just add an `import` statement and move forward.

I believe this change will be non-breaking, and if anything it may fix some projects that may currently have accidental duplicate Three.js libs.

P.S. happy to try to make this change if approved to move forward with it.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 2:59am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/2 "2024-09-05T02:59:38Z")

</div>

I wrote this because in the real world I wanted to try out TSL in an existing Three.js project, and found it difficult to import the new TSL features. Unfortunately for me, this particular project has a build, so I cannot just tweak a standard `importmap`. The project’s tooling is Vinxi+Nitro+Vite, which I’m sure has options, but I’ll have to go fiddle with the tooling config to get it working.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 3:57am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/3 "2024-09-05T03:57:34Z")

</div>

### The problem with package.json exports:

Here is the package.json exports field:

```json
  "exports": {
    ".": {
      "import": "./build/three.module.js",
      "require": "./build/three.cjs"
    },
    "./examples/fonts/*": "./examples/fonts/*",
    "./examples/jsm/*": "./examples/jsm/*",
    "./addons": "./examples/jsm/Addons.js",
    "./addons/*": "./examples/jsm/*",
    "./src/*": "./src/*",
    "./webgpu": "./build/three.webgpu.js",
    "./tsl": "./build/three.webgpu.js"
  },

```

We can see two things here, besides the rest:

- `import {anything} from 'three'` results in stuff that will come from `./build/three.module.js`
- `import {anything} from 'three/tsl'` or `import {anything} from 'three/tsl'` results in classes coming from `./build/three.webgpu.js`, with many things that are duplicates of stuff in `three.module.js`.

Now, let’s consider an app that has this:

```js
// suppose this is in library-a
import {MeshPhongMaterial} from 'three'

```

```js
// app code:
import {something} from 'library-a'

```

Next, suppose the app author wants to import from `three/tsl` to try the new TSL language, or suppose the app author simply imports a 3rd party library (they do not know if it imports from `three` or `three/tsl`):

```js
// suppose this is in library-b
import {MeshPhysicalNodeMaterial} from 'three/tsl'

```

```js
// app code:
import {something} from 'library-a'
import {otherThing} from 'library-b'

```

Now, the user may have no idea, but due to the package.json `exports` of Three.js, their app bundle will now have duplicate Three.js libs (if they use a bundler). Maybe they can use smart tree shaking if they aware of it, or if the tooling even supports it. Or they might not even realize a problem exists.

Or the Three user might be importing into a runtime, not using a bundler. For example if they import directly into Node.js and use a Node.js WebGL or WebGPU backend for Node, then Node will by default import both versions of Three.js into one app.

Etc.

Example in Three.js repo:

- `WaterMesh.js` in examples imports from `three/tsl` (library-a)
- `Lensflare.js` from examples imports from `three` (library-b)

EDIT:

I noticed `Three.WebGPU.js` has commented out `WebGLRenderer` and related classes. I don’t know if there’s some reason for that. But in order to import everything, aliases for a build tool need to be roughly this (give or take the config format for your tool):

```json
			alias: [
				{
					find: /^three$/,
					replacement: path.resolve('node_modules', 'three', 'src', 'Three.js'),
				},
				{
					find: /^three\/tsl$/,
					replacement: path.resolve('node_modules', 'three', 'src', 'Three.WebGPU.js'),
				},
				{
					find: /^three\/webgpu$/,
					replacement: path.resolve('node_modules', 'three', 'src', 'Three.WebGPU.js'),
				},
				{
					find: /^three\/src\/Three.js$/,
					replacement: path.resolve('node_modules', 'three', 'src', 'Three.js'),
				},
			],

```

What this does is it ensures that Three.js is imported from a single location on disk, avoiding any duplicates.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 5:12am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/4 "2024-09-05T05:12:52Z")

</div>

Ah, I just noticed this move of `nodes/` into `src/` is very recent. Congrats @sunag. Exciting stuff!

I’m currently dealing with an error `TypeError: undefined is not an object (evaluating 'string.replace')` trying to replace a `MeshPhysicalMaterial` with a `MeshPhysicalNodeMaterial`, and I haven’t solved the duplicate Three.js issue with my setup yet.

I was at two warnings when I first added `import ... from 'three/tsl'`:

 ![Screenshot 2024-09-04 at 9.20.34 PM](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/d/edacc02ba9ff745345112f6ed0bbead3d7b8c1a6.png)

then playing with aliases got me down to one (the above aliases actually didn’t work as good as I thought):

 ![Screenshot 2024-09-04 at 10.18.07 PM](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/f/9/f9b5476fad892cde0157af810e8cb9a1a48485c6.png)

So I’m hoping getting rid of the last duplicate will solve the error. 🤞

EDIT: I think that error is because node material → WebGLRenderer.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 6:30am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/5 "2024-09-05T06:30:13Z")

</div>

Ah, I managed to resolve duplicates with Vite config for Vinxi for Solid Start, but ironically the message is because both `src/Three.js` and `src/Three.WebGPU.js` contain

```js
if (typeof window !== 'undefined') {
    if (window. __THREE__ ) {
        console.warn('WARNING: Multiple instances of Three.js being imported.');
    } else {
        window. __THREE__ = REVISION;
    }
}

```

So even without a duplicate, as I’m trying to import both, it shows the message.

I’m expecting mixing WebGL + WebGPU stuff obviously won’t work. I heard TSL supports GLSL? Maybe I need to enable that mode?

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 6:45am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/6 "2024-09-05T06:45:36Z")

</div>

Ah ok, looks like we’re in a transitionary phase now:

> Part of the discussion above mentioned the legacy node support for `WebGLRenderer` which has been removed with `r164` in the meanwhile.

([from here](https://github.com/mrdoob/three.js/pull/27156#issuecomment-2094080044))

So, that explains why `WebGLRenderer` and related classes are commented out in the `Three.WebGPU.js` file.

Hmmm, tricky situation.

I guess I’m just thinking out loud at this point. 😃

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 7:09am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/7 "2024-09-05T07:09:06Z")

</div>

Thinking about this just a little more, keeping in mind that the non-node materials are usable with WebGPURenderer, it’ll be good to fix the import situation to avoid duplicate Three.js. This way someone not relying on onBeforeCompile and custom GLSL can still migrate more easily. Thoughts @sunag?

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 7:35am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/8 "2024-09-05T07:35:06Z")

</div>

Site note, if using native `importmap`s in a browser (instead of a build tool), we can avoid duplicate Three.js libs by linking to `src/` files instead of `build/` files.

Instead of this:

```html
<script type="impotmap">{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.module.js",
    "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.webgpu.js"
  }
}</script>

```

Do this:

```html
<script type="impotmap">{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.167.0/src/Three.js",
    "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.167.0/src/Three.WebGPU.js"
  }
}</script>

```

Because both `src/Three.js` and `src/Three.WebGPU.js` import from other files in the `src/` folder using relative paths, the JS module system will automatically resolve the same files, ensuring that duplicates of any modules are avoided (whereas the `build/three.*.js` files are bundled, and each one includes the a copy of the whole Three lib (with differences)).

The caveat with mapping to `src/` instead of `build/` is that more files will be downloaded by the browser (more individual JS modules, as opposed to two single (but duplicated) big bundles). This can be optimized though: when you’re ready to optimize (if needed, sometimes you don’t need to do this), you can use your own bundler to create a bundle based on your app entrypoint (which is importing from `src/` to ensure that it’ll avoid duplicates, especially if a smart enough tree shaking system is not available to otherwise detect duplicate in `build/` files).

---

<div class="post-metadata">

**Author:** ![seanwasere](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/seanwasere/32/20864_2.png) [@seanwasere](https://discourse.threejs.org/u/seanwasere)\
**Post date:** [September 5, 2024, 8:05am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/9 "2024-09-05T08:05:00Z")

</div>

In r168, you can avoid the “multiple instances” error like this.

# Using a buildtool

```diff
-import * as THREE from 'three'
+import * as THREE from 'three/tsl'

...

-const renderer = new THREE.WebGLRenderer()
+const renderer = new THREE.WebGPURenderer()

```

# Using importmaps

```diff
<script type="importmap">
    {
        "imports": {
- "three": "/build/three.module.min.js",
+ "three": "/build/three.webgpu.js",
            "three/addons/": "/jsm/"
        }
    }
</script>

```

…

```diff
-const renderer = new THREE.WebGLRenderer()
+const renderer = new THREE.WebGPURenderer()

```

Example _Three r168_,

> **[Classic Materials (WebGPURenderer)](https://editor.sbcode.net/a88f2f34573dd6fc90d9d70d3af8f2bc3d1db502#L32-L32)**
>
> https://editor.sbcode.net/a88f2f34573dd6fc90d9d70d3af8f2bc3d1db502

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 8:46am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/10 "2024-09-05T08:46:42Z")

</div>

@seanwasere hey thanks. However for some libraries and frameworks that will support both WebGLRenderer and WebGPURenderer for some time, this won’t work. If they import from both `build/three.module.js` (for `WebGLRenderer`) and `build/three.webgpu.js` (for `WebGPURenderer`) they’ll end up with duplicates. They may want to provide an option (f.e. `<lume-scene mode="webgl">` or `<lume-scene mode="webgpu">` for [Lume](https://github.com/lume/lume), or something similar for [react-three-fiber](https://github.com/pmndrs/react-three-fiber)). There are so many features already built on WebGL, so frameworks will want to make it easy to switch between the two, without the duplicate libs, so that users can easily try WebGPU or go back to WebGL, depending on which features work or are needed.

If it is up to the user to pick either `build/three.webgpu.js` or `build/three.module.js`, and not the framework choice, then the framework simply won’t work and cannot be written for either renderer.

Libs/frameworks may have to tell users to map or alias to `src/Three.js` and `src/Three.WebGPU.js` to avoid duplicates (downside of more separate HTTP requests with importmap, but at least it will be duplicate free), although currently this causes a false duplicate instance warning.

To alleviate this issue and make ecosystem migration easier, being able to import both renderers without the duplicate issue would be the key.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 8:52am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/11 "2024-09-05T08:52:47Z")

</div>

@drcmda any thoughts on this for r3f yet?

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 5, 2024, 9:02am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/12 "2024-09-05T09:02:51Z")

</div>

Oh, another option is for a lib/framework to just import everything from `/src` directly, without worrying about the top-level module, f.e. `import ... from 'three/src/renderers/webgpu/WebGPURenderer.js'`, etc, and telling their users to import from src/ files too. This works with plain ESM with the most minimal importmap:

```javascript
           "three/": "/node_modules/three/",

```

An advantage of importing from `src/` for HTTP/3 module servers is only the files directly imported can be sent to the client in a single request (similar to a bundle, but smaller payload if not everything from Three is imported).

A user can optimize their app separately using any bundler they want. The current issue we have is that Three lib pre-optimizes with its own build, but now we have the two bundles instead of one.

Downside of this is if the user installs some other Threejs lib that imports from one of the bundles, then the user in that case needs to make sure to update the importmap or build tool alias to point to `src/Three.*.js`.

---

<div class="post-metadata">

**Author:** ![sunag](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/sunag/32/29472_2.png) [@sunag](https://discourse.threejs.org/u/sunag)\
**Post date:** [September 6, 2024, 3:42am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/13 "2024-09-06T03:42:28Z")

</div>

For `WebGPURenderer` only use `three.webgpu.js`, never import both together. All classes from `three.js` including TSL with the exception of `WebGLRenderer` are included in `three.webgpu.js`.

Many classes have been modified like `PMREMGenerator`, so if you just import `WebGPURenderer` in `three.module.js` things will probably break at some point.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 6, 2024, 4:13am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/14 "2024-09-06T04:13:59Z")

</div>

> [@sunag](#):
>
> For `WebGPURenderer` only use `three.webgpu.js`, never import both together. All classes from `three.js` including TSL with the exception of `WebGLRenderer` are included in `three.webgpu.js`.

Thing is Lume needs to support WebGLRenderer too, for back compat, until WebGL stabilizes, so while I add WebGPU support, it will be optional, something like:

```html
<lume-scene mode="webgl"></lume-scene>
<!-- or -->
<lume-scene mode="webgpu"></lume-scene>

```

For that reason Lume source needs to be able to import both. Would be more hassle to make two separate versions of Lume (like three.module and three.webgpu).

> [@sunag](#):
>
> so if you just import `WebGPURenderer` in `three.module.js` things will probably break at some point.

There’s only one WebGPURenderer though right? I can import either one from `src/` directly (instead of bundles) to avoid duplicate Three.js code:

```js
import WebGPURenderer from 'three/src/renderers/webgpu/WebGPURenderer.js'
import WebGLRenderer from 'three/src/renderers/WebGLRenderer.js'

```

EDIT: Ah wait, there’s two as of a few days ago: `WebGPURenderer.js` and `WebGPURenderer.Nodes.js` (brand new), which differ by `StandardNodeLibrary` and `BasicNodeLibrary` respectively but otherwise are the same. What’s that difference for?

---

<div class="post-metadata">

**Author:** ![drcmda](https://avatars.discourse-cdn.com/v4/letter/d/91b2a8/32.png) [@drcmda](https://discourse.threejs.org/u/drcmda)\
**Post date:** [September 6, 2024, 4:51am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/15 "2024-09-06T04:51:32Z")

</div>

Imo a bug that three has to resolve. You can use bundler aliases but a library shouldn’t export like that.

---

<div class="post-metadata">

**Author:** ![LukeWood](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lukewood/32/14835_2.png) [@LukeWood](https://discourse.threejs.org/u/LukeWood)\
**Post date:** [September 12, 2024, 2:46am UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/16 "2024-09-12T02:46:25Z")

</div>

I also agree that the current exporting situation really does not play nice with standard bundler tools. I think this will be a pretty big bottleneck in adoption of TSL for more serious projects.

The only way I’ve been able to make the imports work in my project is by importing from the direct source files in my source:

```javascript
import WebGPURenderer from 'three/src/renderers/webgpu/WebGPURenderer.js'

```

This is clearly suboptimal imo.

---

<div class="post-metadata">

**Author:** ![donmccurdy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/donmccurdy/32/33209_2.png) [@donmccurdy](https://discourse.threejs.org/u/donmccurdy)\
**Post date:** [September 13, 2024, 2:43pm UTC](https://discourse.threejs.org/t/import-from-three-tsl-warning-multiple-instances-of-three-js-being-imported/70303/17 "2024-09-13T14:43:25Z")

</div>

Ongoing [discussion of how to resolve this](https://github.com/mrdoob/three.js/issues/29156), agreed this is something we’ll need to fix in the library’s packaging for the WebGPU builds.
