3

I am using ThreeJS ES6 native modules directly in the browser. It's a really cool feature where you can just import ThreeJS from your javascript files without any module bundler.

The following works in javascript:

import * as THREE from './lib/three.module.js'
import { OrbitControls } from './lib/OrbitControls.js'

Now I want to do this in Typescript, I installed the typescript definitions using

npm install --save @types/three 

But VS Code still can't find the type declaration files:

⚠️ Could not find a declaration file for module '../lib/three.module.js'

⚠️ Could not find a declaration file for module '../lib/OrbitControls.js'.

As suggested in the comments I changed the imports to

import * as THREE from 'three'
import { OrbitControls } from three/examples/jsm/controls/OrbitControls'

Now the declarations are found, but typescript can't find the modules!

⚠️ An accessor cannot be declared in an ambient context and Failed to resolve module specifier "three".

⚠️ Relative references must start with either "/", "./", or "../".

How can I use ES6 native modules from ThreeJs in my Typescript project without a module bundler?

Kokodoko
  • 26,167
  • 33
  • 120
  • 197

4 Answers4

2

You just have to create a .d.ts file with the same name as the library -- in your case, ./lib/three.module.d.ts. When you import * as Three from "./lib/three.module.js", Typescript will look for a sibling typings file as part of the module resolution strategy. In this file, you can simply export types that describe the shape of the module. In your case, you should be fine with just

import * as Three from "three";
export = Three;
Coderer
  • 25,844
  • 28
  • 99
  • 154
  • hm this seems promising! The `.d.ts` file didn't seem to get picked up right away, but maybe I did something wrong. Will fuss with it a bit later :) – Peter Ehrlich Sep 02 '22 at 14:57
1

Try to organize your imports like so:

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
Mugen87
  • 28,829
  • 4
  • 27
  • 50
  • 1
    Thanks, now type checking works, but when compiling I get: `An accessor cannot be declared in an ambient context` and `Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../".` – Kokodoko May 27 '21 at 19:37
  • What version of TypeScript are you using? – Mugen87 May 28 '21 at 08:30
  • Version 3.4.5. After lots of trial and error, I couldn't get native modules working with typescript compilation. So now I just installed `npm install three` and use a module bundler. This works. I still don't know if native modules can work with typescript though. – Kokodoko May 28 '21 at 19:59
1

Another possible solution from Jamesernator over at the TypeScript Github Issues: just add this to your html:

<script type="importmap">
            {
                "imports": {
                    "three": "./js/lib/three.module.js"
                 }
            }    
 </script>

And the browser will do the remapping. Neat!

https://github.com/microsoft/TypeScript/issues/50600

Peter Ehrlich
  • 6,969
  • 4
  • 49
  • 65
0

So it looks like you have to use an alias for declaration files, and aliases are not supported by es6 native import statements. This is not addressed at all in the docs: https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html

Some people resolve this by adding a whole honkin build pipeline, but that level of complexity was not for me: Typescript declaration file created with alias instead of relative path

Instead I used tsc-watch and a minimal bash script: https://www.npmjs.com/package/tsc-watch

$ tsc-watch --onSuccess "./mysed"

$ cat ./mysed
#!/bin/bash

# use *js to capture .mts as well as .js
sed -i "" "s/import \* as THREE from 'three';/import \* as THREE from '.\/lib\/three\.module\.js';/" js/*js;

This replaces import * as THREE from 'three'; in my .ts with import * as THREE from './lib/three.module.js' in my JS, allowing me to reference the typed version in dev and the non typed version in prod. Whew!

Peter Ehrlich
  • 6,969
  • 4
  • 49
  • 65