In npm why do module imports from examples/jsm use 'three'. This causes errors in all browsers

I just upgraded to the latest npm version of three.js - 0.132.2. This causes my app to fail in all browsers with this error:

index.html:1 Uncaught TypeError: Failed to resolve module specifier “three”. Relative references must start with either “/”, “./”, or “…/”.

I poked around and noticed that in the three.js repo imports from examples/jsm use ‘build/three.module.js’ while in the npm version they use ‘three’. This throws an error in all browsers preventing my app from running.

Can the npm version be changed to use ‘build/three.module.js’?


Packages published to NPM are meant to be used with a build tool or bundler. Changing the files as you mention above would cause issues with the other parts of the NPM ecosystem.

If you are managing dependencies as static files, you may want to get the files from GitHub instead, or make the necessary changes to the files from NPM.

In general I would recommend using a build tool or bundler like Webpack, Parcel, or Snowpack for a JS application with dependencies.

I am using rollup for bundling. Do you have an example config for rollup - or simiilar bundler - that solves the error issue?

For example here is how I currently import

import * as THREE from "../node_modules/three/build/three.module.js";
import { mergeBufferGeometries } from '../node_modules/three/examples/jsm/utils/BufferGeometryUtils.js';

This allows me to run the app and debug without having to repeatedly bundle. I only really need to bundle when I publish for others to use the app.

Typical usage with Rollup would be:

import * as THREE from 'three';
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';

I’m not aware that prefixing with ../node_modules/ would cause bundling to be necessary less often than the syntax above, it seems like it shouldn’t.

EDIT: From rollup’s documentation, you may need @rollup/plugin-node-resolve or a similar resolution plugin when using NPM packages.

that would break. package.json has multiple definitions of “three”, hands them out according to the env (browser, esm, cjs, …). bypass that and you destroy namespaces, and essentially you’ll bundle three multiple times in some situations.

like @donmccurdy said, for rollup you need @rollup/plugin-node-resolve, after that everything will be fine. other bundlers have node resolution preconfigured. it’s not in rollup because it’s usually not being used as a client bundler, it’s mostly for packing up distributed libraries.

The issue for me is I do my development unbundled. The ‘three’ with no suffix does not work with an unbundled development workflow.

You can’t use npm or rely on dependencies in that case. Unless you use import maps which is the canonical solution. You can also use script tags and fetch from three/examples/js, or use cdn bundlers, threejs recommends unpkg or skypack.