Uncaught SyntaxError: Cannot use import statement outside a module - javascript

https://www.youtube.com/watch?v=1TeMXIWRrqE
<!DOCTYPE html>
<html>
<head>
<title>Three.js</title>
<style type="text/css">
html, body {margin: 0; padding: 0; overflow: hidden}
</style>
</head>
<body>
<div id="webgl"></div>
<script src="three.js"></script>
<script src="GLTFLoader.js"></script>
<script>
let scene,camera,renderer;
function init(){
scene = new THREE.Scene();
scene.background = new THREE.Color(0xdddddd);
camera = new THREE.PerspectiveCamera(40,window.innerWidth/window.innerHeight,1,5000);
hlight = new THREE.AmbientLight(0x404040,100);
scene.add(hlight);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth,window.innerHeight);
document.getElementById('webgl').appendChild(renderer.domElement);
let loader = new THREE.GLTFLoader(); //THE ERROR WITH THIS, I TRIED WITHOUT THREE. ONLY GLTLOADER() BUT DID NOT WORK
loader.load('scene.gltf', function(gltf){
scene.add(gltf.scene);
renderer.render(scene,camera);
});
}
init();
</script>
</body>
</html>
https://sketchfab.com/3d-models/1972-datsun-240k-gt-non-commercial-use-only-b2303a552b444e5b8637fdf5169b41cb
//https://www.youtube.com/watch?v=1TeMXIWRrqE
This is tutorial for GLTFLOADER , i imported same 3d file as well and written same code, but when i open the file on local server, i get 2 errors in console:
1) "GLTFLoader.js:9 Uncaught SyntaxError: Cannot use import statement outside a module"
2) "(index):29 Uncaught TypeError: THREE.GLTFLoader is not a constructor."
Although in youtube video it opens with him immediatly!! :(
I would be greatful if anybody can hep me out with this. THANK YOU SO MUCH
GLTFLoader.js:9 Uncaught SyntaxError
(index):29 Uncaught TypeError

Here's a newer tutorial. The bottom of this article explains what changed.
The short version is three.js changed to prefer using es6 modules so instead of
<script src="three.js"></script>
<script src="GLTFLoader.js"></script>
<script>
let scene,camera,renderer;
function init(){
...
THREE.GLTFLoader.load(...
you'd do this
<script type="module">
import * as THREE from './build/three.module.js';
import {GLTFLoader} from './examples/jsm/loaders/GLTFLoader.js';
let scene,camera,renderer;
function init(){
...
GLTFLoader.load(...
But to use it like that requires you copy the three.js files to the same folder structure.
someFolder
|
├-build
| |
| +-three.module.js
|
+-examples
|
+-jsm
|
+-controls
| |
| +-OrbitControls.js
| +-TrackballControls.js
| +-...
|
+-loaders
| |
| +-GLTFLoader.js
| +-...
|
...
If you want to use the old method <script> tag style then you need to make sure you use the files from the js folder, not the jsm folder
Note: You must use this folder structure because the files in the examples/jsm folder like GLTFLoader.js refer to various other files like three.module.js via relative but hard coded paths. For example in GLTFLoader.js there is a line which is effectively
import {stuff} from "../../../build/three.module.js";
A couple of advantages to the new style are
the various modules can pull in the other parts they need.
In the past to use one extra part you might need to add 1 to 10 other <script> tags. Now you just need 1 import and that part can pull in the other 1 to 10 parts on it's own
If you build your page with a web builder it can strip out the parts you are not using.
Rumor is there are plans to get rid of the <script> method completely at some point in the future.
Just to try to make it clear both why ES6 modules are better and why you need to keep the same structure.
In pre r105 to use the EffectComposer you'd do this
<script src="threejs/examples/js/postprocessing/EffectComposer.js"></script>
You run and you'd get an error
THREE.EffectComposer relies on THREE.CopyShader
So you'd dig around to find it, it's not in the same folder as EffectsComposer.js. When you finally find it you add it
<script src="threejs/examples/js/postprocessing/EffectComposer.js"></script>
<script src="threejs/examples/js/shaders/CopyShader.js"></script>
Run again and get another error THREE.EffectComposer relies on THREE.ShaderPass so again digging around you add that
<script src="threejs/examples/js/postprocessing/EffectComposer.js"></script>
<script src="threejs/examples/js/shaders/CopyShader.js"></script>
<script src="threejs/examples/js/postprocessing/ShaderPass.js"></script>
That sucked.
Now as of r105 using es6 modules you can just do
import {EffectComposer} from './threejs/examples/jsm/postprocessing/EffectComposer.js';
Which is arguably much nicer. You won't get the other errors because the ES6 module version EffectComposer.js can reference the files it needs, its dependencies, itself. At the top of EffectComposer.js are the references to its dependencies.
import {
Clock,
LinearFilter,
Mesh,
OrthographicCamera,
PlaneBufferGeometry,
RGBAFormat,
Vector2,
WebGLRenderTarget
} from "../../../build/three.module.js";
import { CopyShader } from "../shaders/CopyShader.js";
import { ShaderPass } from "../postprocessing/ShaderPass.js";
import { MaskPass } from "../postprocessing/MaskPass.js";
import { ClearMaskPass } from "../postprocessing/MaskPass.js";
But, as you can see above, EffectsComposer.js expects that three.module.js is in a folder called build 3 subfolders down from itself. It expects CopyShader.js is in a folder called shaders one folder down from itself. Etc...
In other words, it needs the same folder structure.

I faced a similar issue, this is how I solved it.
In your HTML, the order matters when adding other scripts as it needs certain things from Three.js.
It should be
<script src="../build/three.min.js"></script>
<script src="three.js-master/examples/js/controls/OrbitControls.js"></script>
<script src="three.js-master/examples/js/loaders/GLTFLoader.js"></script>
I would suggest trying to import from your local javascript folder instead of using from jsm. I hope this will solve your issue.

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!

Cannot use console.log() in a module

I'm trying to understand how to use modules in javascript.
But it seems that if I import a module, then I cannot log anything to console.
Here's my code:
index.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="js/scene.js" type="module"></script>
<script src="js/main.js" type="module"></script>
</body>
</html>
scene.js:
class Scene {
constructor() {
console.log("Scene created");
}
}
export default Scene;
main.js:
import { Scene } from './js/scene.js';
var scene = new Scene();
console.log("Hello World");
The Expected Result:
Scene created
Hello World
The Result I Get:
Nothing (No Result)
What is wrong with my code and how can I properly use a module?
I see 3 mistakes
in index.html the first script tag is useless.
import is relative to script file, not html.
Scene.js export a default value not a variable named Scene.
solutions:
import Scene from './scene.js';
or
remove default in Scene.js, and import {Scene} from './scene.js';
In your scenario, I believe that line 1 of main.js is throwing an error. In your index.html file, you're suggesting that you have a folder named js with both javascript modules in it; however, in the main.js file, you're suggesting that scene.js is at path js/js/scene.js.
You probably meant import { Scene } from './scene.js';.
You should open your browser's console to view any errors.
For example, if you are using Google Chrome, becoming familiar with the Chrome Devtools will be invaluable in allowing you to resolve bugs like this one by yourself in the future.
The Chrome Devtools console will allow you to view errors in your website, which will give you an immediate answer on what is wrong. In addition, setting breakpoints will allow you to step-through each line of code and trace the flow of executed lines of code and the value of variables at each point in time.
Learn more here: https://developers.google.com/web/tools/chrome-devtools/javascript

Browsers support module imports, how do I use it?

I'm trying to figure out why my script tags don't work in my html file, and I came across an article that says you can import modules into browsers via a script tag with a module type. Directly from this site: https://www.sitepoint.com/understanding-es6-modules/
<script type="module" src="./main.js"></script>
// or
<script type="module">
import { something } from './somewhere.js';
// ...
</script>
So then I tried it and the imported module is recognized but getting this error Can't find variable World is it because my example.js file doesn't have it in its scope? I don't understand the order in which they are "processed?" don't know the terminology sorry.
My attempt below
//HTML
<body>
<script type="module">
import { World, Ball, Paddle, Brick, Hud} from "./brickbreakclasses.js"
</script>
<script src="example.js"></script>
</body>
example.js file
// commented this part out because it was imported in html file
// import { World, Ball, Paddle, Brick, Hud } from "./brickbreakclasses";
var canvas = new World(document.getElementById("canvas") );
var ball = new Ball(canvas)
var brick = new Brick(canvas)
var hud = new Hud(canvas)
var paddle = new Paddle(canvas)
I hope this makes sense but I really want to understand why I can't just require or import something in JS file and add it to html via script. I've been using webpack to bundle everything and putting that into my html.However I'm now making a npm package and I hear people don't like pre-bundled packages so I'm trying to find a way for a user to use my modules in html without having to install webpack or something like it.
Variables declared inside a <script type="module"> are local to that module. Make example.js a module, import the classes from there, and you can use them:
HTML
<body>
<script type="module" src="example.js"></script>
</body>
example.js
import { World, Ball, Paddle, Brick, Hud } from "./brickbreakclasses.js";
var canvas = new World(document.getElementById("canvas") );
var ball = new Ball(canvas);
var brick = new Brick(canvas);
var hud = new Hud(canvas);
var paddle = new Paddle(canvas);

Javascript classes in ES6, how to import them within other js-files and in html files?

Obviously, I am a beginner and trying to figure out basic staff, so please bear with me!
I have all these files (index.html, app.js and calc.js) in the same folder and their content is shown below.
I have 2 issues:
1: why in file (app.js), importing class Calc and creating a new instance of it works, whereas in file (calc.js) similar process doesn't work with class Test?
2: how could I use the class "Calc" for example in the *.html file?
Note: I am using chrome (62.0.3202.94 (Official Build) (64-bit)) on mac OS 10.13
// app.js
import { Calc } from './calc.js';
class Test {
static hello() {
console.log("hello from class1");
}
}
let c = new Calc(); // this works!
console.log(c.sum(2, 3) + 1); // 6
export { Test };
and
// calc.js
import { Test } from "./app.js";
class Calc {
sum(a, b) {
return a + b;
}
}
let t = new Test(); // Uncaught ReferenceError: Test is not defined
t.hello();
export { Calc };
Finally the HTML file:
<html>
<head>
<meta charset="utf-8" />
<script src="./app.js" type="module"></script>
<script src="./calc.js" type="module"></script>
</head>
<body>
<h1>ES6</h1>
<script>
let c = new Calc();
// simulate input summation from two textboxes for example
console.log(c.sum(2, 1)); //Uncaught ReferenceError: Calc is not defined
</script>
</body>
</html>
Problem 1:
You have a circular dependency - app.js imports calc.js, but calc.js imports app.js.
Usually the module system will ensure all of a module's dependencies are executed before the module itself, but this is impossible when your dependency tree has cycles - it has to pick one of them to run first. In this case, calc.js is run first, at which point Test isn't yet defined!
There are ways to work around this if you're careful, but cyclic dependencies are pretty much always a sign that you're structuring your code wrong - the best solution is to reorganize it so you no longer have a cycle.
Problem 2:
ES2016 modules don't execute in the global scope. If you want to make something available to the window as a whole, you need to be explicit:
window.Calc = Calc;

How to import Javascript file into Ionic/Angular project

For my Ionic 2 app, I'm using the three.js and a PLYLoader extension for three.js (found here: https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/PLYLoader.js)
I'm able to import in three.js just fine, by putting this in my index.html:
<script src="three.js"> </script>
Then in the relevant TypeScript file:
import * as THREE from '../../three.js';
So I'm trying to do the same thing with PLYLoader:
<script src="PLYLoader.js"> </script>
and
import * as PLYLoader from '../../PLYLoader.js';
But whenever I load the page, I get the following error:
ionViewDidLoad error: __WEBPACK_IMPORTED_MODULE_2__three_js__.PLYLoader is not a constructor
Ionic/Angular is obviously able to find the file, but for some reason the TypeScript isn't interpreting the JavaScript class correctly. Is there a reasonable solution to this?
I don't see any exports in PLYLoader. That could be one issue.
On the npm page, it specifically has this code:
const THREE = require("three");
const PLYLoader = require("three-ply-loader");
PLYLoader(THREE);

Categories