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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.