React Native에서 사용하기 위해 PouchDB 해킹



업데이트(2021/02/12)








안녕하세요, 여기 있습니다.

CouchDB와 데이터를 동기화해야 하는 React Native 앱을 개발 중입니다.
PouchDB 브라우저용 JavaScript로 작성된 CouchDB와 동기화할 수 있는 잘 설계된 데이터베이스는 React Native에서도 사용할 수 있습니다.
RN에서 작동하도록 react-native-sqlite-2pouchdb-adapter-react-native-sqlite을 빌드했습니다.

그러나 여전히 작동하려면 몇 가지 문제가 있습니다.
예를 들어, RN이 아직 FileReader.readAsArrayBuffer를 지원하지 않기 때문에 storing attachments에 큰 문제가 있습니다.

요즘 pouchdb-react-native 프로젝트가 활동하지 않는 것 같습니다.
그래서 저는 PouchDB가 RN에서 완벽하게 실행될 수 있도록 노력했고 성공적으로 해냈습니다. 여기 내가 한 일이 있습니다.

RN에서 PouchDB를 실행하는 방법



먼저 RN에서 PouchDB를 사용하는 방법을 보여드리고자 합니다.
공식 PouchDB 핵심 모듈을 기반으로 해킹한 일부 패키지를 만들었습니다.
다음은 a working demo app 입니다.
Inkdrop이라는 프로덕션 앱에서 사용할 계획입니다.

뎁 설치



PouchDB 핵심 패키지를 설치하십시오.

npm i pouchdb-adapter-http pouchdb-mapreduce


React Native용으로 해킹된 패키지를 설치합니다.

npm i @craftzdog/pouchdb-core-react-native @craftzdog/pouchdb-replication-react-native 


다음으로 SQLite3 엔진 모듈을 설치합니다.

npm i pouchdb-adapter-react-native-sqlite react-native-sqlite-2
react-native link react-native-sqlite-2


그런 다음 PouchDB에 필요한 기능을 폴리필하기 위해 일부 패키지를 설치하십시오.

npm i base-64 events


폴리필 만들기



PouchDB에 필요한 일부 기능을 폴리필하기 위해 js 파일을 만드십시오.

import {decode, encode} from 'base-64'

if (!global.btoa) {
    global.btoa = encode;
}

if (!global.atob) {
    global.atob = decode;
}

// Avoid using node dependent modules
process.browser = true

index.js 의 첫 번째 줄에서 가져옵니다.

파우치DB 로드


pouchdb.js를 다음과 같이 만듭니다.

import PouchDB from '@craftzdog/pouchdb-core-react-native'
import HttpPouch from 'pouchdb-adapter-http'
import replication from '@craftzdog/pouchdb-replication-react-native'
import mapreduce from 'pouchdb-mapreduce'

import SQLite from 'react-native-sqlite-2'
import SQLiteAdapterFactory from 'pouchdb-adapter-react-native-sqlite'

const SQLiteAdapter = SQLiteAdapterFactory(SQLite)

export default PouchDB
  .plugin(HttpPouch)
  .plugin(replication)
  .plugin(mapreduce)
  .plugin(SQLiteAdapter)

pouchdb-find 와 같은 다른 플러그인이 필요한 경우 추가하면 됩니다.

PouchDB 사용



그런 다음 평소와 같이 사용하십시오.

import PouchDB from './pouchdb'

function loadDB () {
  return new PouchDB('mydb.db', { adapter: 'react-native-sqlite' })
}


내가 PouchDB를 해킹한 방법



React Native에서 작동하게 하려면 PouchDB 코어 모듈에서 호출FileReader.readAsArrayBuffer을 피해야 합니다.
즉, Blob 대신 항상 Base64에서 첨부 파일을 처리합니다.
a few lines of code hacks 으로 할 수 있습니다.

readAsArrayBuffer가 호출되는 위치



PouchDB는 readAsArrayBuffer를 호출해야 하는 모든 문서에 대해 MD5 다이제스트를 계산하려고 시도합니다.
pouchdb-binary-utils/lib/index-browser.js에서:

72 function readAsBinaryString(blob, callback) {
73   if (typeof FileReader === 'undefined') {
74     // fix for Firefox in a web worker
75     // https://bugzilla.mozilla.org/show_bug.cgi?id=901097
76     return callback(arrayBufferToBinaryString(
77       new FileReaderSync().readAsArrayBuffer(blob)));
78   }
79
80   var reader = new FileReader();
81   var hasBinaryString = typeof reader.readAsBinaryString === 'function';
82   reader.onloadend = function (e) {
83     var result = e.target.result || '';
84     if (hasBinaryString) {
85       return callback(result);
86     }
87     callback(arrayBufferToBinaryString(result));
88   };
89   if (hasBinaryString) {
90     reader.readAsBinaryString(blob);
91   } else {
92     reader.readAsArrayBuffer(blob);
93   }
94 }


이 함수는 pouchdb-md5/lib/index-browser.js에서 호출됩니다.

24 function appendBlob(buffer, blob, start, end, callback) {
25   if (start > 0 || end < blob.size) {
26     // only slice blob if we really need to
27     blob = sliceBlob(blob, start, end);
28   }
29   pouchdbBinaryUtils.readAsArrayBuffer(blob, function (arrayBuffer) {
30     buffer.append(arrayBuffer);
31     callback();
32   });
33 }


글쎄, 그것을 피하는 방법?

첨부 파일 저장



다음과 같이 binary에서 getAttachment 메서드의 pouchdb-core/src/adapter.js 옵션을 비활성화합니다.

714     if (res.doc._attachments && res.doc._attachments[attachmentId]
715       opts.ctx = res.ctx;
716       // force it to read attachments in base64
717       opts.binary = false;
718       self._getAttachment(docId, attachmentId,
719                           res.doc._attachments[attachmentId], opts, callback);
720     } else {


이 변경으로 인해 항상 base64로 인코딩된 첨부 파일을 받게 됩니다.

풀 복제



다음과 같이 pouchdb-replication/lib/index.js의 원격 데이터베이스에서 첨부 파일을 가져올 때 Blob을 base64로 변환해야 합니다.

function getDocAttachmentsFromTargetOrSource(target, src, doc) {
  var doCheckForLocalAttachments = pouchdbUtils.isRemote(src) && !pouchdbUtils.isRemote(target);
  var filenames = Object.keys(doc._attachments);

  function convertBlobToBase64(attachments) {
    return Promise.all(attachments.map(function (blob) {
      if (typeof blob === 'string') {
        return blob
      } else {
        return new Promise(function (resolve, reject) {
          var reader = new FileReader();
          reader.readAsDataURL(blob);
          reader.onloadend = function() {
            const uri = reader.result;
            const pos = uri.indexOf(',')
            const base64 = uri.substr(pos + 1)
            resolve(base64)
          }
        });
      }
    }));
  }

  if (!doCheckForLocalAttachments) {
    return getDocAttachments(src, doc)
      .then(convertBlobToBase64);
  }

  return target.get(doc._id).then(function (localDoc) {
    return Promise.all(filenames.map(function (filename) {
      if (fileHasChanged(localDoc, doc, filename)) {
        return src.getAttachment(doc._id, filename);
      }

      return target.getAttachment(localDoc._id, filename);
    }))
      .then(convertBlobToBase64);
  }).catch(function (error) {
    /* istanbul ignore if */
    if (error.status !== 404) {
      throw error;
    }

    return getDocAttachments(src, doc)
      .then(convertBlobToBase64);
  });
}


그것은 효과가 있었다!
그래서 @craftzdog/pouchdb-core-react-native@craftzdog/pouchdb-replication-react-native 를 모두 만들었습니다.
문제가 발견되면 끌어오기 요청을 환영합니다here.

좋은 웹페이지 즐겨찾기