BlackBoxVision / react-qr-reader

React component for QR Scanning on web using Zxing library
MIT License
56 stars 11 forks source link

Throws error in Next.js v11 production app #38

Open atuttle opened 2 years ago

atuttle commented 2 years ago

When I run in development mode, everything works great. Once I switch to a production build, I start to get errors in an infinite loop the moment I render the QR Reader.

This is the line that's throwing:

https://github.com/zxing-js/library/blob/c6b4a70996e65f0c1ba315d3052726bb385b811c/src/core/qrcode/detector/FinderPatternFinder.ts#L597

Here's my app running in DEV mode, able to load the camera and scan QR codes:

working-dev

And here's the same app running on the same server after simply running a next build and starting the app in production mode:

prod-errors

Note that in the second screen shot, the app is on a different tab. I switched to the scanning tab to make the errors happen and then back to another tab quickly to make them stop so that I could get the screen shot.

JonatanSalas commented 2 years ago

Hi @atuttle can you share a repro example, so I can check it out?

atuttle commented 2 years ago

I saw that on Twitter you asked if I'm wrapping with Next's Dynamic util. I am not, but I am using React Suspense. Here's the current code:

<Suspense fallback={<div>Loading...</div>}>
    <ScanStatus {...scanStatus} />
    <ErrorBoundary fallbackUI={<h4>Unable to load scanner. Your device may be incompatible.</h4>}>
        <QrReader
            onError={handleInitializeError}
            onResult={handleScan}
            style={{ width: `100%` }}
            constraints={{ facingMode: 'environment' }}
        />
    </ErrorBoundary>
</Suspense>

This is the entire body of the component that includes the QR scanner (handler functions/etc excluded).

If you still need it, I can create a small repro repo.

atuttle commented 2 years ago

Ah, my mistake, I am using dynamic from Next:

const QrReader = dynamic(() => import('@blackbox-vision/react-qr-reader').then((mod) => mod.QrReader), {
    ssr: false
});
JonatanSalas commented 2 years ago

Can you test the following?

  1. Move the QR reader to a custom component:
import { QrReader } from '@blackbox-vision/react-qr-reader';

const MyQrReader = ({ onError, onResult }) => 
  <QrReader
     onError={onError}
     onResult={onResult}
     style={{ width: `100%` }}
     constraints={{ facingMode: 'environment' }}
  />

 export default MyQrReader;
  1. Then import the custom component using dynamic from next.js disabling server side rendering:
import dynamic from 'next/dynamic';

const QrReader = dynamic(() => import('../components/MyQrReader'), { 
   ssr: false 
})
  1. Use the custom component as usual.

I assume that there's some kind of issue regarding server side rendering.

JonatanSalas commented 2 years ago

Ah, my mistake, I am using dynamic from Next:

const QrReader = dynamic(() => import('@blackbox-vision/react-qr-reader').then((mod) => mod.QrReader), {
  ssr: false
});

Great, so there's something out with the lib then, I will create a repro case so I can test and see if I can ship a fix for it!

atuttle commented 2 years ago

Is it possible that the NextJS production build is compressing the error.name property?

My handleScan function looks like this:

const handleScan = async (data, err) => {
    if (err) {
        if (err.name && err.name.indexOf('NotFoundException') > -1) {
            return;
        }
        if (err.name && err.name.indexOf('ChecksumException') > -1) {
            return;
        }
        return handleScanError(err);
    }
    if (data === null) {
        return;
    }

    //scan is legit, handle it...
};

The errors I'm seeing roll in continuously in production VERY much resemble the errors I see when the QrReader component is visible but there is no QR code for it to scan. The guard statements at the top of my handler show how I'm ignoring them. BUT if the err.name property might be different in production, that would explain all of this...

charleskoehl commented 2 years ago

The same errors are thrown in a loop in my unejected CRA while running on webpack dev server. I'm handling them similarly, which works fine on dev, but when I make a production build and use "serve" on my Mac the error name is "e" and the message is undefined.

error: e
column: 1017048
line: 2
message: undefined
name: "e"
sourceURL: "https://..."
stack: "e@https://…"
pawelkrystkiewicz commented 2 years ago

The same errors are thrown in a loop in my unejected CRA while running on webpack dev server. I'm handling them similarly, which works fine on dev, but when I make a production build and use "serve" on my Mac the error name is "e" and the message is undefined.

error: e
column: 1017048
line: 2
message: undefined
name: "e"
sourceURL: "https://..."
stack: "e@https://…"

I'm having the same issue as described on CRA. Would really love to use this lib but I need to know how to properly handle this rolling error

atuttle commented 2 years ago

@charleskoehl @pawelkrystkiewicz I've basically taken the approach of ignoring all errors reported in my handleScan function. Unfortunate, because this seems like a bad thing to do (/cc @JonatanSalas ) but so far it's been fine.

pawelkrystkiewicz commented 2 years ago

@atuttle I've done the same