14

i have this simple js sample which i test via visual studio code with live preview server build in: i don't use node.js in this sample all js files under js dir :

C:\Dev\my\javascript\ThreeJS\tests\js>ls -1
GLTFLoader.js
OrbitControls.js
main.js
three.js
three.min.js
three.module.js

HTML:

but i keep getting this general error :

   Uncaught TypeError: Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../".
<html>
    <head>
        
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta charset="UTF-8" />
        <title>My first three.js app</title>
        <link href="main.css" rel="stylesheet" type="text/css">
        <script type="module" src="js/main.js"></script>
    </head>
    <body>
        <div id="scene-container">
            <canvas></canvas>
        </div>
    </body>
</html>

in js/main.js

import {
  BoxBufferGeometry,
  Color,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
} from 'three';

// Get a reference to the container element that will hold our scene
const container = document.querySelector('#scene-container');

// create a Scene
const scene = new Scene();

// Set the background color
scene.background = new Color('skyblue');

// Create a camera
const fov = 35; // AKA Field of View
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1; // the near clipping plane
const far = 100; // the far clipping plane

const camera = new PerspectiveCamera(fov, aspect, near, far);

// every object is initially created at ( 0, 0, 0 )
// move the camera back so we can view the scene
camera.position.set(0, 0, 10);

// create a geometry
const geometry = new BoxBufferGeometry(2, 2, 2);

// create a default (white) Basic material
const material = new MeshBasicMaterial();

// create a Mesh containing the geometry and material
const cube = new Mesh(geometry, material);

// add the mesh to the scene
scene.add(cube);

// create the renderer
const renderer = new WebGLRenderer();

// next, set the renderer to the same size as our container element
renderer.setSize(container.clientWidth, container.clientHeight);

// finally, set the pixel ratio so that our scene will look good on HiDPI displays
renderer.setPixelRatio(window.devicePixelRatio);

// add the automatically created <canvas> element to the page
container.append(renderer.domElement);

// render, or 'create a still image', of the scene
renderer.render(scene, camera);
user63898
  • 29,839
  • 85
  • 272
  • 514

7 Answers7

17

The following is my code when using cdn without webpack/node.js.

#index.html

<head>
    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/three@0.138.0/build/three.module.js",
                "OrbitControls": "https://unpkg.com/three@0.138.0/examples/jsm/controls/OrbitControls.js"
            }
        }
    </script>
</head>
<body>
  <script type="module" src="js/test.js"></script>
</body>

#test.js

import * as THREE from 'three';
import { OrbitControls } from 'OrbitControls';

scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
controls = new OrbitControls(camera, renderer.domElement);

ref: https://jspm.org/import-map-cdn

This is because unlike other web resources, the JS modules specification for HTML reserved the space of these non-relative references (called "bare specifiers") exactly to allow custom package imports via import maps.

ouflak
  • 2,458
  • 10
  • 44
  • 49
Jerry
  • 499
  • 6
  • 5
  • It still doesn't work. Still the same error message. How to use Three.js correctly on static hosting without NPM? Or use this unpkg.com? – arrowman Oct 25 '22 at 11:50
6

Also since 26th of January this year three.js released r137 update and since r137 using ES6 modules like GLTFLoader in the browser requires an import map.

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

The three.js import statement in your scripts.js looks like so then:

import * as THREE from 'three'

https://github.com/Kramzin/threejs-task - Here you can see updated and previous code, after these changes everything is working.

Rim
  • 116
  • 2
  • 6
  • For some reason, my laptop seems not to recognize "importmap" at all, so I have to make direct link to file three.module.js to solve the problem. – Wisarut Bholsithi Apr 19 '22 at 15:20
5

write namespace THREE and import like this.....

  import * as THREE from 'fileUrl';

for more info go to this link https://discoverthreejs.com/book/introduction/get-threejs/

Sanoodia
  • 830
  • 4
  • 9
  • i can't use import if i dont use node.js ? – user63898 Jan 13 '21 at 11:14
  • Import statement is used in es6 instead of required statement, so yes you can use this statement if you are not using node.js. – Sanoodia Jan 13 '21 at 12:55
  • This solution does not work when I have run on Mozilla Firefox. It causes "Uncaught Error: Unable to resolve specifier 'fileUrl' from http://localhost:3000/examples/?0 throwUnresolved https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js:786 d .... Need better alterantive solution. – Wisarut Bholsithi Apr 19 '22 at 13:57
3

I understand your question as follows: You want to include the distributed three.js file into your HTML file without bundling your code (using e.g. webpack). If that's the case, you should not use import in your own code, but rather globally import the dependency (three) into your HTML file. This will expose the THREE object into the global namespace. Then, in your JavaScript file, you automatically have access to the global variables. You can directly access the module (without referencing to it).

Here is an example (taken and adapted from the official documentation):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My first three.js app</title>
        <style>
            body { margin: 0; }
        </style>
    </head>
    <body>
    <script src="js/three.js"></script>
    <script src="js/my-script.js"></script>
</body>

my-script.js:

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

To reuse your existing code, you can use the spread operator and break down the global variable into your now imported ones:

const {
  BoxBufferGeometry,
  Color,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
} = window.THREE;
ssc-hrep3
  • 15,024
  • 7
  • 48
  • 87
  • Thanks ! so webpack is just node.js thing? – user63898 Jan 13 '21 at 11:50
  • 1
    @user63898 webpack is a tool which lets you program for the front-end in regular JavaScript modules, similar to Node.js modules. It then bundles your code together and creates at the end one `.js` file which you can add to your HTML. This file does then contain all your code, but without import/export statements. Webpack uses Node.js as its runtime. The bundled files do not require Node.js anymore though. – ssc-hrep3 Jan 13 '21 at 12:17
1

if you are using 'three' package from npm thenyou need to install that pakage in terminal and import like this

import * as THREE from './js/three.module.js';

or
import {
  BoxBufferGeometry,
  Color,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
} from 'three';
Sanoodia
  • 830
  • 4
  • 9
1

The following worked for mee..

//import * as THREE from 'three'; // somehow this does not work    
import * as THREE from './node_modules/three/build/three.module.js';

with following directory structure and installation as per Three.js installation page...

/node_modules
index.html
main.js
mhk
  • 436
  • 6
  • 14
0

My solution is to make a correct directory link to file three.module.js according to the solution from ThreeJS discourse for Mozilla Firefox case when importmap of script is not working by changing from:

import * as THREE from 'three';

to be the correct directory to file three.module.js according to this example depended upon the place of the html file or javascript file that cause the trouble :

import * as THREE from '../build/three.module.js';