From 3765b9482e93edc3638aa254e6dcffc3f4dfbe8b Mon Sep 17 00:00:00 2001 From: Niklas Gruhn Date: Mon, 2 Sep 2024 13:30:36 +0200 Subject: [PATCH] feat: BarcodeDetector polyfill only if no native support See: #447 --- .gitignore | 3 +++ src/misc/scanner.ts | 35 ++++++++++++++++++++++++++++++----- src/misc/shimGetUserMedia.ts | 4 ++-- src/misc/util.ts | 2 +- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 3ff7c80a..18084c6d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,9 @@ # Icon must end with two \r Icon +# VitePress +.vitepress/cache +.vitepress/dist # Thumbnails ._* diff --git a/src/misc/scanner.ts b/src/misc/scanner.ts index c2644b59..f14c6038 100644 --- a/src/misc/scanner.ts +++ b/src/misc/scanner.ts @@ -1,10 +1,35 @@ -import { type DetectedBarcode, type BarcodeFormat, BarcodeDetector } from 'barcode-detector/pure' +import { type DetectedBarcode, type BarcodeFormat, BarcodeDetector, type BarcodeDetectorOptions } from 'barcode-detector/pure' import { eventOn } from './callforth' import { DropImageFetchError } from './errors' +declare global { + interface Window { + BarcodeDetector?: typeof BarcodeDetector + } +} + +/** + * Wrapper function that creates `BarcodeDetector` instances. The native API is used + * if it's available. Otherwise the polyfill is used. + * + * Note, that we can't just monkey the API on load, i.e. + * + * globalThis.BarcodeDetector ??= BarcodeDetector + * + * because that is not SSR compatible. If the polyfill is applied during SSR, then + * it's actually missing at runtime. + */ +function createBarcodeDetector(options: BarcodeDetectorOptions): BarcodeDetector { + if (window.BarcodeDetector === undefined) { + return new BarcodeDetector(options) + } else { + return new window.BarcodeDetector(options) + } +} + let barcodeDetector: BarcodeDetector export const setScanningFormats = (formats: BarcodeFormat[]) => { - barcodeDetector = new BarcodeDetector({ formats }) + barcodeDetector = createBarcodeDetector({ formats }) } type ScanHandler = (_: DetectedBarcode[]) => void @@ -28,7 +53,7 @@ export const keepScanning = async ( } ) => { console.debug('[vue-qrcode-reader] start scanning') - barcodeDetector = new BarcodeDetector({ formats }) + barcodeDetector = createBarcodeDetector({ formats }) const processFrame = (state: { lastScanned: number; contentBefore: string[]; lastScanHadContent: boolean }) => @@ -140,7 +165,7 @@ export const processFile = async ( file: File, formats: BarcodeFormat[] = ['qr_code'] ): Promise => { - const barcodeDetector = new BarcodeDetector({ + const barcodeDetector = createBarcodeDetector({ formats }) @@ -151,7 +176,7 @@ export const processUrl = async ( url: string, formats: BarcodeFormat[] = ['qr_code'] ): Promise => { - const barcodeDetector = new BarcodeDetector({ + const barcodeDetector = createBarcodeDetector({ formats }) diff --git a/src/misc/shimGetUserMedia.ts b/src/misc/shimGetUserMedia.ts index 7b73c253..c65bae3e 100644 --- a/src/misc/shimGetUserMedia.ts +++ b/src/misc/shimGetUserMedia.ts @@ -8,9 +8,9 @@ import { shimGetUserMedia as safariShim } from 'webrtc-adapter/dist/safari/safar import { detectBrowser } from 'webrtc-adapter/dist/utils' import { StreamApiNotSupportedError } from './errors' -import { indempotent } from './util' +import { idempotent } from './util' -export default indempotent(() => { +export default idempotent(() => { const browserDetails = detectBrowser(window) switch (browserDetails.browser) { diff --git a/src/misc/util.ts b/src/misc/util.ts index d2baf68f..f67fac2f 100644 --- a/src/misc/util.ts +++ b/src/misc/util.ts @@ -2,7 +2,7 @@ * Takes a function `action` and returns a new function, that behaves * like action but when called a second time does nothing. */ -export const indempotent = (action: (x: any) => T) => { +export const idempotent = (action: (x: any) => T) => { let called = false let result: T | undefined = undefined