Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native support #1013

Open
aboodman opened this issue Jul 31, 2022 · 20 comments
Open

React Native support #1013

aboodman opened this issue Jul 31, 2022 · 20 comments
Labels
Future Something we want to fix but is not blocking next release

Comments

@aboodman
Copy link
Contributor

aboodman commented Jul 31, 2022

Currently it is possible to use Replicache with React Native by implementing experimentalKVStore and hooking it to SQLite. However it's quite manual. We should have first-class support for RN, including:

  • a sample app
  • first-class bindings to SQLite
@aboodman aboodman moved this to Planned in Replicache Roadmap Jul 31, 2022
@arv arv added the Future Something we want to fix but is not blocking next release label Oct 20, 2022
@izakfilmalter
Copy link

This would be much appreciated. If the example used expo that would be a win, https://docs.expo.dev/versions/latest/sdk/sqlite/.

@aboodman
Copy link
Contributor Author

This is currently being addressed well by https://github.com/Braden1996/react-native-replicache, but we should consider making it first-class.

@aboodman aboodman moved this from Planned to In Progress in Replicache Roadmap Dec 12, 2023
@darioielardi
Copy link

darioielardi commented Dec 12, 2023

This is currently being addressed well by https://github.com/Braden1996/react-native-replicache

@aboodman I've been recently trying to go that way but unfortunately replicache@14 (maybe even from v13) does not work in react native at all.

  • metro cannot resolve replicache dependencies like @rocicorp/logger (can probably be solved with unstable package exports support).
  • apparently replicache now uses EventTarget which is not available in react native

Also, react-native-replicache doesn't seem to work with expo-sqlite@11 because the native module gets imported with the wrong key from the native modules proxy. It doesn't seem maintained at all tbh.

Can you share any plans for an official and reliable solution?

Edit: I just tested with replicache@13, I get ReferenceError: Property 'BroadcastChannel' doesn't exist.

@aboodman
Copy link
Contributor Author

Ah, I did not know that react-native-replicache had stopped working. Thanks for the information.

@darioielardi
Copy link

Ah, I did not know that react-native-replicache had stopped working. Thanks for the information.

@aboodman It's not just react-native-replicache, actually the problems with that library are easily solvable, the real problems are with the replicache library, which doesn't work in a react native environment anymore because of the use of browser-only APIs like BroadcastChannel and EventTarget.

I'd really like to use Replicache in my mobile apps (I think that's where local-first apps really shine), but these problems related to browser-only APIs make me think that react native support is not even being considered, which is fair but it'd be great to know that before committing to anything.

Would you mind sharing your team's plans about this, if any?

@aboodman
Copy link
Contributor Author

Thanks @darioielardi.

So we fixed the BroadcastChannel dependency in Replicache 14:

https://www.notion.so/replicache/Replicache-14-0-3-3dce462db565425c846875b488677c07?pvs=4#64335524f55f402597dec4c521912e66

This wasn't for React Native, but older Safaris. Unfortunately, we introduced the EventTarget dep at same time:

CleanShot 2023-12-13 at 08 35 18@2x

The real issue here is that we don't have a RN sample, and thus aren't testing RN as part of our release process. I agree you should not rely on RN for anything real if we're not doing that.

I do not have a concrete timeline for this right now other than 2024. I'll have a better idea in January.

@darioielardi
Copy link

darioielardi commented Dec 14, 2023

@aboodman that makes sense, I'll look forward to any updates on official React Native support and take some other route in the meantime, thank you!

@robsoden
Copy link

wanted to post some updates here as we just completed a successful upgrade to replicache 14 on react-native. here are the workarounds to everything we ran into:

  • there's a polyfill for EventTarget (thanks to @aboodman for pointing us toward it) https://www.npmjs.com/package/event-target-polyfill - just add this to your dependencies, and add an import to your project root (in index.js)

  • there were a couple of changes to our babel config that were tricky to figure out. here's our config:

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    '@babel/plugin-transform-flow-strip-types',
    'react-native-reanimated/plugin',
    ['@babel/plugin-transform-private-methods', { loose: true }],
  ],
};

['@babel/plugin-transform-private-methods', { loose: true }] was required by something in the replicache module. however, this broke react-native flatlists in our jest tests. '@babel/plugin-transform-flow-strip-types', was the solution for that.

  • finally, we used patch-package to fix the @rocicorp dependencies for the replicache module. They've been bundled in such a way where the output file is in a out folder, but the package.json is missing a main delcaration, so the bundler gets confused. you can use patch-package with the --exclude flag like so:
    npx patch-package --exclude '^$' @rocicorp/resolver
    to add main to each of the sub-packages package.json (resolver, logger, and lock)
    ex: "main": "./out/logger.js",

also, react-native-replicache is still working for us (thankfully) but we are NOT using expo, so YMMV.

hope all of this this helps somebody!

@darioielardi
Copy link

darioielardi commented Dec 20, 2023

@robsoden thank you very much! Inspired by your comment I went ahead and tried to make it work again, this time with @react-native-replicache/react-native-quick-sqlite.

I successfully setup babel and patched all the packages, but I'm still getting errors with @react-native-replicache/react-native-quick-sqlite:

  • with [email protected] I'm getting Quick SQLite Error: Cannot execute query on finalized transaction.
  • with [email protected] and @react-native-replicache/react-native-quick-sqlite patched based on this PR I get Error: unable to open database file.

Do you mind sharing your setup? Or at least what version of these libraries you are using?

@robsoden
Copy link

@darioielardi glad it was helpful!

so I'm using the following:
"@react-native-replicache/react-native-quick-sqlite": "^1.0.0"
"react-native-quick-sqlite": "^8.0.4"

and then I've used patch-package to apply those 2 changes to the ReplicacheQuickSQLiteTransaction class (since my PR you found hasn't been merged yet)

the generated patch ends up looking like this:

diff --git a/node_modules/@react-native-replicache/react-native-quick-sqlite/src/replicache-quick-sqlite-transaction.ts b/node_modules/@react-native-replicache/react-native-quick-sqlite/src/replicache-quick-sqlite-transaction.ts
index a86aaa7..710f9a9 100644
--- a/node_modules/@react-native-replicache/react-native-quick-sqlite/src/replicache-quick-sqlite-transaction.ts
+++ b/node_modules/@react-native-replicache/react-native-quick-sqlite/src/replicache-quick-sqlite-transaction.ts
@@ -2,7 +2,7 @@ import { ReplicacheGenericSQLiteTransaction } from "@react-native-replicache/rep
 import * as QuickSQLite from "react-native-quick-sqlite";
 
 export class ReplicacheQuickSQLiteTransaction extends ReplicacheGenericSQLiteTransaction {
-  private _tx: QuickSQLite.TransactionAsync | null = null;
+  private _tx: QuickSQLite.Transaction | null = null;
   private _transactionCommittedSubscriptions = new Set<() => void>();
   private _txCommitted = false;
   private _transactionEndedSubscriptions = new Set<{
@@ -20,7 +20,7 @@ export class ReplicacheQuickSQLiteTransaction extends ReplicacheGenericSQLiteTra
     return await new Promise<void>((resolve, reject) => {
       let didResolve = false;
       try {
-        this.db.transactionAsync(async (tx) => {
+        this.db.transaction(async (tx) => {
           didResolve = true;
           this._tx = tx;
           resolve();

let me know if there's any other info that might help

@robsoden
Copy link

oh and also FWIW here's my replicache instantiation, nothing really unique here:

const replicache = new Replicache<MutatorsTypeDef>({
          licenseKey: Config.REPLICACHE_LICENSE_KEY ?? '',
          experimentalCreateKVStore:
            createReplicacheReactNativeQuickSQLiteExperimentalCreateKVStore,
          name: 'your-project',
          mutators,
          pullInterval: null,
          puller: customPuller,
          pusher: customPusher,
          indexes: {
            ...
          },
          pushDelay: 5000,
        });

@aboodman
Copy link
Contributor Author

aboodman commented Dec 20, 2023

If anyone here is interested in contracting for Rocicorp to get this cleaned up, I would pay for it. I want to (a) fix Replicache to install cleanly in rn and expo, (b) if there are any automated unit style tests we can add to avoid regressions do that, (c) have a working sample of todo thst works in in rn and expo with instructions on how to set up and run that any react (web) dev can successfully follow to test and debug changes.

If you’re interested dm me on discord.replicache.dev.

@darioielardi
Copy link

darioielardi commented Dec 22, 2023

@robsoden I realized the reason it wasn't working is that I was using user/userId as the client name, which is not a valid filename for the SQLite db 🤦‍♂️

Everything works now! I think I'll try to make it work with expo-sqlite and post any updates here. Thanks again for all your support!

@darioielardi
Copy link

darioielardi commented Dec 22, 2023

@aboodman apparently on your side the only necessary change is to add the "main" field to every packages.json, 4 out of 5 patches I have are for that (all @rocicorp/ packages and replicache-react).

About the EventTarget polyfill, I guess it can be addressed with a recommendation in the docs.

@robsoden
Copy link

Anyone else working with Repliache and react-native may have also noticed that react-native-quick-sqlite has recently been deprecated, with the maintainer suggesting a migration to op-sqlite (https://github.com/ospfranco/react-native-quick-sqlite)

quick-sqlite was the main underlying store implemented by the (very excellent) react-native-replicache package (https://github.com/Braden1996/react-native-replicache)

Luckily, thanks to the very solid work on that package, it was pretty trivial to swap in op-sqlite. I've submitted a PR there in the hopes that they'll publish a new adapter.

Feel free to reach out if anyone needs this and has trouble implementing. If there's no movement on the PR over there, we may just publish it ourselves depending on outside interest.

Thanks!

@NavaceSystem
Copy link

Anyone else working with Repliache and react-native may have also noticed that react-native-quick-sqlite has recently been deprecated, with the maintainer suggesting a migration to op-sqlite (https://github.com/ospfranco/react-native-quick-sqlite)

quick-sqlite was the main underlying store implemented by the (very excellent) react-native-replicache package (https://github.com/Braden1996/react-native-replicache)

Luckily, thanks to the very solid work on that package, it was pretty trivial to swap in op-sqlite. I've submitted a PR there in the hopes that they'll publish a new adapter.

Feel free to reach out if anyone needs this and has trouble implementing. If there's no movement on the PR over there, we may just publish it ourselves depending on outside interest.

Thanks!

Ran into the same issues and your fixes worked like a charm. Thank you!

I've pinged the owner of https://github.com/Braden1996/react-native-replicache and he said he'll have a look at the open PRs tomorrow.

@Braden1996
Copy link

Braden1996 commented May 28, 2024

Hello all!

Over the weekend I upgraded the React Native Replicache libraries in a few ways. Sorry for not being better with this.

It is worth noting:

  • The migration path around switching bindings is unclear to me.
  • I've not thoroughly tested the new op-sqlite and expo-sqlite bindings.

@aboodman as for an example app you can add to your test flow, the example provided in that repo should work pretty well and I've added some instructions to the Readme. More than happy to hop on a call and go through it!

Also, regarding EventTarget being introduced, I would suggest removing dom from your internal repo's TSConfig lib. The TS ecosystem has a habit of sticking this in everywhere. We recently removed it from all unnecessary packages at Attio (basically by introduce a "universal types" package which defined the client APIs we expect to be available on all runtimes, like setTimeout).

@arv
Copy link
Contributor

arv commented Jun 6, 2024

Also, regarding EventTarget being introduced, I would suggest removing dom from your internal repo's TSConfig lib. The TS ecosystem has a habit of sticking this in everywhere. We recently removed it from all unnecessary packages at Attio (basically by introduce a "universal types" package which defined the client APIs we expect to be available on all runtimes, like setTimeout).

I would love to do this. It has been a pet peeve of mine for the last year at least. We do have a lot of bindings (through IDB and fetch) so we need to maintain a copy of those entire type hierarchies. Is your "universal types" package available?

@Braden1996
Copy link

Also, regarding EventTarget being introduced, I would suggest removing dom from your internal repo's TSConfig lib. The TS ecosystem has a habit of sticking this in everywhere. We recently removed it from all unnecessary packages at Attio (basically by introduce a "universal types" package which defined the client APIs we expect to be available on all runtimes, like setTimeout).

I would love to do this. It has been a pet peeve of mine for the last year at least. We do have a lot of bindings (through IDB and fetch) so we need to maintain a copy of those entire type hierarchies. Is your "universal types" package available?

We don't plan on publishing it, unfortunately.
Although it's pretty straightforward: mostly a rip of React Native's global types, which you can find here: https://www.npmjs.com/package/react-native?activeTab=code under /react-native/types/modules/globals.d.ts

@harrysolovay
Copy link

I'd very much like to use Replicache in an Expo (v51) project. Wondering if this is advisable or if I should hold off for now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Future Something we want to fix but is not blocking next release
Projects
Status: In Progress
Development

No branches or pull requests

8 participants