powersync-js icon indicating copy to clipboard operation
powersync-js copied to clipboard

Support for react-native-web

Open jasonlewicki opened this issue 1 year ago • 10 comments
trafficstars

I'm having trouble getting powersync installed and working with an expo universal app (react-native and react-native-web)

Error running powersync/react-native on web: Screenshot 2024-07-26 at 2 23 27 PM

text version of the link: https://github.com/expo/fyi/blob/main/fb-batched-bridge-config-web.md

jasonlewicki avatar Jul 26 '24 19:07 jasonlewicki

If i use @powersync/web, i get the error: Uncaught SyntaxError: Cannot use 'import.meta' outside a module (at index.bundle?platform=web&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.routerRoot=src%2Fapp:258371:114)

which comes from here:

class SharedWebStreamingSyncImplementation extends _WebStreamingSyncImplementation.WebStreamingSyncImplementation {
    constructor(options) {
      super(options);
      /**
       * Configure or connect to the shared sync worker.
       * This worker will manage all syncing operations remotely.
       */
      const syncWorker = new SharedWorker(new URL('../../worker/sync/SharedSyncImplementation.worker.js', import.meta.url), {
        /* @vite-ignore */
        name: `shared-sync-${this.webOptions.identifier}`,
        type: 'module'
      });

jasonlewicki avatar Jul 26 '24 19:07 jasonlewicki

Additional info, issue raised on expo: https://github.com/expo/expo/issues/21099 https://github.com/expo/expo/issues/30323

jasonlewicki avatar Jul 26 '24 20:07 jasonlewicki

here's a git repo reproducing the error:

https://github.com/fig-wealth/powersync-react-native-web

npx expo install npx expo start w to launch web

jasonlewicki avatar Jul 27 '24 02:07 jasonlewicki

Metro does not support esm, probably wont until at least next year: https://github.com/facebook/metro/issues/916 https://github.com/facebook/metro/issues/886

any chance of making a commonjs transpile of powersync or changing the import.meta.url instances?

jasonlewicki avatar Jul 27 '24 05:07 jasonlewicki

Thanks for the detailed issue and example repository! We'll use your example to investigate the requirements - I'll keep you posted when we have an update.

stevensJourney avatar Jul 29 '24 11:07 stevensJourney

I was missing a commit, i've since added it to the repo. apologies

jasonlewicki avatar Jul 29 '24 13:07 jasonlewicki

To give you all an update, and potentially reduce the problem set, I've created another branch that conditionally incorporates @powersync/react-native

https://github.com/fig-wealth/powersync-react-native-web/tree/with-react-native

As far as I can tell, it works on iOS (at least saying the auth is wrong... [I have the self hosted demo running]) Screenshot 2024-07-29 at 2 01 35 PM

jasonlewicki avatar Jul 29 '24 19:07 jasonlewicki

We've done an initial investigation where we identified some hurdles and potential solutions for providing React Native web support. We have managed to get an example POC running using a UMD bundled version of the Web SDK. Support may be available in the near future.

stevensJourney avatar Aug 05 '24 10:08 stevensJourney

That's great news. I can't wait 👍

jasonlewicki avatar Aug 05 '24 20:08 jasonlewicki

The dev build has been working great so far. Thanks for all the hard work!

jasonlewicki avatar Aug 12 '24 15:08 jasonlewicki

Hey team. We're trying to build for MVP over here: npx expo export -p w --clear

This is the error we are getting on load: Failed to fetch a worker script. Pretty sure it's powersync.

Here's a screen grab of the dist directory: Screenshot 2024-08-30 at 10 57 41 AM

I'll try to get more information shortly.

jasonlewicki avatar Aug 30 '24 15:08 jasonlewicki

Ok we're in business.

i have a git action:

# Copy public powersync files to dist directory
- name: Copy public files to dist directory
  run: |
    # Define the source and destination directories
    SOURCE_DIR="apps/client/dist"
    DEST_DIR="apps/client/dist/_expo/static/js/web"

    # Create the destination directory if it doesn't exist
    mkdir -p $DEST_DIR

    # Copy all files from the source to the destination
    cp -r $SOURCE_DIR/* $DEST_DIR

Moving the files into the _expo/web/js directory fixed it! This is probably just an artifact of the dev build.

jasonlewicki avatar Aug 31 '24 01:08 jasonlewicki

hi @jasonlewicki , so does the powersync work on expo web now? Do we need to add more config like git action you paste above? Thanks

ducpt-bili avatar Sep 02 '24 14:09 ducpt-bili

hi @jasonlewicki , so does the powersync work on expo web now? Do we need to add more config like git action you paste above? Thanks

@ducpt-bili Hey, yeah, until the team merges into main, there's a list of things you need to do to get it working:

install these:

"@powersync/attachments": "0.0.0-dev-20240812065227",
"@powersync/common": "0.0.0-dev-20240812065227",
"@powersync/kysely-driver": "0.0.0-dev-20240812065227",
"@powersync/react": "0.0.0-dev-20240812065227",
"@powersync/react-native": "0.0.0-dev-20240812065227",
"@powersync/web": "0.0.0-dev-20240812065227",

Then, add this script:

// This file is required for the dev build of powersync to work properly.
// It copies the necessary files from the node_modules/@powersync/web/dist directory to the public directory.
// Gets around the package being built with esm modules and not being able to be resolved by metro.
// This is a temporary solution until the package is updated.

const fs = require('fs');
const path = require('path');
// Source directory
const sourceDir = path.join(
  __dirname,
  'node_modules',
  '@powersync',
  'web',
  'dist',
);
const destDir = path.join(__dirname, 'public');
function copyRecursiveSync(src, dest) {
  if (fs.existsSync(src) && fs.statSync(src).isDirectory()) {
    // Create the destination directory if it doesn't exist
    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest, { recursive: true });
    }
    const files = fs.readdirSync(src);
    // Copy each file/directory
    files.forEach((file) => {
      const srcFile = path.join(src, file);
      const destFile = path.join(dest, file);
      if (fs.statSync(srcFile).isDirectory()) {
        copyRecursiveSync(srcFile, destFile);
      } else {
        fs.copyFileSync(srcFile, destFile);
      }
    });
  } else {
    // eslint-disable-next-line no-console
    console.error(
      `Source directory ${src} does not exist or is not a directory.`,
    );
  }
}
// Execute the copy
copyRecursiveSync(sourceDir, destDir);
// eslint-disable-next-line no-console
console.log(`Files copied from ${sourceDir} to ${destDir} successfully.`);

and run it.

then modify your metro config to add this:

const customResolveRequest = (context, moduleName, platform) => {
  if (platform === 'web') {
    if (
      ['react-native-prompt-android', '@powersync/react-native'].includes(
        moduleName,
      )
    ) {
      return {
        type: 'empty',
      };
    }
    const mapping = {
      'react-native': 'react-native-web',
      '@powersync/web': '@powersync/web/dist/index.umd.js',
      kysely: 'kysely/dist/cjs/index.js',
    };
    if (mapping[moduleName]) {
      // eslint-disable-next-line no-console
      console.log('remapping', moduleName);
      return context.resolveRequest(context, mapping[moduleName], platform);
    }
  } else if (['@powersync/web'].includes(moduleName)) {
    return {
      type: 'empty',
    };
  }

  // Ensure you call the default resolver.
  return context.resolveRequest(context, moduleName, platform);
};

the git action above is for production runs, where you copy/move the dev files into the proper dist directory

jasonlewicki avatar Sep 02 '24 21:09 jasonlewicki

hi @jasonlewicki , thank you for your hard work.

ducpt-bili avatar Sep 03 '24 03:09 ducpt-bili

https://releases.powersync.com/announcements/react-native-for-web-support

cahofmeyr avatar Sep 27 '24 17:09 cahofmeyr