Search code examples
workerimport-maps

How do I use workers with node_modules?


I have in my project folder:

index.html
src
resources
node_modules

index.html:

<!DOCTYPE html>
<html>
    <head>
        <title>WebGPU App</title>
        <meta charset="UTF-8" />
        <link rel="shortcut icon" href="#"> 
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" typ="text/css" href="resources/css/style.css">       

        <script type="importmap"> { 
            "imports": { 
                "three": "/node_modules/three/build/three.module.js",
                "three/addons/": "/node_modules/three/examples/jsm/",
                "three/nodes": "/node_modules/three/examples/jsm/nodes/Nodes.js" 
            } 
        }     
        </script> 
    </head>
    <body>

        <div id="container"></div>
        <script type="module" src="./src/index.js"></script>
    
    </body>
</html>

I have all my scripts in the src folder. I use one of the scripts as an import library

src/three-defs.js

import * as THREE from 'three';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { CopyShader } from 'three/addons/shaders/CopyShader.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';

import WebGPU from 'three/addons/capabilities/WebGPU.js';           
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';

import { ShaderNode, MeshBasicNodeMaterial, texture, vec2, vec3, vec4, uv, color, wgslFn, tslFn, attribute, uniform, storage, positionWorld, normalLocal, normalWorld } from 'three/nodes';


export {THREE, WebGPU, WebGPURenderer, OrbitControls, RenderPass, ShaderPass, EffectComposer, CopyShader, ShaderNode, MeshBasicNodeMaterial, texture, color, vec2, vec3, vec4, wgslFn, tslFn, uv, attribute, uniform, storage, positionWorld, normalLocal, normalWorld};

If I import "three.module.js" without importmap it works. Can it be that workers cannot see the importmap in index.html and therefore cannot import THREE? I don't have any error messages, but you rarely get them if workers don't work because workers run independently of the main code.

if I do it like this in the worker it works:

//import {THREE} from 'three-defs.js';
import * as THREE from "../node_modules/three/build/three.module.js';

Does anyone have experience in dealing with import maps and workers?


Solution

  • Install Node.js if needed from https://nodejs.org. This will allow us to use npm and run JavaScript outside the browser.

    1. Open a terminal/command prompt. This is where we will run all the commands.
    2. Initialize the Vite project:
    npm create vite@latest my-threejs-project -- --template vanilla
    

    This scaffolds a new project using Vite, a build tool that makes development easier. We pass the --template vanilla flag to indicate we want a basic JavaScript project setup. 3. Install dependencies when prompted. This will install Vite and other packages needed for the project template. 4. Navigate into the project folder:

    cd my-threejs-project
    

    This puts us inside the project directory we just created. 5. Install Three.js:

    npm install three
    

    This installs the three.js library we will use for 3D graphics. 6. Open src/main.js and import Three.js. This imports the library into our JavaScript code.

    Create scene, camera, renderer, and cube objects using Three.js constructors. This sets up a basic 3D scene.

    import * as THREE from 'three';
    
    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);
    
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    
    camera.position.z = 5;
    
    function animate() {
      requestAnimationFrame(animate);
    
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
    
      renderer.render(scene, camera);
    }
    
    animate();
    

    Animate the cube by rotating it each frame. Render the scene with the renderer and camera. This will draw the 3D graphics.

    1. Run the dev server:
    npm run dev
    

    This starts the Vite development server so we can view the rendered scene in the browser.

    Now when you go to http://localhost:5173, you should see the rotating cube!