How to import a Three.js loader into an Angular 6 project
I've finally reached two working solutions (=> workarounds to be precise).
Using Webpack's imports-loader
[...] import-loader is a Webpack plugin allows you to inject a global variable into your module's scope. So the global (
!
) namespace of your execution context still remains completely clean, but during "compilation", Webpack will be able to figure out where to lookup the binding for a module that only comes with a global variable.
import "imports?THREE=three!loaders/BinaryLoader";
Using this import we tell Webpack to use THREE
as a global variable defined by the npm module 'three'
and the BinaryLoader wont be binded to any variable.
Use three-full to provide the THREE namespace
The project three-full extends the namespace defined by the standard three.js library adding several "examples" like loaders and controls. Using it instead of the classical three
npm package it will be possible to have full support to ES6 namespaces for the most common and useful classes that usually are part of the great majority of those projects based on three.js.
npm install --save three-full
And then you can import the entire namespace:
import * as THREE from 'three-full';
...
const loader = new THREE.ColladaLoader();
sentenza
I am a software engineer constantly keen on improving my skills and open-minded about cutting edge greenfield technologies, particularly on the web-environment spectrum, since I am firmly convinced that the Internet will become the playground where dev-platforms will flow together.
Updated on June 12, 2022Comments
-
sentenza almost 2 years
I want to extend the type definitions imported into an ng6 project using Three.js (
@types/three/index
) with a set of functions that will be directly attached to the same "namespace". Something like:THREE.myFunction()
. I don't want to declare THREE asany
to suppress the type checking and the linter, and I guess that it would be possible to wrap a vanilla JS function that extend THREE using a TS class/function and then taking advantage oftypings.d.ts
.Importing a loader
First of all, I would like to import a THREE.js loader into my project, and that's normally defined a vanilla function that extends
THREE
.I'm trying to import the
BinaryLoader
into a ng service and I'm not sure about how to do it in the right way.What I have done so far:
npm install three --save
npm install @types/three --save-dev
import * as THREE from 'three';
- add the BinaryLoader to the new angular.json
scripts
array
angular.json
"scripts": [ "./node_modules/three/examples/js/loaders/BinaryLoader.js" ]
So far so good, but now I need to create a binary loader:
import * as THREE from 'three'; // import { BinaryLoader } from 'three'; // import 'three/examples/js/loaders/BinaryLoader'; export class ThreeManagerService { const loader = new THREE.BinaryLoader(); ...
and I have to find the way to add the
BinaryLoader
to@types/three/index
somehow. In that way I should be able to extend the type definitions in order to be able to create a new typeTHREE.BinaryLoader
. Is it possible to do something like that?The warning I got is:
WARNING in ./src/app/shared/three-manager.service.ts 24:25-43 "export 'BinaryLoader' (imported as 'THREE') was not found in 'three'
Silencing Type warnings and the TS transpiler
A workaround to get rid of the warnings and the error might be something like that:
import * as THREEJS from 'three'; declare const THREE: any; export class ThreeManagerService { const loader = new THREE.BinaryLoader();
the fact is that I consider this workaround a very ugly "fix". I would like to use the type system as much as possible.
EDIT: Get examples to play nice with Intellisense & Typescript
While waiting for a complete rewriting of the examples to be compatible with the ES6 modules and namespaces it could be possible to define a local module that exposes and augments the global, in
/src/node_modules/three-extras/index.ts
:import * as THREE from 'three'; declare global { interface Window { THREE: typeof THREE; } } window.THREE = THREE; require('three/examples/js/controls/OrbitControls'); require('three/examples/js/loaders/GLTFLoader');
via: https://github.com/mrdoob/three.js/issues/9562#issuecomment-386522819
Related and useful SO answers:
-
K-Dawg over 4 yearsYou have no idea how long I've been struggling with this. I looked for answers everywhere! Thank you so much!
-
Jacksonkr almost 3 yearsI suspect that @K-Dawg, like myself and I'm sure countless others, expected to be able to use three.js just like most other NPM packages. I'm stunned by my forgetfulness that meshing libraries is complex and fortunately tools like yarn/npm have streamlined that for us. Anyway, thanks for a full answer that provides a range of solution. Many karma upvotes to you.