Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using webpack, threejs examples, and typescript?

I'm having a lot of trouble getting stuff in threejs's examples (like EffectComposer or Detector) to work with webpack and typescript.

First off the relevant *.d.ts files are all present and installed via tsd. My problem is getting webpack to actually include files outside of the default threejs build (namely things in examples/js/).

With three installed from npm I can do something like

import THREE = require('three');

Which works fine but lacks any of the aforementioned goodies. There are a few other threejs packages on npm that bundle plugins but I don't think they work with typescript (since require('three-js')(['EffectComposer']) is rejected by the typescript compiler.

Has anyone gotten something in this package (like postprocessing) to work with typescript?

like image 418
Ryan N Avatar asked Mar 13 '16 08:03

Ryan N


2 Answers

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.

like image 57
Chris Williamson Avatar answered Oct 10 '22 08:10

Chris Williamson


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.

like image 24
Jokester Avatar answered Oct 10 '22 10:10

Jokester