DEV Community

Yeow Zi Qin
Yeow Zi Qin

Posted on

Step by step on how to setup fabric.js in the next.js app

🧐 What is fabric.js

Fabric.js is a powerful and simple
Javascript HTML5 canvas library. It provides an interactive object model on top of the canvas element.
Fabric also has SVG-to-canvas (and canvas-to-SVG) parser.

Fabric.js

What we build in this blog

End Product

The demo above is taken from this medium blog, in which there's some slight modification or fix need to be done.


Install fabric.js

npm

npm i fabric
npm i -D @types/fabric # typescript
Enter fullscreen mode Exit fullscreen mode

yarn

yarn add fabric
yarn add -D @types/fabric # typescript
Enter fullscreen mode Exit fullscreen mode

pnpm

pnpm add fabric
pnpm add -D @types/fabric # typescript
Enter fullscreen mode Exit fullscreen mode

Setup for next.config.js

Below is the code for next.config.js. The reason is to configure the webpack for canvas runtime error that will crash the application and utf-8-validate & bufferutil warning. View more at the relevant references.

/** @type {import('next').NextConfig} */
const nextConfig = {
  // reactStrictMode: false,
  webpack: (config) => {
    config.externals.push({
      "utf-8-validate": "commonjs utf-8-validate",
      bufferutil: "commonjs bufferutil",
      canvas: "commonjs canvas",
    });
    // config.infrastructureLogging = { debug: /PackFileCache/ };
    return config;
  },
};

module.exports = nextConfig;
Enter fullscreen mode Exit fullscreen mode

See also relevant references

  1. Appropriate webpack loader for canvas
  2. Common js - utf-8-validate & bufferutil

Boilerplate for Next.js with Fabric.js

Below is the next.js .tsx code. If you are using Next.js 13.4 and above and opt-in to the app router, add "use client" on top of the file to use the Next.js client component, or else ignore the line.

"use client"; // next.js app router

import React, { useState, useEffect } from "react";
import { fabric } from "fabric";

const App = () => {
  const [canvas, setCanvas] = useState<fabric.Canvas>();

  useEffect(() => {
    const c = new fabric.Canvas("canvas", {
      // ...
    });

    // settings for all canvas in the app
    // ...

    setCanvas(c);

    return () => {
      // ...
    };
  }, []);

  const addRect = (canvi?: fabric.Canvas) => {
    // ...
  };

  return (
    <div>
      <button onClick={() => addRect(canvas)}>Rectangle</button>
      <canvas id="canvas" />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Ensure that <canvas> tag has an ID the same as new fabric.Canvas(id, {...})

useEffect & addRect function

  useEffect(() => {
    const c = new fabric.Canvas("canvas", {
      height: 400,
      width: 800,
      backgroundColor: "black",
    });

    // settings for all canvas in the app
    fabric.Object.prototype.transparentCorners = false;
    fabric.Object.prototype.cornerColor = "#2BEBC8";
    fabric.Object.prototype.cornerStyle = "rect";
    fabric.Object.prototype.cornerStrokeColor = "#2BEBC8";
    fabric.Object.prototype.cornerSize = 6;

    setCanvas(c);

    return () => {
      c.dispose();
    };
  }, []);

  const addRect = (canvas?: fabric.Canvas) => {
    const rect = new fabric.Rect({
      height: 280,
      width: 200,
      stroke: "#2BEBC8",
    });
    canvas?.add(rect);
    canvas?.requestRenderAll();
  };
Enter fullscreen mode Exit fullscreen mode

Note

c.dispose() is required to clean up the instantiated canvas element. See why you should clean up so that your rectangle can move and resize properly -> StackOverflow Question.

If you refuse to add the return () => {c.dispose();}; statement, you can disable the reactStrictMode in next.config.js. See the concept of reactStrictMode in this StackOverflow Question.


❤️ Leave a like if you like this post
❤️ It will be a massive motivation for me

Top comments (3)

Collapse
 
mrv90 profile image
mrv90

thank you bro.. you saved me from a bad headache !!

Collapse
 
tharindaprabhath profile image
TharindaPrabhath

Thanks mate!

Collapse
 
dendrofen profile image
Mark K

May you provide demo, github?