Rails+React+QuaggaJSを使ってバーコードスキャンしてみた

# はじめに
チーム開発したい方たちと集まりRuby on RailsとReactを使ってアプリ作成しており、
バーコード読み取り機能の実装を担当することとなったためざっくり動くところまで作ってみました。

# 環境
- Ruby:  2.6.5
- Ruby on Rails: 6.0.3

# セットアップ
```
rails _6.0.3_ new barcode_app -d postgresql

cd barcode_app 

yarn add quagga

rails webpacker:install
rails webpacker:install:react
rails generate react:install
```

```app/javascript/components/scanners/config.json
{
  "inputStream": {
    "type": "LiveStream",
    "constraints": {
      "width": { "min": 450 },
      "height": { "min": 300 },
      "facingMode": "environment",
      "aspectRatio": { "min": 1, "max": 2 }
    }
  },
  "locator": {
    "patchSize": "medium",
    "halfSample": true
  },
  "numOfWorkers": 2,
  "frequency": 10,
  "decoder": {
    "readers": ["ean_reader"]
  },
  "locate": true
}
```

```app/javascript/components/scanners/Index.jsx
import React, { useState } from "react";
import Scanner from "./Scanner";


const Index = () => {
  const [camera, setCamera] = useState(true);
  const [result, setResult] = useState(null);

  const onDetected = result => {
    setResult(result);
    setCamera(!camera)
    window.location.href = '/scanners/' + result
  };

  return (
    <section className="section-wrapper">
      <div className="section-title">
        <h1 className="section-title-text">
          {camera ? <Scanner onDetected={onDetected} /> : <p>読み込み中...</p> }
        </h1>
      </div>
    </section>
  );
}

export default Index
```

```app/javascript/components/scanners/Scanner.jsx
import React, { useEffect } from "react";
import config from "./config.json";
import Quagga from "quagga";

const Scanner = props => {
  const { onDetected } = props;

  useEffect(() => {
    Quagga.init(config, err => {
      if (err) {
        console.log(err, "error msg");
      }
      Quagga.start();
      return () => {
        Quagga.stop()
      }
    });

    Quagga.onProcessed(result => {
      var drawingCtx = Quagga.canvas.ctx.overlay,
        drawingCanvas = Quagga.canvas.dom.overlay;

      if (result) {
        if (result.boxes) {
          drawingCtx.clearRect(
            0,
            0,
            Number(drawingCanvas.getAttribute("width")),
            Number(drawingCanvas.getAttribute("height"))
          );
          result.boxes
            .filter(function(box) {
              return box !== result.box;
            })
            .forEach(function(box) {
              Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, {
                color: "green",
                lineWidth: 2
              });
            });
        }

        if (result.box) {
          Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, {
            color: "#00F",
            lineWidth: 2
          });
        }

        if (result.codeResult && result.codeResult.code) {
          Quagga.ImageDebug.drawPath(
            result.line,
            { x: "x", y: "y" },
            drawingCtx,
            { color: "red", lineWidth: 3 }
          );
        }
      }
    });

    Quagga.onDetected(detected);
  }, []);

  const detected = result => {
    onDetected(result.codeResult.code);
  };

  return (
    <div id="interactive" className="viewport" />
  );
};

export default Scanner;
```

# はまったポイント
![スクリーンショット 2021-01-09 22.40.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230985/8f074af1-ef67-c6cf-ba28-65ba979a9f90.png)

### 参考にした記事
https://github.com/visgl/react-map-gl/issues/874


### 対応箇所


```config/webpack/environment.js
const { environment } = require('@rails/webpacker')

// 追記
environment.loaders.delete('nodeModules');

module.exports = environment
```

#完成
![ezgif.com-gif-maker (4) (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230985/67cbca78-42b3-3250-eb25-bd84a42d882a.gif)

GitHub
https://github.com/yodev21/scanner_app

# 参考記事
[WebRTCを使ってブラウザでバーコードのスキャンをしてみる](https://qiita.com/dnrsm/items/cb0ca65d3e6f674918ad)