Using webpack, threejs examples, and typescript?

I was able to bundle OrbitControls with (webpack v2 + ts-loader) and no other loaders.

package.json:

"dependencies": {
    "three": "^0.85.2",
    "@types/three": "^0.84.12",
    "ts-loader": "^2.1.0",
    "typescript": "^2.3.4",
    "webpack": "^2.6.1"
},

entrypoint.ts:

import * as THREE from "three";

// OrbitControls.js expects a global THREE object
(window as any).THREE = THREE;

// NOTE: OrbitControls must be included with require:
// using "import" cause it to be executed before global THREE becomes available
require("three/examples/js/controls/OrbitControls");

// ... code that uses THREE and THREE.OrbitControls

NOTE: webpack may warn like "export 'OrbitControls' (imported as 'THREE') was not found in 'three', because OrbitControls.js is not a proper JS module. I suppose we can just ignore this warning.


Here's what worked for me.

$ npm install --save-dev exports-loader imports-loader

Then, to use something from three/examples/js, I do this:

const THREE = require('three');
// imports provides THREE to the OrbitControls example
// exports gets THREE.OrbitControls
THREE.OrbitControls = require('imports?THREE=three!exports?THREE.OrbitControls!../../node_modules\/three\/examples\/js\/controls\/OrbitControls');

// use THREE.OrbitControls ...

I think the right thing to do is use the imports and exports loaders by config rather than embedding them in the require. I'll update this answer when I have an example.


I managed to find a pretty clean way to set this up in webpack.config.js.

As per Dan's answer:

$ npm install --save-dev imports-loader

It turns out we don't actually need exports-loader, since the three.js examples add their constructors to the THREE object.

Then, in webpack.config.js, we can add a rule to add var THREE = require('three'); to an imported module if the module's path resolves to anything containing three/examples/js:

module: {
  rules: [
    ...
    {
      test: /three\/examples\/js/,
      use: 'imports-loader?THREE=three'
    }
  ]
}

Now the example modules will find the THREE global when they expect it.

Then, to make importing examples a little less verbose:

resolve: {
  alias: {
    'three-examples': path.join(__dirname, './node_modules/three/examples/js')
  },
  ...
},

This assumes that webpack.config.js is in the same directory as node_modules, adjust accordingly.

Now, we can use the example files like so:

import * as THREE from 'three';
import 'three-examples/controls/OrbitControls';

to import the module for its side-effects.

If you're using this with Typescript and/or Babel and are getting warnings about the example module not being found on THREE, you may find this issue on the imports-loader repository useful to reference.


I will try to answer just the part of your question regarding TypeScript and ThreeJS integration within your IDE.

As you've seen, most of the components are hosted on the DefinitelyTyped archives. I do recommend stop using tsd and migrate to typing.

A basic typings.json that typing will consume is listed below. It gets the latest main ThreeJS and the effect composer library to be recognized by TypeScript. Note the commit hashtags will change as the .tsd evolves.

{
  "ambientDependencies": {
    "three": "github:DefinitelyTyped/DefinitelyTyped/threejs/three.d.ts#c6c3d3e65dd2d7035428f9c7b371ec911ff28542",
    "three-projector": "github:DefinitelyTyped/DefinitelyTyped/threejs/three-projector.d.ts#48f20e97bfaf70fc1a9537b38aed98e9749be0ae",
    "three-detector": "github:DefinitelyTyped/DefinitelyTyped/threejs/three-effectcomposer.d.ts#48f20e97bfaf70fc1a9537b38aed98e9749be0ae",
    "three-effectscomposer": "github:DefinitelyTyped/DefinitelyTyped/threejs/detector.d.ts#48f20e97bfaf70fc1a9537b38aed98e9749be0ae",
    "three-shaderpass": "github:DefinitelyTyped/DefinitelyTyped/threejs/three-shaderpass.d.ts#ee05b1163d8da7f16719f08d52f70ab524f1003a"
  }
}

Attached is a snapshot of an IDE recognizing the public methods of the EffectsComposer. You may want to also experiment with different module loader capabilities of TypeScript.

TypeScript within the IDE recognizes the ThreeJS libraries