alexcorvi/heic2any

"ReferenceError: Blob is not defined" error when using with NextJS

Closed this issue ยท 10 comments

Getting "ReferenceError: Blob is not defined" error when doing a build in NextJS. Works fine in development and my .heic image is converted on the client side like I want but when doing a build to deploy it to production I get this error.

Here is where I use it in my code:

  const onDrop = useCallback(async (files) => {
    setFiles(
      await Promise.all(
        files.map(async (file) => {
          let result;
          if (file.type === "image/heic") {
            setConvertingImage(true);
            result = await heic2any({
              blob: file,
              toType: "image/jpeg",
            });
            setConvertingImage(false);
          } else {
            result = file;
          }

          return Object.assign(file, {
            preview: URL.createObjectURL(result),
          });
        })
      )
    );
  }, []);

I'm thinking it may have to do with the fact that NextJS is Server Side Rendered and when heic2any is executed on the server something funny happens?

Got the exact same error, with the same conditions. Works great in development but then as soon as I try to make a build it returns the error.

@ezeikel @gdstewart
If you use require it works fine!

const [img, setImg] = useState(null);
  
  useEffect(() => {
    const heic2any = require('heic2any')
    if (typeof window !== 'undefined') {
      fetch('https://alexcorvi.github.io/heic2any/demo/14.heic')
        .then((res) => res.blob())
        .then((blob) => heic2any({
          blob,
        }))
        .then((conversionResult) => {
          setImg(URL.createObjectURL(conversionResult));
        })
        .catch((e) => {
          console.log(e);
        });
    }
  }, []);

I did figure this out but can't remember exactly how. Hopefully @devdigitalrepublic's solution works for you @gdstewart otherwise I'll try and dig around and remember what I did.

@ezeikel @devdigitalrepublic Using require was the solution! Thanks a lot guys

const heic2any = require('heic2any') not working for me

I fixed the error thank you

How did you fix? @honeykikiki

@blakejoy import the library inside the function.

maybe it's too late and I guess most of you got the problem solved, but still would like to mention that
to remove this error
we need to write import inside the function or the place where we are using
example,
const onChange =(e)=>{
const heic2any = require('heic2any') \ like
\ ...rest code

heic2any({
  blob: heic,
  toType: "image/jpeg",
  quality: 0.1,
  }).then((blob) => {
  let heicFile = new File([blob], ${heic.name.split('.')[0]}.jpg, {
  type: "image/jpeg",
  });
  console.log(heicFile);
  });

}
Ehtz commented

This works for me in Nextjs - took me a long time to figure out:

  const onFileUploaderChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files) {
      const filesArray: File[] = Array.from(e.target.files);
      const newFilesArray: File[] = [];
  
      // Array to hold the promises for HEIC conversions
      const conversionPromises: Promise<void>[] = [];
  
      for (let file of filesArray) {
        console.log(`Processing file: ${file.name}, type: ${file.type}`);
  
        // Check both MIME type and file extension
        const isHEIC =
          file.type === 'image/heic' ||
          file.type === 'image/heif' ||
          file.name.toLowerCase().endsWith('.heic') ||
          file.name.toLowerCase().endsWith('.heif');
  
        if (isHEIC) {
          if (typeof window !== 'undefined') {
            // Create a promise for each HEIC conversion and add it to the array
            const conversionPromise = (async () => {
              try {
                const heic2any = (await import('heic2any')).default;
                const result = await heic2any({
                  blob: file,
                  toType: 'image/jpeg',
                  quality: 1,
                });
                const blobsToProcess = Array.isArray(result) ? result : [result];
                blobsToProcess.forEach((blob, index) => {
                  const convertedFile = new File(
                    [blob],
                    `converted-image-${index}.jpeg`,
                    {
                      type: 'image/jpeg',
                      lastModified: new Date().getTime(),
                    }
                  );
                  newFilesArray.push(convertedFile);
                  console.log(`Converted file: ${convertedFile.name}`);
                });
              } catch (error) {
                console.error('Error converting HEIC to JPEG', error);
              }
            })();
  
            conversionPromises.push(conversionPromise);
          }
        } else {
          newFilesArray.push(file);
          console.log(`Added non-HEIC file: ${file.name}`);
        }
      }
  
      // Wait for all HEIC conversions to complete
      await Promise.all(conversionPromises);
  
      if (newFilesArray.length + pictures.length <= 25) {
        setPictures([...pictures, ...newFilesArray]);
        setErrorMessagePic('');
        console.log('Pictures set successfully');
      } else {
        setErrorMessagePic('Please choose a maximum of 25 images');
        console.log('Exceeded maximum number of images');
      }
    }
  };