It looks like the browser can't recognizing the modules. (script type=importmap & module)

Hey there! I want to use the three.js library with a web builder platform similar to Webflow (I must load it via CDN). However, it seems like I can’t load the script type=importmap and script type=module on this platform’s site. How can I resolve this issue? (I checked the network tab in Chrome DevTools, and there doesn’t seem to be any problem with the MIME type, which is set to application/javascript.)

occured errors:

'Uncaught SyntaxError: Unexpected token ‘:’ (at importmap script)
'Uncaught SyntaxError: Cannot use import statement outside a module (at GLTFLoader.js:1:1)
'Uncaught SyntaxError: Cannot use import statement outside a module ’ ‘Uncaught TypeError: Failed to resolve module specifier “three”. Relative references must start with either “/”, “./”, or “…/”.’

<!DOCTYPE html> 
<head> 
  <style>
    html,
body {
  margin: 0;
  padding: 0;
  font-family: "Courier New", Courier, monospace;
}

#webgl {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: -1;
}

section {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
}

  </style>
</head>
<body>
  
  <main>
    <section>
      <h2>Hello</h2>
    </section>
    <section>
      <h2>Sweet</h2>
    </section>
    <section>
      <h2>Child</h2>
    </section>
  </main>
    <!-- WEBFLOW EMBED START -->
    <canvas id="webgl"></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js"></script>
    <script
      async
      src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"
    ></script>
    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@0.149.0/build/three.module.js",
          "three/addons/": "https://unpkg.com/three@0.149.0/examples/jsm/"
        }
      }
    </script>
    <script type="module">
      import * as THREE from "three";
      import { GLTFLoader } from "three/addons/loaders/GLTFLoader";

      class Experience {
        isHovering = false;
        mouse = { x: 0, y: 0 };
        scrollPos = 0;

        constructor() {
          this.windowResize = this.windowResize.bind(this);
          this.windowScroll = this.windowScroll.bind(this);
          this.mouseMove = this.mouseMove.bind(this);
          this.animate = this.animate.bind(this);

          this.setScene();
          this.setCanvas();
          this.setCameras();
          this.setRenderer();
          this.createBox();
          this.loadFox();
          this.addLights();
          this.setEvents();

          this.clock = new THREE.Clock();

          this.animate();
        }

        setScene() {
          this.scene = new THREE.Scene();
        }

        setCanvas() {
          this.canvas = document.getElementById("webgl");
        }

        setCameras() {
          this.camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
          );
          this.camera.position.z = 5;
          this.scrollPos = this.camera.position.y;
          this.scene.add(this.camera);
        }

        setRenderer() {
          this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas });
          this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio));
          this.renderer.setSize(window.innerWidth, window.innerHeight);
        }

        addLights() {
          const ambientLight = new THREE.AmbientLight();
          this.scene.add(ambientLight);
        }

        createBox() {
          const geometry = new THREE.BoxGeometry(1, 1, 1);
          const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
          this.box = new THREE.Mesh(geometry, material);

          this.group = new THREE.Group();

          this.group.position.y = -2.5;

          this.group.add(this.box);
          this.scene.add(this.group);
        }

        windowResize(e) {
          this.camera.aspect = window.innerWidth / window.innerHeight;
          this.camera.updateProjectionMatrix();

          this.renderer.setSize(window.innerWidth, window.innerHeight);
        }

        windowScroll(e) {
          this.scrollPos =
            (window.pageYOffset || document.scrollTop) -
              (document.clientTop || 0) || 0;
        }

        mouseMove(e) {
          this.mouse.x = e.clientX / window.innerWidth - 0.5;
          this.mouse.y = e.clientY / window.innerHeight - 0.5;
        }

        setEvents() {
          window.addEventListener("resize", this.windowResize);
          window.addEventListener("scroll", this.windowScroll);
          window.addEventListener("mousemove", this.mouseMove);

          const titles = Array.from(document.querySelectorAll("h2"));
          titles.forEach((title) => {
            title.addEventListener("mouseover", () => {
              this.fadeToAction(this.action2);
              this.isHovering = true;
            });
            title.addEventListener("mouseleave", () => {
              this.fadeToAction(this.action1);
              this.isHovering = false;
            });
          });
        }

        fadeToAction(newAction, duration = 0.2) {
          const previousAction = this.activeAction;
          this.activeAction = newAction;

          if (previousAction !== this.activeAction) {
            previousAction.fadeOut(duration);
          }

          this.activeAction
            .reset()
            .setEffectiveTimeScale(1)
            .setEffectiveWeight(1)
            .fadeIn(duration)
            .play();
        }

        loadFox() {
          const gltfLoader = new GLTFLoader();
          gltfLoader.load(
            "https://webflow-and-code.s3.amazonaws.com/glTF/Fox.gltf",
            (gltf) => {
              console.log("success");
              console.log(gltf);
              gltf.scene.scale.set(0.03, 0.03, 0.03);
              gltf.scene.position.y = 0.5;
              this.group.add(gltf.scene);

              this.mixer = new THREE.AnimationMixer(gltf.scene);
              this.action1 = this.mixer.clipAction(gltf.animations[0]);
              this.action2 = this.mixer.clipAction(gltf.animations[1]);

              this.activeAction = this.action1;
              this.activeAction.play();
            }
          );
        }

        animate() {
          this.camera.position.y = -this.scrollPos * 0.005;

          gsap.to(this.group.rotation, {
            x: this.mouse.y * 0.5,
            y: this.mouse.x * 0.5
          });

          if (this.mixer) {
            this.mixer.update(this.clock.getDelta());
          }

          this.box.material.color = this.isHovering
            ? new THREE.Color(0.0, 1.0, 0.0)
            : new THREE.Color(1.0, 0.0, 0.0);

          this.renderer.render(this.scene, this.camera);

          window.requestAnimationFrame(this.animate);
        }
      }

      const experience = new Experience();
    </script>
    <!-- WEBFLOW EMBED END -->
  </body>
</html>

</body>

</html>```

Make sure you add the .js to the import statement…

  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";

I checked your importmap urls and those look correct…

If you’re still getting errors, then yeah it might be some webserver configuration problem?

Thank you manthrax, I’ve added the .js, as you mentioned. |
Yes, this code works fine on my local VSCode. However, when I input the code on the web platform, I’m still encountering errors(Uncaught SyntaxError: Unexpected token ‘:’ ). Just as you suggested, it might be an issue with the webserver. I’ve reached out to the platform for assistance, but I haven’t received a response yet… Thanks for your comment.

1 Like