Skip to content

Nextjs build fails but runs locally with image resize extension #15

@Rchn1907

Description

@Rchn1907

Describe the bug
Hey guys,
i am encountering a different problem.
My next js app is running locally fine.
But when I reload the page where I use Tiptap this error occurs:
Bildschirmfoto 2024-10-04 um 15 52 35
The same Error occurs when I build my next App locally and in my CI/CD.
I searched a lot of solution on the internet but could not find any possible one.
I would be happy if some of you guys could help me.
Here is my Code:

import React, { useEffect, useRef, useState } from 'react';
import { EditorContent, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Bold from '@tiptap/extension-bold';
import Italic from '@tiptap/extension-italic';
import Underline from '@tiptap/extension-underline';
import Strike from '@tiptap/extension-strike';
import Link from '@tiptap/extension-link';
import Image from '@tiptap/extension-image';
import TextAlign from '@tiptap/extension-text-align';
import Heading from '@tiptap/extension-heading';
import BulletList from '@tiptap/extension-bullet-list';
import OrderedList from '@tiptap/extension-ordered-list';
import ListItem from '@tiptap/extension-list-item';
import Blockquote from '@tiptap/extension-blockquote';
import CodeBlock from '@tiptap/extension-code-block';
import Color from '@tiptap/extension-color';
import Highlight from '@tiptap/extension-highlight';
import TextStyle from '@tiptap/extension-text-style';
import HorizontalRule from '@tiptap/extension-horizontal-rule';
import TaskList from '@tiptap/extension-task-list';
import TaskItem from '@tiptap/extension-task-item';
import { Button, Box, TextField, ButtonGroup, Divider } from '@mui/material';
import authConfig from 'src/configs/auth';

import { 
  FormatBold, 
  FormatHeader1, 
  FormatHeader2, 
  FormatItalic, 
  FormatListBulleted, 
  FormatListNumbered, 
  FormatQuoteOpen, 
  FormatStrikethrough, 
  FormatUnderline, 
  CodeBraces, 
  FormatAlignLeft, 
  FormatAlignCenter, 
  FormatAlignRight, 
  ImageArea,
  FormatColorText,
  FormatColorHighlight,
  Minus,
  LinkVariant,
  LinkVariantOff,
  FormatHeader3,
  TableLargePlus,
  TableLargeRemove,
  TableRowPlusAfter,
  TableColumnPlusAfter,
  FormatHeader4
} from 'mdi-material-ui';
import toast from 'react-hot-toast';
import axios from 'axios';
import ImageResize from 'tiptap-extension-resize-image';
import Table from '@tiptap/extension-table';
import TableRow from '@tiptap/extension-table-row';
import TableCell from '@tiptap/extension-table-cell';
import TableHeader from '@tiptap/extension-table-header';

export default function TiptapEditor(props) {
  const {language, value, setValue, readOnly} = props;
  const fileInputRef = useRef(null); // Reference to the file input
  const textColorRef = useRef(null);
  const highlightColorRef = useRef(null);


  const editor = useEditor({
    extensions: [
      StarterKit,
      Bold,
      Italic,
      Underline,
      Strike,
      Link,
      Image,
      ImageResize,
      TextAlign.configure({ types: ['heading', 'paragraph'] }),
      Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),
      BulletList,
      OrderedList,
      ListItem,
      Blockquote,
      CodeBlock,
      Color,
      Highlight.configure({ multicolor: true }),
      TextStyle,
      HorizontalRule,
      TaskList,
      TaskItem.configure({ nested: true }),
      Table.configure({resizable: true}),
      TableRow,
      TableCell,
      TableHeader
    ],
    content: value,
    autofocus: true,
    editable: !readOnly,
    onUpdate: ({ editor }) => {
      setValue(editor.getHTML()); // Updates the state with the HTML content
    },
  });

  const handleTextColorChange = (e) => {
    editor.chain().focus().setColor(e.target.value).run();
    textColorRef.current.style.display = 'none'; // Hide the color input
  };
  
  const handleHighlightColorChange = (e) => {
    editor.chain().focus().toggleHighlight({ color:  `${e.target.value}` }).run();
    highlightColorRef.current.style.display = 'none'; // Hide the highlight input
  };  

  const handleSetLink = () => {
    const url = window.prompt('Enter the link URL:');
    if (url) {
      editor.chain().focus().setLink({ href: url }).run();
    }
  };

  // Function to handle image upload
  const handleImageUpload = async (event) => {
    const file = event.target.files[0];
    if (file) {
      // Assuming you have an API endpoint to upload the image
      const formData = new FormData();
      formData.append('file', file);

      try {
        const url = `Media?languageId=${language}`;
        const res = await axios.post(authConfig.defaultEndpoint + url, formData);
        let urlEncoded = encodeURIComponent(res.data.Data.Description);
        editor.chain().focus().setImage({src: `${authConfig.defaultEndpoint}Media/${urlEncoded}`}).run();
      } catch (error) {
        toast.error("Error uploading image");
        console.error('Error uploading image:', error.response || error.message);
      }
    }
  };

  if (!editor) {
    return null;
  }

  // Toolbar for editor controls with active state check
  const Toolbar = () => (
    <Box sx={{ display: 'flex', gap: '8px', mb: 2, mt: 2, flexWrap: 'wrap'}}>
      <ButtonGroup size='small' disabled={readOnly}>
        <Button 
          onClick={() => editor.chain().focus().toggleBold().run()} 
          variant={editor.isActive('bold') ? 'contained' : 'outlined'}
        >
          <FormatBold />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleItalic().run()} 
          variant={editor.isActive('italic') ? 'contained' : 'outlined'}
        >
          <FormatItalic />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleUnderline().run()} 
          variant={editor.isActive('underline') ? 'contained' : 'outlined'}
        >
          <FormatUnderline />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleStrike().run()} 
          variant={editor.isActive('strike') ? 'contained' : 'outlined'}
        >
          <FormatStrikethrough />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleBulletList().run()} 
          variant={editor.isActive('bulletList') ? 'contained' : 'outlined'}
        >
          <FormatListBulleted />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleOrderedList().run()} 
          variant={editor.isActive('orderedList') ? 'contained' : 'outlined'}
        >
          <FormatListNumbered />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()} 
          variant={editor.isActive('heading', { level: 1 }) ? 'contained' : 'outlined'}
        >
          <FormatHeader1 />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} 
          variant={editor.isActive('heading', { level: 2 }) ? 'contained' : 'outlined'}
        >
          <FormatHeader2 />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} 
          variant={editor.isActive('heading', { level: 3 }) ? 'contained' : 'outlined'}
        >
          <FormatHeader3 />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()} 
          variant={editor.isActive('heading', { level: 4 }) ? 'contained' : 'outlined'}
        >
          <FormatHeader4 />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleBlockquote().run()} 
          variant={editor.isActive('blockquote') ? 'contained' : 'outlined'}
        >
          <FormatQuoteOpen />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().toggleCodeBlock().run()} 
          variant={editor.isActive('codeBlock') ? 'contained' : 'outlined'}
        >
          <CodeBraces />
        </Button>
        <Button onClick={() => editor.chain().focus().setHorizontalRule().run()} variant="outlined">
          <Minus />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().setTextAlign('left').run()} 
          variant={editor.isActive({ textAlign: 'left' }) ? 'contained' : 'outlined'}
        >
          <FormatAlignLeft />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().setTextAlign('center').run()} 
          variant={editor.isActive({ textAlign: 'center' }) ? 'contained' : 'outlined'}
        >
          <FormatAlignCenter />
        </Button>
        <Button 
          onClick={() => editor.chain().focus().setTextAlign('right').run()} 
          variant={editor.isActive({ textAlign: 'right' }) ? 'contained' : 'outlined'}
        >
          <FormatAlignRight />
        </Button>
        {/* Color picker for text color */}
        <Button onClick={() => textColorRef.current.style.display = 'block'}>
          <FormatColorText />
        </Button>
        <input
          ref={textColorRef}
          type="color"
          style={{ display: 'none' }}  // Initially hidden
          onChange={handleTextColorChange}
        />

        <Button onClick={() => highlightColorRef.current.style.display = 'block'}>
          <FormatColorHighlight />
        </Button>
        <input
          ref={highlightColorRef}
          type="color"
          style={{ display: 'none' }}  // Initially hidden
          onChange={handleHighlightColorChange}
        />
        <Button onClick={handleSetLink} variant="outlined">
          <LinkVariant/>
        </Button>
        <Button onClick={() => editor.chain().focus().unsetLink().run()} variant="outlined">
          <LinkVariantOff/>
        </Button>
        <Button onClick={() => fileInputRef.current.click()} variant="outlined">
          <ImageArea />
        </Button>
        <input
          type="file"
          accept="image/*"
          style={{ display: 'none' }} // Hidden file input
          ref={fileInputRef}
          onChange={handleImageUpload}
        />
        <Button onClick={() => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()} variant="outlined">
          <TableLargePlus/>
        </Button>
        <Button onClick={() => editor.chain().focus().addRowAfter().run()} variant="outlined">
          <TableRowPlusAfter/>
        </Button>
        <Button onClick={() => editor.chain().focus().addColumnAfter().run()} variant="outlined">
          <TableColumnPlusAfter/>
        </Button>
        <Button onClick={() => editor.chain().focus().deleteTable().run()} variant="outlined">
          <TableLargeRemove/>
        </Button>
      </ButtonGroup>
    </Box>
  );

  return (
    <Box sx={{position: "relative", width: "100%", border: "3px solid #444", padding: 2}}>
      <Toolbar/> {/* Render toolbar */}
      <Divider/>
      <EditorContent editor={editor}/>
    </Box>
  );
}

Desktop (please complete the following information):

  • OS: MacOS
  • Browser safari

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions