1

With Nextjs 14 i'm trying to create a component that can switch the running script depending on a prop that is passed:

TLDR. I'm not trying to import a component or a node_module, this is an external script that I'm trying to include with my next.js app....

'use client'

import { RefObject, useEffect, useRef, useState } from 'react';

interface JSCanvasProps {
    scriptSrc: string
    className?: string
    ref?: RefObject<HTMLDivElement>
}

interface CanvasScriptModule {
    initialize: (canvasId: string, canvasScriptId: string) => void;
    stop: () => void;
}

export default function JSCanvas(props: JSCanvasProps) {
    const canvasContainerRef = useRef<HTMLDivElement>(null);
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const [currentModule, setCurrentModule] = useState<CanvasScriptModule | null>(null);

    const resizeCanvas = () => {
        if (!canvasRef.current || !canvasContainerRef.current) return;

        const container = canvasContainerRef.current;
        const canvas = canvasRef.current;

        canvas.width = container.clientWidth;
        canvas.height = container.clientHeight;
    }

    useEffect(() => {
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas();

        return () => {
            window.removeEventListener('resize', resizeCanvas);
        }
    }, []);


    // dynamic script import
    useEffect(() => {
        import(props.scriptSrc)
            .then((module: CanvasScriptModule) => {
                module.initialize("canvasContainer", "canvasScript");
                setCurrentModule(module);
            })
            .catch(err => {
                console.error("Failed to load the script", err);
            });

        return () => {
            if (!currentModule) return;

            currentModule.stop();
        }

    }, [props.scriptSrc, currentModule]);

    return (
        <div ref={canvasContainerRef} id="canvasContainer" className={props.className}>
            <canvas ref={canvasRef} id="jsCanvas" />
        </div>
    )
}

Specifically this line fails no matter where where I put my script:

import(props.scriptSrc)

Here's a sample error: Cannot find module './hue_effect.js'

Here is my script file:

// module level variables
let canvas: any, ctx: any, container: any, intervalId: any;


const FRAMES_PER_SEC = 60;
const NUM_DOTS = 150;
const BORDER = 20;
const CONNECT_DISTANCE = 120;

const particles: Particle[] = [];
var hue = 0;

var mouse = {
    x: null,
    y: null,
    effectRadius: 200,
};

export function initialize(canvasId, containerId) {
    canvas = document.getElementById(canvasId);
    container = document.getElementById(containerId)
    ctx = canvas.getContext("2d");

    canvas.width = container.clientWidth;
    canvas.height = container.clientHeight;

    window.addEventListener("resize", resizeCanvas);
    window.addEventListener("mousemove", handleMouseMove);

    intervalId = setInterval(animate, 1000 / FRAMES_PER_SEC);
}

export function stop() {
    clearInterval(intervalId);

    window.removeEventListener("resize", resizeCanvas)
    window.removeEventListener("mousemove", handleMouseMove);
}

class Particle {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.dx = Math.random() * 2 + 2 * (Math.random() < 0.5 ? -1 : 1);
        this.dy = Math.random() * 2 + 2 * (Math.random() < 0.5 ? -1 : 1);
        this.radius = Math.random() * (30 - 10) + 5;
        this.color = hue;
    }

    draw() {
        ctx.fillStyle = "hsl(" + this.color + ", 100%, 50%";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
        ctx.fill();
    }

    update() {
        //updates position
        this.x += this.dx;
        this.y += this.dy;

        //decrease the size
        if (this.radius > 1) this.radius -= 0.3;
    }
}

function animate() {
    //clear previous frame
    //ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "rgba(0, 0, 0, 0.02)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    //update&draw all particle positions
    for (var i = 0; i < particles.length; i++) {
        particle = particles[i];
        if (particle.radius < 2) {
            particles.splice(i, 1);
        } else {
            particle.update();
            particle.draw();
        }
    }

    //draw the mouse as a red dot
    drawMouse();

    //change the hue a bit
    hue += 1;
}

function drawMouse() {
    ctx.beginPath();
    ctx.arc(mouse.x, mouse.y, 5, 0, Math.PI * 2, false);
    ctx.fillStyle = "red";
    ctx.fill();
}



function resizeCanvas() {
    var container = document.getElementById("canvasContainer")

    // Update the canvas size to match the window size
    canvas.width = container.clientWidth;
    canvas.height = container.clientHeight;
}

function handleMouseMove(event) {
    mouse.x = event.clientX;
    mouse.y = event.clientY;
    for (var i = 0; i < 2; i++) {
        particles.push(new Particle(mouse.x, mouse.y));
    }
}

I've tried to import using the following:

import("/scripts/hue_effect.js")
---------------------------------
import("../../public/scripts/hue_effect.js")
---------------------------------
import("/public/scripts/hue_effect.js")
---------------------------------

I've tried putting the script in the following locations to no avail:

  • "/public/scripts/hue_effect.js"
  • in a folder with the index.js of the component and importing using path: "./hue_effect.js"

The script is formatted as a module with exports so I don't see what could be going wrong? Would appreciate it if anyone can help me... Thanks!

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.