How to Build a Barcode and QR Code Scanner in Nuxt.js

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

In this article, we are going to build a barcode and QR code scanner using Nuxt.js. Dynamsoft Camera Enhancer is used to access the camera in browsers and Dynamsoft Barcode Reader is used to read barcodes from the camera video frames.

New Project

Create a new Nuxt.js project named barcode-scanner:

npx nuxi@latest init barcode-scanner

Install Dependencies

Install the Dynamsoft Barcode Reader bundle.

npm install dynamsoft-barcode-reader-bundle

Configure the SDK

Create a file named dynamsoft.config.ts with the following content to initialize the license and resources. You can apply for a license here.

import { CoreModule } from "dynamsoft-core";
import { LicenseManager } from "dynamsoft-license";
import "dynamsoft-barcode-reader";

let initialized = false;
export async function init(){
  if (initialized) {
    return;
  }
  // Configures the paths where the .wasm files and other necessary resources for modules are located.
  CoreModule.engineResourcePaths.rootDirectory = "https://cdn.jsdelivr.net/npm/";

  /** LICENSE ALERT - README
   * To use the library, you need to first specify a license key using the API "initLicense()" as shown below.
   */

  await LicenseManager.initLicense("LICENSE-KEY", {
    executeNow: true,
  });

  /**
   * You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=samples&product=dbr&package=js to get your own trial license good for 30 days.
   * Note that if you downloaded this sample from Dynamsoft while logged in, the above license key may already be your own 30-day trial license.
   * For more information, see https://www.dynamsoft.com/barcode-reader/docs/web/programming/javascript/user-guide/index.html?ver=10.4.2002&cVer=true#specify-the-license&utm_source=samples or contact support@dynamsoft.com.
   * LICENSE ALERT - THE END
   */

  // Optional. Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading.
  await CoreModule.loadWasm(["DBR"]);
  initialized = true;
  return;
}

Create a Barcode Scanner Vue Component

Next, let’s create a barcode scanner component under src/components/BarcodeScanner.vue that can open the camera and scan barcodes from the camera video frames.

  1. Write the basic content of the component:

    <script setup lang="ts">
    const cameraViewContainer: Ref<HTMLElement | null> = ref(null);
    </script>
    
    <template>
      <div ref="cameraViewContainer" id="cameraViewContainer"></div>
    </template>
    
    <style scoped>
    #cameraViewContainer {
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      position: absolute;
    }
    </style>
    

    It has an element which serves as the container of the camera.

  2. Run the init method defined in dynamsoft.config.ts after the component is mounted.

    onMounted(async () => {
      await init();
    });
    
  3. Initialize Camera Enhancer and bind it to the UI element after the component is mounted.

    const cameraViewContainer: Ref<HTMLElement | null> = ref(null);
    let cameraEnhancer: CameraEnhancer;
    let cameraView:CameraView;
    onMounted(async () => {
      try {
        await init();
        // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control.
        cameraView = await CameraView.createInstance();
        cameraEnhancer = await CameraEnhancer.createInstance(cameraView);
    
        // Get default UI and append it to DOM.
        cameraViewContainer.value!.append(cameraView.getUIElement());
      } catch (ex: any) {
        let errMsg = ex.message || ex;
        console.error(errMsg);
      }
    });
    
  4. Create a Capture Vision Router instance to process the camera frames to read barcodes.

    let cvRouter: CaptureVisionRouter;
    onMounted(async () => {
      try {
        //...
        cvRouter = await CaptureVisionRouter.createInstance();
        cvRouter.setInput(cameraEnhancer);
      } catch (ex: any) {
        let errMsg = ex.message || ex;
        console.error(errMsg);
      }
    });
    
  5. Define two emit events. One is to emit the detected barcode results and the other is to emit the initialized event.

    // define a 'scanned' event that the Scanner component emits when frames are scanned
    const emit = defineEmits<{
      (e: 'scanned', results: BarcodeResultItem[]): void
      (e: 'initialized'): void
    }>();
    
    1. Add a result receiver to get the detected barcode results and emit them.

      // Define a callback for results.
      cvRouter.addResultReceiver({
        onDecodedBarcodesReceived: (result) => {
          emit("scanned",result.barcodeResultItems);
        }
      });
      
    2. Emit initialized after the instances are created.

      onMounted(async () => {
        try {
          //...
          emit("initialized");
        } catch (ex: any) {
          let errMsg = ex.message || ex;
          console.error(errMsg);
        }
      });
      
  6. Expose two methods to control the scanning status of the component.

    // expose start/stop to control pause/resume scanning
    const start = async () => await startScanning();
    const stop = () => stopScanning();
    
    defineExpose({ start, stop });
       
    const stopScanning = () => {
      cameraView?.setScanLaserVisible(false);
      cvRouter?.stopCapturing();
      cameraEnhancer.close();
    }
    
    const startScanning = async () => {
      await cameraEnhancer.open();
      cvRouter?.startCapturing("ReadSingleBarcode");
      cameraView?.setScanLaserVisible(true);
    }
    
  7. Release resources before the component is unmounted.

    // dispose cvRouter when it's no longer needed
    onBeforeUnmount(async () => {
      try {
        cvRouter?.dispose();
        cameraEnhancer?.dispose();
      } catch (_) { }
    });
    

Use the Barcode Scanner Component in the App

Switch to app.vue. Let’s use the scanner component in the app.

  1. Import the scanner component and add a button to control its scanning status. Since the SDK has to modify the DOM, we need to wrap the scanner with ClientOnly.

    <template>
      <div id="app">
        <h2>Barcode Scanner in Nuxt.js</h2>
        <button v-if="initialized" @click="toggleScanning"></button>
        <span v-if="!initialized">Initializing...</span>
        <div class="container" v-if="mounted">
          <ClientOnly fallback-tag="span" fallback="Loading barcode scanner...">
            <BarcodeScanner ref="scanner" @initialized="onInitialized" @scanned="onScanned"></BarcodeScanner>
          </ClientOnly>
        </div>
    </template>
    <script setup lang="ts">
    import type { BarcodeResultItem } from 'dynamsoft-barcode-reader-bundle';
    import BarcodeScanner from './components/BarcodeScanner.vue';
    const scanner = ref();
    const initialized = ref(false);
    const scanning = ref(false);
    const onInitialized = () => {
      initialized.value = true;
    }
    const toggleScanning = () => {
      if (scanner.value) {
        scanning.value = !scanning.value;
        if (scanning.value) {
          scanner.value.start();
        }else{
          scanner.value.stop();
        }
      }else{
        alert("Not mounted");
      }
    }
    </script>
    <style lang="css" scoped>
    .container {
      position: relative;
      width: 360px;
      height: 360px;
    }
    </style>
    
  2. Display the scanned results.

    <template>
      <div>
        <div>
          Results:
        </div>
        <ol>
          <li v-for="(barcode,index) in scannedBarcodes" :key="'barcode-'+index"></li>
        </ol>
      </div>
    </template>
    <script setup lang="ts">
    const scannedBarcodes = ref<BarcodeResultItem[]>([]);
    const onScanned = (barcodes:BarcodeResultItem[]) => {
      if (barcodes.length>0) {
        scannedBarcodes.value = barcodes;
      }
    }
    </script>
    

All right, we’ve now finished the barcode and QR code scanner with Nuxt.js. You can check out the online demo to have a try.

Source Code

https://github.com/tony-xlh/NuxtJS-Barcode-Scanner