pouchdb-react-native
pouchdb-react-native copied to clipboard
Attachments Support
This issue is to act as a placeholder for work remaining to fully support Attachments.
The remaining issues are as follows:
- On replication to remote CouchDB where the local doc contains an attachment it should successfully sync the doc and attachment data. If doc contains an attachment sync fails.
- On replication from remote CouchDB were the remote doc contain an attachment it should successfully sync the doc and attachment data. If doc contains an attachment sync fails.
Considerations unique to ReactNative:
(Note: these following information is based on my observations, some accuracy may be missing, please correct where appropriate. I'm still learning how the ReactNative packager works.)
- ReactNative has 2 runtimes V8 in Debug and JSC in Release.
- During Debug (simulator build in Debug) the application is packaged targeting the browser (Chrome V8) and we have access to the window and DOM and other browser native implementations e.g. Blob
- During JSC Release (simulator build in Release) the application is packaged targeting JSC and we do not have access to the window and DOM. JSC isn't at feature parity with V8. Blob is replaced with node's Buffer.
- Most polyfills fallback to native browser when available, which causes some interesting results between Debug and Release.
- ReactNative only uses fetch
- PouchDB has many dependencies - adapters, plugins, utils - each of these are packages for node or browser. However, ReactNative packager always chooses the browser version during package resolution (based on my testing)
Research:
- This library currently has a hack during the
postinstal
phase, where thepouchdb-binary-utils/package.json
is patched to force the ReactNative packager to chose the node versions of the library. - If I remove the above hack locally:
- I can successfully get sync to work for all use cases, on iOS simulator in V8 Debug. This is due to the reliance on both this library and all Pouchdb dependencies choosing browser installs, and and native browser lib implementations, all the way down.
- During JSC release mode, on iOS simulator, I receive Blobs from the
pouchdb-adapter-http
, which in turn delegated topouchdb-ajax
. Since ReactNative runtime JSC has no support for FileReader/FileReaderSync we do not have a utility to transform aBlob
toBuffer
orBase64
. more context here- I believe we can get an
ArrayBuffer
in all cases instead of returning aBlob
and be in a better situation. More research needed here. - We also cannot opt for the the node version of
pouchdb-ajax
because it relies onrequest
which will not work in ReactNative without hacks to expose additional core node modules.
- I believe we can get an
Next Steps:
- I've been building out test cases for Attachments. All scenarios pass. This is due to our test suite being run in a fully node.js context and doesn't represent the ReactNative runtime. In the future it would be beneficial to extend coverage to more environment.
- I've currently forked both
pouchdb-adapter-http
andpouchdb-ajax
and have created ReactNative versions of these and am experimenting with getting full support for both Debug and Release. For these versions I'm supporting onlyfetch
and always returningArrayBuffer
neverBlob
. This is getting close. However, many tests are not passing locally. - I believe if we can patch the above utilities then we will have full - or very close - support for Attachments in this library, for both the Debug and Release contexts.
- I am worried that this effort could snowball into to essentially forking PouchDB, but right now I'm not seeing the need for this.
- I could use some additional direction in terms of patching
pouchdb-adapter-http
. My current build hasn't made any changes except to the new pouchdb-ajax delegation library. There is currently no way to provide strategies without having direct access to the PouchDB instance. Long term this will not be maintainable without a strategy pattern in place at plugin registry. Also, there may be much better ways of injecting a different implementation, will need some direction from @nolanlawson e.g.
const db = new PouchDB('local');
db._ajax = fetchCore;
Any additional approaches, solutions, consideration, corrections etc. is greatly appreciated. I'll keep the issue up-to-date will all progress.
Update:
I've got both scenarios working: V8 Debug and JSC Release by using react-native-fetch-blob. react-native-fetch-blob
polyfills both XMLHttpRequest, Fetch, and Blob. The Blob implementation defers to a Native implementation and relies on the devices file system to store the blob. With this library we can easily fetch blobs and transform them as we need. But it creates a new set of dependencies on this library etc.
I'm trying to get my fork up-to-date with my current prototype - I'll post further updates when that is completed.
Direction
After working through some use-cases I'm starting to realize that Blob support, on a Native Device, would not be realistic to do in-memory. Moving data in-out of AsyncStorage into Device memory probably only work for small files, and probably lead to instability at any real scale. My longterm approach would be to keep Attachments stored on the filesystem and stream to CouchDB on sync. Ideally we would try to remove any in-memory loading of Attachments in this library.
This could be a large shift in the direction of this library.
More discussions needed. Once I get my fork updated I'll go over the code and talk about options and tradeoffs.
I finally have a working branch that supports Attachment replication/sync in both V8 (Debug) and JSC (Release) modes. Currently tested in iOS. There are 8 failing regression tests (from the original pouchdb regression set) that I'll be fixing soon.
Code is in a branch on my fork here: https://github.com/jurassix/pouchdb-react-native/tree/attachments
Note:
I've updated the package.json
so we use the GitHub repo as a npm dependency. Add the following to your package.json
to test out the fork above (works with npm = 3):
{
"dependencies": {
"pouchdb-react-native": "git://github.com/jurassix/pouchdb-react-native.git#4a44854ffa5566126d023669218dd2ee8801025e"
}
}
The main enhancements are as follows:
-
packages/pouchdb-adapter-http-react-native - this package is a copy of
pouchdb-adapter-http
that injectspouchdb-fetch-react-native
to replace thepouchdb-ajax
module by default. There are also a couple of enhancements to blob handling forreact-native-fetch-blob
-
packages/pouchdb-fetch-react-native - this packages is a copy of the
pouchdb-ajax
library but refactored to always usefetch
-
packages/pouchdb-adapter-asyncstorage - this package has extra blob handling for
react-native-fetch-blob
To fully support Attachments your library must use react-native-fetch-blob. Code changes made to pouchdb-react-native
inspect at runtime to determine if it should delegate to react-native-fetch-blob
. This allows users to not have this dependency if they do not require Attachment support.
To use the above fork, you need to follow the install instructions from react-native-fetch-blob and then add the following code to you app:
import RNFetchBlob from 'react-native-fetch-blob'
global.Blob = RNFetchBlob.polyfill.Blob
const Fetch = RNFetchBlob.polyfill.Fetch
// replace built-in fetch
global.fetch = new Fetch({
auto : true,
// now, response with Content-Type contains `image/`, `video/`, and `video/`
// will downloaded into file system directly.
binaryContentTypes : ['image/', 'video/', 'audio/']
}).build()
The above code will polyfill both Fetch and Blob support in your application and pouchdb-react-native
will leverage this to transform Blobs to Base64 and Base64 to Blobs etc.
Next steps:
- Fix 8 failing tests from regression suite
- Document all the changes made to support Blobs in RN
- Determine if there is a simpler or smaller footprint solution that the one presented in the fork
- Determine if there is a way to never load an Attachment into memory in any intermediary steps e.g. only if the developer specifically needs the Blob content - Perf optimization
- Brainstorm with @nolanlawson about how to leverage more of the existing pouchdb code base e.g. how will we maintain and support packages/pouchdb-adapter-http-react-native, is there a better pattern for injecting behavior etc
- Test Android support
- Formalize the solution with @stockulus and release
CC @jaredly @ddolheguy @cmrichards @tseck
@jurassix Thanks for the great work you did!
If you like to chat/talk with me about the integration just ping me via Twitter. In the evening Hours Central European Time works best for me.
@stockulus @jurassix Any new developments on this?
@kkbhav I'm still using the fork from above for my needs. I think we should be able to move this work into an official branch and release under a tagged npm version as a first next step.
Something like pouchdb-react-native@attachment
?
@stockulus I'll reach out to you via Twitter this weekend to talk about options. Moving this into a mainline branch and releasing it will go along way in getting people to help verify and find issues before we move to master. Any initial thoughts?
@jurassix thats fine for me.
Is there additional setup work needed like react-native link...? If so, I'd write some documentation.
@stockulus Nope the only thing that is needed for attachment support is for users to follow the install instructions from react-native-fetch-blob and then add the following code to you app:
import RNFetchBlob from 'react-native-fetch-blob'
global.Blob = RNFetchBlob.polyfill.Blob
const Fetch = RNFetchBlob.polyfill.Fetch
// replace built-in fetch
global.fetch = new Fetch({
auto : true,
// now, response with Content-Type contains `image/`, `video/`, and `video/`
// will downloaded into file system directly.
binaryContentTypes : ['image/', 'video/', 'audio/']
}).build()
If you don't do the above pouchdb-react-native
will work exactly as it does today, users are who need attachment support have to do the above dependency and setup, otherwise the library should just match current master functionality.
Note, a project to watch out for in the future will be react-native-node which essentially allows us to run a node.js instance in the background of our apps (currently only supports Android.) With this project we should have many more options for handling attachments in the future.
I am already watching this Project, would be so great, not only for this Project!
@jurassix if you create a Pull Request agains https://github.com/stockulus/pouchdb-react-native/tree/attachments I'd take care of the Documentation and publish it on npm with @ attachment
@stockulus thanks for setting this up. I'm swamped with deadlines through Friday. Hopefully I'll have some this weekend to port over.
Can I assume that each of the existing packages
pouchdb-adapter-asyncstorage, pouchdb-react-native (plus the two I've added) will be released as @attachment
version?
Right now I just have relative paths between the packages in my branch, would be best to require these from npm.
@jurassix no stress!!
I'd publish them on npm with @attachment version and write few line in the readme about it
Hi,
I'have problem when I use "npm install pouchdb-react-native@attachment" command. Is that supposed to work ?
Sorry did not manage it yet, still waiting for the merged code. Try install via git link from @jurassix
as soon the https://github.com/stockulus/pouchdb-react-native/tree/attachments is up to date, I'll publish it.
@Franklin62120 @stockulus Hopefully I'll start working on the Attachment Release soon, until then let me know if you have any issues installing via Git. The only issues I've encountered is npm versions unpack the project slightly different. If you hit any issues in the interim please raise them and I'll help where I can.
Again, apologies on the delays.
Ok, thanks. It's not blocking for my project. I'll just wait a future attachment release.
@stockulus I've started working on the migration. Hopefully I'll have this completed this weekend.
@jurassix how did it went? is attachment support stable now?
Still in-progress, again apologies for the delay. The fork is stable, I've been using it production for 6+months. Expect update soon.
Hey, any updates?
Subscribing.
I’m still, slowly, making progress. Current status is trying to get all regression tests to pass.
FYI: A PR that adds Blob support to RN has been finally merged:
https://github.com/facebook/react-native/pull/11573
@craftzdog that sounds great, that makes it much easier
@stockulus @craftzdog I knew my procrastination was purposeful ;) . Most of the changes in this issue were to get Blob support to work with fetch, so we should scrap this work in favor of RN.
Guess we need to do a prototype with attachments and see if we are good.
Any news on this? Considering PouchDB for a project but would need Attachments :)
I've spent all day trying to get this to work any way possible, and am hitting a brick wall with being able to install the forked branch from github and get it working. If I edit my package.json
as indicated above to have the "pouchdb-react-native": "github:jurassix/pouchdb-react-native#attachments"
, npm won't install anything, and if I do npm install --save github:jurassix/pouchdb-react-native#attachments
from the command line I get the directory to be created, but I also get an error:
Error: Cannot find module '/home/.../node_modules/pouchdb-react-native-bundle/packages/pouchdb-react-native/setup.js'
It still creates a pouch-db-react-native-bundle folder in my node_modules folder, but it doesn't have an index.js in it and can't be referenced by the code.
Any help you can offer, @jurassix or @stockulus would be hugely appreciated.
@equesteo yes I'm also experiencing this issue now. I've update the postinstall script, so the error you reached should be resolved. There are a couple other issues I'm seeing. The package is now being installed under the pouchdb-react-native-bundle
module name, and the version of npm is important.
To resolve the module name issue, I've renamed it manually inside my node_modules to be pouchdb-react-native
. This is not ideal, I'll look into how to properly handle.
Npm version is also important. Because this is a fork, the packages/ folder has newly added packages, that are not published to npm (pouchdb-fetch-react-native, pouchdb-adapter-http-react-native). These are npm installed via file paths, and new versions of npm create symlinks which breaks the React Native bundler in my testing. I've had to downgrade to node 6 + npm 3, I'm using nvm so it's not a pain. Again it's not ideal.
Doing the above has allowed the fork to install and work.
Based on the blob support now added to natively to RN's fetch, I don't think we need the fork going forward, assuming you can upgrade to the latest RN. I'm trying to put together a working example and flush out any open issues this library has to support Attachments.
Let me know if you struggle with the above install suggestions, I'll do what I can to help.
@jurassix Whats the current status of attachments? Does it work without the fork?