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!