Issues with importing THREE.js modules - javascript

I'm trying to import the custom geometry "OutlinesGeometry.js" from https://plnkr.co/edit/uEYo6L3pgbIaYXXzVzXd?preview
I'm trying to import following way:
<script type="module" src="./three/build/three.module.js"></script>
<script type="module" src="./three/examples/jsm/controls/OrbitControls.js"></script>
<script type="module" src="./three/examples/jsm/libs/dat.gui.min.js"></script>
<script type="module" src="./OutlinesGeometry.js"></script>
This gives me following errors:
First I did not import three, OrbitControls and dat.gui as modules, as everything worked fine (see imports below). But as soon I'm importing the OutlinesGeometry I received following error: Uncaught TypeError: class constructors must be invoked with 'new'. Because of that I'm importing the modules.
<script src="./three/build/three.js"></script>
<script src="./three/examples/js/controls/OrbitControls.js"></script>
<script src="./three/examples/js/libs/dat.gui.min.js"></script>
<script src="./OutlinesGeometry.js"></script>
How should the imports be done correctly?

The runtime error happens because you are deriving from a ES6 class via ES5 syntax.
In newer releases BufferGeometry is a ES6 class. When creating a custom geometry generator, the following code is invalid:
THREE.BufferGeometry.call( this );
You can only solve this issue by migrating OutlinesGeometry to an ES6 class as well.
BTW: When working with modules, you just have a single <script type="module"></script> tag and use inside of the tag ES6 import syntax. Meaning:
<script type="module">
import * as THREE from './three/build/three.module.js';
import OrbitControls from './three/examples/jsm/controls/OrbitControls.js';
I suggest you study the official three.js example for more details.

Related

Imported three.js module OrbitControls "not defined"

Javascript and HTML newbie here:
I'm trying to display a 3D model (.gltf file) in a website with controls (pan, zoom, etc.), using the javascript three.js OrbitControls module. In spite of using <script type="module"> tags in the HTML to load OrbitControls, when I try to load the page, I get Uncaught ReferenceError: OrbitControls is not defined from firefox. I can successfully render the image if I do not include the statement defining the controls, but do include the import tag.
Brief code:
--HTML:
<head>
<!-- Imports for three.js and GLTFLoader.js, both seem to be working -->
<script type="module">
import { OrbitControls } from "https://unpkg.com/three/examples/jsm/controls/OrbitControls.js";
</script>
<script src="script.js" defer="defer"></script>
</head>
--Javascript (from script.js):
"use strict";
function main() {
//Create render and camera objects; both work when not using controls
const controls = new OrbitControls( camera, renderer.domElement );
// create scene, GLTFLoader, run animate function
}
const obj_returned = main();
I've tried a few different styles of the script command:
<script type="module"> import { OrbitControls } from "https://unpkg.com/three/examples/jsm/controls/OrbitControls.js"; </script>
This gives the Uncaught ReferenceError: OrbitControls is not defined error,
<script type="module" src="https://unpkg.com/three/examples/jsm/controls/OrbitControls.js">
produces the same error, and
<script src="https://unpkg.com/three/examples/jsm/controls/OrbitControls.js"></script>
This actually gives the same error plus Uncaught SyntaxError: import declarations may only appear at top level of a module, I think due to the missing type="module" flag.
All local files are in the same directory.
I've looked at several other examples of this sort of thing to see what I'm missing (like here, here, here, the three.js documentation, the OrbitControls source code, and several others).
I'm very new to JS and HTML, so 1) it's likely something very obvious and 2) if it's not trivial / a typo, I would appreciate a little explanation as to why this doesn't work so I can avoid similar mistakes in the future. Thanks!

When I try type="module" get this Error ( Uncaught ReferenceError: loadFoods is not defined)

When I use type="application/javascript" everything is okay.
<script type="module" src="./assets/scripts/homepage.js></script>
<script>
loadFoods()
</script>
Variables inside modules are scoped to those modules.
They aren't designed to create global variables (although there are hacky ways to achieve that).
The <script> element should be the entry point to the program, not a means to load a dependency. That is what import is for.
Your approach should be something more along the lines of:
<script type="module">
import {loadFoods} from "./assets/scripts/homepage.js";
loadFoods();
</script>
Obviously the homepage module needs to explicitly export the loadFoods function.

Why Stats.min.js can only be imported by `script src=` but not `import`?

I have Javascript codes as below. When the importation is inside <script src="..."></script>, it works. However, if I moved the importation to import ...;, it doesn't work. The error message is: "Uncaught ReferenceError: Stats is not defined".
Why is that? Since I am working on a Jekyll site, I prefer to do the import ...; way to make sure other elements of the site work. Any idea how to do the import ...; way without error?
It works
<div id="stats"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script type="module">
const stats = new Stats()
stats.setMode(0)
document.getElementById('stats').appendChild(stats.domElement)
</script>
It doesn't work
<div id="stats"></div>
<script type="module">
import 'https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js';
const stats = new Stats()
stats.setMode(0)
document.getElementById('stats').appendChild(stats.domElement)
</script>
import allows you to import JavaScript modules which conform to the ES6 module format.
Stats.min.js does not. The code is obfuscated but appears to create a global and support the old CommonJS module format.

How to import es6 module that has been defined in <script type="module"> tag inside html?

I am able to define a module in my html file me.html:
<script type="module" id="DEFAULT_MODULE">
import Atom from './atom.js';
console.log("definition of getAtom")
export default function getAtom(){
return new Atom('atom');
}
console.log("exported getAtom")
</script>
Also see
https://blog.whatwg.org/js-modules
https://github.com/whatwg/html/pull/443#issuecomment-167639239
=> Is it possible to import that "anonymous" module to another module script in the same html file? Or to some "code behind"- JavaScript file that also has been loaded by the me.html file? The export seems to work; at least it does not throw any error.
For the import of the getAtom method I tried for example:
<script type="module">
import getAtom from '.'; //this line does not work
console.log("usage of getAtom")
var atom = getAtom();
</script>
I would expect some syntax like
import getAtom;
import getAtom from '.';
import getAtom from window;
import getAtom from './me.html';
import getAtom from '.DEFAULT_MODULE';
However, none of these lines worked.
=>What is the correct syntax to reference the "anonymous" module if it is possible at all?
I use Chrome version 63.0.3239.108.
Related question:
How to dynamically execute/eval JavaScript code that contains an ES6 module / requires some dependencies?
As I understand, there is no way to import "anonymous" module, because "anonymous" module have no module specifier or individual url (its import.meta.url is just the html url as current spec). In theory it can be extended in the future, but I can not find the good use cases for such feature.

ES6 modules in the browser: Uncaught SyntaxError: Unexpected token import

I'm new to ES6 (ECMAScript 6), and I'd like to use its module system in the browser. I read ES6 is supported by Firefox and Chrome, but I'm getting the following error using export
Uncaught SyntaxError: Unexpected token import
I have a test.html file
<html>
<script src="test.js"></script>
<body>
</body>
</html>
and a test.js file
'use strict';
class Test {
static hello() {
console.log("hello world");
}
}
export Test;
Why?
Many modern browsers now support ES6 modules. As long as you import your scripts (including the entrypoint to your application) using <script type="module" src="..."> it will work.
Take a look at caniuse.com for more details:
https://caniuse.com/#feat=es6-module
You can try ES6 Modules in Google Chrome Beta (61) / Chrome Canary.
Reference Implementation of ToDo MVC by Paul Irish - https://paulirish.github.io/es-modules-todomvc/
I've basic demo -
//app.js
import {sum} from './calc.js'
console.log(sum(2,3));
//calc.js
let sum = (a,b) => { return a + b; }
export {sum};
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>ES6</h1>
<script src="app.js" type="module"></script>
</body>
</html>
Hope it helps!
Unfortunately, modules aren't supported by many browsers right now.
This feature is only just beginning to be implemented in browsers natively at this time. It is implemented in many transpilers, such as TypeScript and Babel, and bundlers such as Rollup and Webpack.
Found on MDN
it worked for me adding type="module" to the script importing my mjs:
<script type="module">
import * as module from 'https://rawgit.com/abernier/7ce9df53ac9ec00419634ca3f9e3f772/raw/eec68248454e1343e111f464e666afd722a65fe2/mymod.mjs'
console.log(module.default()) // Prints: Hi from the default export!
</script>
See demo: https://codepen.io/abernier/pen/wExQaa
It could be that you changed an existing script to a module and forgot to remove the original script tag. This is what happened to me and how I got directed to this page. I had originally had this:
<script src="app.js" defer></script>
Then I changed my main script tag to import it as a module and it was working, but I still received the error. I couldn't figure out how it could be working and throwing an error, but I had forgotten to remove the original script tag.

Categories