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

posthog-react-native seems not to support web #18

Closed
opiation opened this issue Aug 29, 2022 · 8 comments
Closed

posthog-react-native seems not to support web #18

opiation opened this issue Aug 29, 2022 · 8 comments

Comments

@opiation
Copy link

opiation commented Aug 29, 2022

I have an Expo app that also gets used by web browsers but posthog-react-native does not seem to recognize that or set itself up correctly.

As instructed by the Installation section and Configuration section, I've installed the required dependencies and setup PostHog as follows:

$ expo install posthog-react-native expo-file-system expo-application expo-device expo-localization
function MyApp() {
  return <NavigationContainer ... />
    <PostHogProvider apiKey={myKey} autocapture options={{ host: myHost }}>
      <MyNavigationStuffHere />
    </PostHogProvider>
  </NavigationContainer />
}

Nevertheless, I get the following error:

PostHog failed to persist data to storage Error: The method or property expo-file-system.writeAsStringAsync is not available on web, are you sure you've linked all the native dependencies properly?

I was able to reproduce this here: https://snack.expo.dev/@opiation/posthog-expo-web-bug

It seems like the new PostHog client does not handle the case where the platform is Web which is quite common for Expo projects. Is web supposed to be supported or are we expected to create a wrapper the web-only client and expo clients to choose the appropriate one ourselves depending on the platform?

@benjackwhite
Copy link
Collaborator

Yeah I think when running in the "web" mode, all sorts of things won't work. I think we could modify some of the error messages to just be a warn if running in web mode perhaps.

I haven't tried myself but I would assume the library still works, only persistence won't work. Can you confirm that's the case?

@benjackwhite
Copy link
Collaborator

Given just how different the environments are, I think the best option would be to have two different implementations loaded rather than trying to get RN to support a web environment.

I'll create a PR to at least have a clearer warning and example code of how to do this 👍

@opiation
Copy link
Author

opiation commented Sep 9, 2022

Hey @benjackwhite, thanks for the reply!

I haven't tried myself but I would assume the library still works, only persistence won't work. Can you confirm that's the case?

I haven't checked if it's behaving the same in the reproduction but in my own app, the errors show up a lot and eventually cripple the app becoming unresponsive. I haven't had the time to try to isolated and reproduce that specific side-effect but the Expo repro linked above might do it too 🤷.

Given just how different the environments are, I think the best option would be to have two different implementations loaded rather than trying to get RN to support a web environment.

I assumed this would be the outcome though I'd hoped for a fully isomoprhic JS client. I ended up doing something like the following in case it helps anyone 🤷

// @filename Provider.native.tsx

import { PostHogOptions, PostHogProvider } from "posthog-react-native";
import { useMemo } from "react";

import type { ProviderProps } from "./types";

export function Provider(props: ProviderProps) {
  const { apiHost, apiKey, children } = props;

  const options = useMemo(
    (): PostHogOptions =>
      typeof apiHost === "string" ? { host: apiHost } : {},
    [apiHost]
  );

  return (
    <PostHogProvider
      apiKey={typeof apiKey === "string" ? apiKey : undefined}
      autocapture
      options={options}
    >
      {children}
    </PostHogProvider>
  );
}
Provider.displayName = "PostHogNativeProvider"; // For debugging purposes

export { usePostHog } from "posthog-react-native";
// @filename Provider.tsx

import { default as PostHog } from "posthog-js";
import { createContext, useContext, useEffect, useState } from "react";

import type { Client, ProviderProps } from "./types";

const Context = createContext<typeof PostHog | undefined>(undefined);

/**
 * Provide the PostHog client for use by {@link usePostHog}.
 *
 * @note This must be used directly under React Navigation's
 *   `NavigationContainer` to capture its state changes.
 */
export function Provider(props: ProviderProps) {
  const { apiHost, apiKey, children } = props;

  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    if (typeof apiKey !== "string") return;

    PostHog.init(apiKey, {
      api_host: typeof apiHost === "string" ? apiHost : undefined,
      loaded() {
        setInitialized(true);
      },
    });

    return () => PostHog.reset();
  }, [apiHost, apiKey]);

  return (
    <Context.Provider value={initialized ? PostHog : undefined}>
      {children}
    </Context.Provider>
  );
}
Provider.displayName = "PostHogWebProvider"; // For debugging purposes

export function usePostHog(): Client | undefined {
  return useContext(Context);
}
// @filename types.ts

import type { PostHog as PostHogWebClient } from "posthog-js";
import type { PostHog as PostHogNativeClient } from "posthog-react-native";
import type { PropsWithChildren } from "react";

export type Client = PostHogWebClient | PostHogNativeClient;

export type Config = {
  apiHost?: string,
  apiKey?: string
}

export type ProviderProps = PropsWithChildren<Config>;
// @filename index.ts

export { Provider, usePostHog } from "./Provider";
// ^^^ Expo (React Native) chooses the appropriate platform implementation to import here.
export type { Config } from "./types";
export type { Client, EventReporter, ProviderProps } from "./types";

@filipef101
Copy link

Kinda just a +1 but I agree that posthog-react-native should work on web, there is a lot of precedent on the ecosystem and lot's of inspiration to be taken from packages to do just this.
Don't see why not single posthog/posthog-js/posthog-react package could exist, there is no feature gap and probably would ease maintenance. Only diference is supporting both sync and async storages(?)

@filipef101
Copy link

filipef101 commented Jun 13, 2023

Do wonder, if just passing a custom storage would solve @opiation problem
edit: seems so https://snack.expo.dev/sJdMswYz6

@nksen
Copy link

nksen commented Sep 5, 2023

I'm having the same issue, are there plans to support expo web in the posthog-react-native package? I've also noticed that posthog-js (Javascript Web) and the other packages have different configuration options making it challenging to support both for a single expo project.

Do wonder, if just passing a custom storage would solve @opiation problem edit: seems so https://snack.expo.dev/sJdMswYz6

@filipef101 did this method work for enabling autocapture?

@filipef101
Copy link

@filipef101 did this method work for enabling autocapture?

Don't use autocapture

@marandaneto
Copy link
Member

Closing in favor of #140

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants