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

RFC: Upgrade the app UI to a more modern javascript framework #857

Open
shankari opened this issue Feb 15, 2023 · 33 comments
Open

RFC: Upgrade the app UI to a more modern javascript framework #857

shankari opened this issue Feb 15, 2023 · 33 comments

Comments

@shankari
Copy link
Contributor

shankari commented Feb 15, 2023

Options:

  • Ionic React: maybe can re-use parts of Coach CO2 web app?
  • React Native: everybody uses it, more slick
  • Vue: NREL CIMS UI dev group uses it
  • Flutter: wave of future?

Ideally, we want to be as forward compatible as possible since web frameworks change often and we don't have a large dedicated team to work on forward migrations every two years.

One option that we are seriously considering is to convert all of the main UI components into standard web components. This will allow us to migrate at the top level - e.g. the glue framework - quickly and then slowly migrate the individual web components over time, one every month.

I will also note that one of the requests that comes up periodically is to support a web version (sort of like WhatsApp vs. WhatsApp Web) so that people can explore their trips on a bigger screen. This is very low priority right now but we can keep it in mind for later, especially if we want to support more complex visualizations of the collected data.

@TTalex @paulvantran @asiripanich @larbigharib @ericafenyo in case you have thoughts. We can discuss further at the monthly meeting. We hope to make the switch over the summer.

@asiripanich
Copy link
Member

Yayyy! I don't know too much technical details on these mobile app frameworks. So my only vote is that we choose a framework that is widely used, has a strong adoption rate, and not going to be obsoleted any time soon. This would make hiring someone to work on it less challenging which is unlike the current pairng of Ionic and PhoneGap (?) that we chose.

@shankari
Copy link
Contributor Author

shankari commented Feb 15, 2023

@asiripanich ionic and cordova (phonegap was closed source and is EOL, cordova is open source and is still maintained)
Note also that the two aspects are potentially decoupled - e.g. you could switch the HTML+JS+CSS to react/vue while keeping the native code as cordova, or switch to React Native, which would also need to change the interface layer of the plugins, but then we can't as easily switch to Vue later, for example.

I suspect that the biggest challenge that you are facing is with the ionic1/angularJS UI (other than @ericafenyo nobody has ever contributed native code). AngularJS is also EOL

@JGreenlee
Copy link

JGreenlee commented Feb 21, 2023

To narrow down our choices, I think the next major question is whether we want A) a truly native app, or if we're ok with B) a web solution packaged as a native app.

For (A) we'd be looking at React Native (unless anyone is particularly enthusiastic about Flutter)

  • This probably yields the most performant and most convincingly 'native' app
  • Everything needs to be migrated, and I don't see much potential for re-using existing code. We would be starting from scratch.
  • Although it's not hard to find people with React Native experience, what about in 5 years? I worry that by choosing React Native, we'd be more locked into it than if we chose a web framework. We run the risk another painful migration down the road

For (B), we have countless options.

  • The door is wide open for web frameworks but we're probably looking at React or Vue.

    • I suspect that the migration from AngularJS to Vue would be a little smoother than going to React. If we want to keep our components structured in a similar way as they are now, Vue would allow that. React has its own paradigms we would need to adopt and that could require reorganizing more components
    • Vue is very flexible. If we want to use WebComponents for an easier transition between frameworks, Vue might be slightly preferred. React will work with them, but the interoperability could be a little bit clunkier
    • (I don't necessarily think Vue is the better choice long-term; I just think it is easier to migrate to)
  • We can use a newer version of Ionic, or we can ditch it altogether

    • I don't anticipate that we will re-implement much of the current use for Ionic elements because the newer versions (v4+) seem so different than what we use now (v1)
    • Nonetheless, as we're rebuilding the UI it still might be handy to use a UI library that invokes the look and feel of a mobile app and Ionic 6 is a logical choice
    • If we don't use Ionic, we could consider Tailwind or Bulma to help with CSS
  • We can keep Cordova or we can switch to Capacitor

    • Ionic no longer relies on Cordova to encapsulate native code; it has its own solution called Capacitor. I believe this would give us a significantly better development experience
    • Evidently, Cordova is rarely used today but is still maintained for now. If we are not ready to ditch it yet, I think this is a decision we could postpone

@lgharib
Copy link

lgharib commented Mar 6, 2023

List of criteria Angular (Web Components) VueJS (Web Components) ReactJS (Web Components) React native Dart Flutter
Keep up with the hype No No No Yes Yes
Long term support Yes Yes Yes No No
Portability Yes Yes Yes No No

We want to keep the hype to let the community interested in working on the project. We need to be able to refactor the mobile app every 5 years to stay in the flow. We have less then 10 people so we need to find the balance between a long term support community and enough people to work on the project.

@TTalex
Copy link

TTalex commented Mar 6, 2023

For reference, the 2022 stackoverflow survey, with the most "hype" frameworks https://survey.stackoverflow.co/2022/#section-most-loved-dreaded-and-wanted-web-frameworks-and-technologies

(For our sanity, we should look at the most loved techs, not the most dreaded ones, where we would find both angular.js and cordova 😆 )

@shankari
Copy link
Contributor Author

shankari commented Mar 6, 2023

@TTalex that does seem to argue for React, but React webapp or React Native? Note also that flutter currently seems to be higher on the hype scale than React Native.

@shankari
Copy link
Contributor Author

shankari commented Mar 7, 2023

From the table that @lgharib created, a solution that might check all the boxes might be ReactJS (Web Components) on a React Native base. This would have the following advantages:

  • ReactJS = popular tech
  • React Native = Expo support, widespread plugin support
  • Long term support = use web components for incremental updates
  • Portability = again, web components will help with this

This will also support @TTalex's comment that there are likely to be lots of UI contributions and few native code contributions, so it might be better to keep the UI and the native code separate instead of integrated.

It looks from some light searching on the internet that this might be possible
https://blog.logrocket.com/react-native-webview-a-complete-guide/
or
https://github.com/meliorence/react-native-render-html

Does anybody with more experience with React Native (e.g. @lgharib) have thoughts on the feasibility of this approach?

This will also allow us to use the following migration path:

  • convert UI to reactJS over cordova
  • add plugin wrappers to support react native

= get reactJS over react native

The only high-level con that I can see is that React Native is not part of the Apache ecosystem, so it is not clear what will happen if/when Facebook pulls funding for it.

Or maybe that this is the worst of both possible worlds instead of the best 😄

@shankari
Copy link
Contributor Author

shankari commented Mar 7, 2023

There is also this option https://necolas.github.io/react-native-web/
which supports the opposite use case; react native for web

Final thought, we can create custom react native components as well.
Since we are going to modularize anyway, couldn't we create a react native version of the web components as well?
It seems like the main difference will be in the JSX/rendering; the javascript parts can be the same

And honestly most of the complexity in e-mission/OpenPATH is in the javascript, not in the rendering.

@JGreenlee
Copy link

ReactJS (Web Components) on a React Native base

Interesting idea, but I can't find evidence of anyone who is actually doing this.
We can theoretically place a parent webview in React Native - and have that act as a wrapper for ReactJS. But doesn't that largely defeat the purpose of using RN in the first place? In that case, the only reason we are using it is to interface with native APIs.
This seems to go against the intended usage pattern of RN as a whole, and I worry that it would just make things heavier and more complicated than it needs to be.

I think the main appeal of React Native, to most people, is its native rendering.
If we want that, then ok - RN is our frontrunner.
Else, what do we envy about RN's native plugin support? Is there anything we wouldn't get from Capacitor?

We already have the existing Cordova plugins, which Capacitor would probably be backwards-compatible with. Capacitor also has its own library of native plugins and plugins from the community.
The obvious downside is that Capacitor is less widely used. However it is apparently a bit more "loved" than React Native, among the people who do use it.

@shankari
Copy link
Contributor Author

shankari commented Mar 7, 2023

My 3 cents:

  • I am OK with non-native rendering; we don't really have a lot of audio/video playback type use cases for which that would be a big consideration
  • @lgharib brought up the tooling using Expo as a big reason why people prefer React Native. I haven't evaluated the Capacitor toolchain. I am actually OK with the cordova toolchain, but have not used Expo for comparison
  • what about the option of having two separate JSX - one for RN and one for ReactJS for each component, with the same javascript? Or even autogenerate one from the other? Our HTML is not that complex, a lot of the complexity is in the Javascript. It looks like "React Native Web" essentially does that - takes ReactNative code and automatically converts it into HTML.

@shankari
Copy link
Contributor Author

Since the high-level seems to have equally balanced pros and cons, at NREL, we are actually diving a bit deeper into a few alternatives.

The two alternatives are:

  • starting by leveraging Cozy's work as the base
    • Run Coach CO2 app
    • Look at their components, and compare to our directives
    • Experiment with what it would take to make their reactJS components into react native components
  • start with our directives
    • convert it into a web component
    • convert it into a react native component
    • try and include it in a dummy app
      • React Native app
      • web app using React Native to web platform

@shankari
Copy link
Contributor Author

shankari commented Mar 21, 2023

Wrt approach (1):

  • it looks like CoachCO2 is a reactJS app that basically displays the timeline and some high level analyses; it does not support labeling; which is a core feature of OpenPATH
  • it lookes like the Cozy flagship phone app is a react native app that has an embedded webserver and a webview. The webview can then display reactJS components.
    • this seems like a nice compromise between a full rewrite in react native, or a cordova + reactJS application
    • concretely, it allows us to use the expo/react native toolchain while retaining web components for maximum flexibility
    • as a bonus, this approach is also maintained by an OpenPATH community member so presumably if we choose to move to a more modern framework such as Flutter/Dart, they will also move to a webview using Flutter and we can move with them

The big question that I have is whether they can make calls from the javascript layer to the native layer with this approach (aka re-implement cordova :) @TTalex do you know the answer? @JGreenlee and I will poke around the codebase as well, but presumably somebody at Cozy such as @paultranvan can give us a definitive answer as well.

@JGreenlee
Copy link

Regarding approach (2), I did a little bit of experimentation with WebComponents to see if it would be possible to gradually migrate components in-place. This approach is possible, but there are some caveats.

One of the things I realized is that the version of AngularJS we use (1.5) is not the best for WC interoperability.
I've noticed migration guides will usually ask you to upgrade to 1.7 or 1.8 before anything else. However, I think we are stuck at 1.5 because that's as far as Ionic v1 ever supported.

The good news is that I found a few tools that can make this more seamless. ng-custom-element will allow us to bind angular scope variables to the properties of our custom web components directly in the HTML. Without this, the process would be a huge headache.

If we use WebComponents, I'd also like to use lit, which is a lightweight set of helper functions and a declarative template system, that sits on top of WC to make them a lot more useful. This way, its are features more congruent to AngularJS (and whatever framework we convert to later) and passing data back and forth is not so complicated.

Using those tools, I converted a couple components to test. I made a trip-list-item and a leaflet-map to replace infinite-scroll-list-item and leaflet-ui (an external angular directive that we use to show leaflet maps)

Once I found the right methodology, it worked pretty well. I didn't convert them all the way, but it was just an experiment and a proof of concept. We do have this as an option, and over the next few months we could gradually refactor into WC until we no longer depend on AngularJS and Ionic v1. Then we are free to use WebComponents in whatever framework we choose.

@shankari
Copy link
Contributor Author

shankari commented Mar 22, 2023

The big question that I have is whether they can make calls from the javascript layer to the native layer with this approach (aka re-implement cordova 😄 )

I poked around about this, and it looks like it is possible, but might be a bit tricky.

  1. React Native does have a javascript <-> native bridge (https://reactnative.dev/docs/native-modules-intro).
  2. However, this bridge is only invocable from the javascript engine that react native runs (https://reactnative.dev/docs/javascript-environment)
    1. This does not appear to be tied to the javascript context in the webview
    2. So if our code runs in the webview (as does the Cozy app's code), we cannot make native calls the "standard" way)
  3. The way to communicate to/from the webview is using injectJavascript or onMessage/getMessage (https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md#communicating-between-js-and-native)
    1. Both of these seem like they will work, albeit clunkily.
    2. It does feel like re-inventing cordova, especially since the message passing only supports strings, so we will need to stringify everything to pass it back and forth
  4. There is an existing project that aims to simplify this https://github.com/alinz/react-native-webview-bridge
    i. However, the last update was in 2020
    ii. I am not sure how maintained it is

@TTalex
Copy link

TTalex commented Mar 24, 2023

This kind of bridge is uncharted territory for me. So I can't really help.
I can however confirm that it is not something the coachCO2 is currently doing.

However, the app does have a kind of labelling support, but I believe it's missing the connection to the openpath server. Updated labels are not sent back to the server, they are stored somewhere else.

Screenshot_20230324-120814_Cozy_Cloud

By the way, the app also has the beginnings of an automatic labelling system, it finds similar trips and applies the user input to all of them.

@shankari
Copy link
Contributor Author

shankari commented Mar 24, 2023

@TTalex as you know, we already built an automatic labeling system and it has been in production for a while. We also wrote a paper on it - it is a bit non-trivial to get super-good accuracy. We also just expanded the labeling system to support more complex surveys and changed the display mechanism to be more performant. I would really like to make sure that we are coordinating with Cozy, so that we don't waste our (limited) time implementing the same functionality over and over.

The whole premise of an open source community is that the whole is greater than the sum of the parts (<<tout est plus grand que la somme de ses parties>>) and that we can all contribute towards building a smooth, performant system that people want to use.

@shankari
Copy link
Contributor Author

FYI, AirBnB tried react native and went back to pure native.
https://medium.com/airbnb-engineering/react-native-at-airbnb-f95aa460be1c

Interesting post, but I am not sure if it is very relevant to our situation since it looked like they already had native apps and their concern was that they had to now support three platforms.

@JGreenlee
Copy link

To recap the approach that was put forth today, we can migrate in three steps:

  1. Componentize:AngularJS -> Web Components
  2. Reactify:Web Components -> ReactJS Components
  3. Nativize:ReactJS Interface -> React Native interface

However, I thought about this a little bit afterwards.
One of the reasons we originally considered componentizing with Web Components was to not be tied to any particular framework. But, it seems that if our ultimate target is React Native, this is a moot point. We are going to end up in the React ecosystem anyhow.

It is possible to do a soft migration from AngularJS directly to ReactJS. This seems relatively common. (Babbel, Awesense).
I think that if the goal is to have a React Native app at the end of all this, we do not need to use WebComponents as a stepping stone.
If step (1) can be eliminated altogether, we would likely shorten the timeline of the migration and could focus our efforts on other improvements.

@JGreenlee
Copy link

The second link from above implements its own solution to allow the use of ReactJS components inside AngularJS. Other guides recommend react2angular.
A newer package, react-in-angularjs, seems to further simplify this.

@shankari
Copy link
Contributor Author

As I said during the meeting, the current community membership seems to lead us inexorably towards react.
However, I am still worried that, 5 years from now, we will have to rewrite everything in Dart because everybody is using Flutter. But if we pick a popular framework, I guess there will be some nice packages to help us along 😄

I do want to point out that we can create web components using reactJS now
https://medium.com/javascript-by-doing/how-to-create-a-web-component-in-reactjs-62b71116ea36

That uses a wrapper library to wrap the reactJS component into a webcomponent without changing the react component code.

Now finally the interesting part! Let’s transform our component into a web component! To do this we will use the react-to-webcomponent library, used by many people and super stable.

I would really like to see if there is a way to expose the same component functionality as react native and web component.
When we start making the real changes, I want to spend a couple of days poking around at the tool chain and seeing if that is possible, but not now...

@shankari
Copy link
Contributor Author

shankari commented Mar 29, 2023

I have to try this out, but it looks like react-native-for-web does exactly this "expose the same component functionality as react native and web component."

The only difference is that we had assumed that we would first write web components and then figure out a way to use them in react native.

With react native web, we write everything in react native (so the JSX has View, Image... but then use the framework to use the react native components directly as web components in reactJS.

  • e.g. use Header.js to define a react native component called Header ending with export default Header;
  • use the new web component directly in the app
// add this after other import statements
import Header from './shared/components/Header';

// Modify the JSX in App component
const App = () => {
  return (
    <View styles={styles.screenContainer}>
      <Header />
      <Text style={styles.text}>I'm a React Native component</Text>
    </View>
  );
};

This seems like it would allow us to reuse components for native and web and give us a non-horrendous migration path to other web frameworks in the future (potentially using react-to-webcomponent) if we wanted to.

@JGreenlee
Copy link

🎉 I have good news! (with some caveats)

It looks like, at least from a UI standpoint, the migration is not going to be as hard as we may have thought.

I experimented with several approaches that would allow a soft migration to ReactJS and React Native.
Surprisingly, I found a solution that allows us to migrate to React Native by only rewriting once. I didn't actually think this would be possible, but it is!

See the following:

Embedded here is the default "Hello world", or starter page, for React Native Web.

This was the first thing I did to test the possibility of rendering React Native components inside AngularJS.
As shown, I was able to append this starter page to the Dashboard screen. It is exposed to AngularJS as <react-hello> and then simply inserted at the end of main-metrics.html.

It appeared at the bottom of the Dashboard scroll view, just as you would expect.

This works because React Native Web compiles React Native components to be rendered as ReactJS components (this happens before runtime).
Then, at runtime, react2angular exposes the ReactJS component as an AngularJS component.

This would allow us to migrate with only 1 rewrite (which is promising!), but first I wanted to make sure we could actually pass in props from AngularJS.

You would probably not guess from looking, but the button showing "Add Activity" is rendered using React Native Web, while the "Mode" and "Purpose" remain rendered as normal HTML from AngularJS.

The button is defined as a React Native component as follows:

const DiaryButton = ({ text }) => {
  return (
    <Button mode="elevated"
      buttonColor="white"
      style={buttonStyles.button}
      contentStyle={buttonStyles.buttonContent}>
      {text}
    </Button>
  );
};
DiaryButton.propTypes = {
  text: string
}
// styles below ...
...

The text ("Add Activity") is passed in as a prop from the parent, which is an AngularJS directive. In the parent, it was a scope variable.

<diary-button text="displayLabel"></diary-button>

Numbers, arrays, and objects can also be passed, and reactivity is preserved. This means we have sufficient interoperability between frameworks!

Some things to note:

  • I haven't used React Native before, but I found the styling options rather limiting compared to CSS.
    • If you aren't familiar, React Native defines stylesheets in JS, without using selectors. Its property names loosely follow CSS standards, but there are many features missing (including media queries, CSS grid, pseudo-classes).
    • To get a truly unified look between platforms, I found that it took an annoying amount of work.
      • For example, to achieve a simple shadow, Android uses a property called elevation. On the other hand, iOS uses four different shadow properties: (shadowColor, shadowOffset, shadowOpacity, shadowRadius). React Native on its own doesn't abstract this away, so it would be a pain to write and maintain anywhere we want a shadow.
    • Thus, for the demo above I experimented with React Native Paper. It is a lot easier to get a unified look this way. I wouldn't normally suggest a third-party UI library, but in this case I think it is warranted.
      • There are many other options, but React Native Paper seemed like a safe choice with a thriving community. It complies with Google's Material Design so I think as long as RN lives, there will be a strong faction of people who will keep RN Paper alive.
  • In React Native, we can optionally use TypeScript for whichever components we want.
    • I think this project is large enough to warrant it, so I strongly suggest we use it as much as we can. Overall, it will just reduce frustration and future bugs.
    • If we don't want to use TypeScript everywhere, we don't have to. TS components will interop with JS components just fine.

The complications

AngularJS to React Native is a significant jump, and I somewhat doubt that anyone has done this exact process before.
There are plenty of AngularJS -> ReactJS migration guides, and while it is largely the same in terms of actually rewriting code, this is a bit of uncharted territory for how to organize the project and its dependencies. Basically we are trying to bridge a gap of 10 years in Javascript evolution - it's messy.
It took me several hours of fiddling around just to find the right combination of tools, with compatible versioning and dependency configuration. There are so many moving parts here, given that we will literally have 2 frameworks existing simultaneously in the same application. Also while having old dependencies from a legacy package manager (bower), and trying to use modern ES modules. It is the perfect storm of old and new Javascript!

The good news is that 1) after wrangling with it for hours, I now understand things much clearer, so maybe the initial headache is out of the way and 2) we can break the process into steps so it's not all too much all at once. I think we can prevent a lot of frustration by just having a solid plan for the prep work that we will do before we introduce React.

Suggested prep / Refactoring before migration

  • We need to bump our version of AngularJS just a little bit. We currently use v1.5.3 because that's what the last Ionic 1.x version bundles with. We just barely miss out on the component-based features that allow for interoperability with React. I accomplished the above result using v1.6.7.
  • React, and modern component-based architecture in general, has some common paradigms we should adopt. AngularJS with its two-way binding is very permissive in how data flows and this is not considered best practice today. We should adopt one-way binding and set clearer boundaries between components.
  • We should get rid of Bower sooner rather than later. We should be able to move all packages over to NPM. This will allow us to use Webpack for all dependencies and retain our sanity when it comes time to add React.
    • Doing this before introducing React would eliminate most the frustrations I had while trying to set up the demo.
    • There's a nice guide we can use, which is referenced by a lot of AngularJS migration guides (Bye, Bye, Bower!)

Overall suggested plan

Given these findings, I created a roadmap of what specific steps I think will be necessary for this plan to work.
This is obviously subject to change, but it should demonstrate my general vision of how we might tackle the migration.

diagram-export-4_3_2023, 2_21_20 PM

@TTalex
Copy link

TTalex commented Apr 4, 2023

Good job @JGreenlee ! Very interesting read.

That looks like a sound plan to me :)

@shankari
Copy link
Contributor Author

shankari commented Apr 4, 2023

Agreed. Great summary, @JGreenlee! I am glad that we were able to fold in React Native for Web so that we have both portability and a modern toolchain.

I can see that this is a lot of work, but it honestly seems fairly doable once we have the initial templates set up.
wrt "copy over our source files with git history", I think it is critical to retain git history, especially for a large and complex project with many moving parts.

It seems like just using git mv so that git log --follow will work correctly should be fine.
Alternatively, if that doesn't work properly, we can rename the current phone repo and archive it, create a new repo, and then just add a note to check history on the old repo if you get to the end of the new repo.

@lgharib @AlirezaRa94 @ericafenyo any thoughts on this migration plan?

@shankari
Copy link
Contributor Author

shankari commented Apr 4, 2023

One more task for prep/refactor in AngularJS is to merge the master and master_for_platform branches.
Which means that we need to resolve #850

Are we the only ones using a multi-tenant architecture?

  • I think UNSW (@asiripanich) will want to use a multi-tenant architecture if we can simplify onboarding
  • Transway (@ericafenyo) will use a native UI anyway
  • @lgharib will you want to have multiple versions of the app for multiple studies?

@shankari
Copy link
Contributor Author

@JGreenlee another consideration is the enekto survey code.
We use the enketo survey even in the MULTILABEL case (for the demographic survey, and potentially to push targeted surveys to users)
but enketo is going to remain javascript and is not going to become react native.

Some potential options for dealing with the surveys are:

  • find an open-source react native survey library + builder that we can integrate
    • ideally, this would also be ODK-compatible so we can be part of that other community as well
  • use the webview to display the surveys only; we can pass in the prefilled survey and get back the response as we currently do

@JGreenlee
Copy link

If there's a react native alternative that'd be great but I don't know of one. I was envisioning that we would just keep Enketo and wrap the surveys in a webview.

If we do keep Enketo I think we should try to get even with enketo-core so that we can benefit from upstream improvements.

@JGreenlee
Copy link

Moment is another library we might consider swapping out during the rewrite.

Moment is not deprecated, but they consider it a legacy project and recommend modern alternatives.
Luxon is the successor to Moment, which is more lightweight because it utilizes the Intl standard that is now part of modern JS.

I thought we might be able to use no library and only Intl, but it looks a little too barebones. we need some library to easily handle timezone offsets.

@JGreenlee
Copy link

There are at least 2 web-based libraries that we want to keep using, but use non-native (HTML) rendering: Leaflet and Enketo.

@shankari Before I go much further, I wanted to discuss how we plan to do this, because I think it's going to get messy. We can't put raw HTML in React Native Web and I thought it would be simple enough to just wrap these in a WebView. Although there is a way to do this, it's somewhat absurd: React Native Web WebView.

I actually burnt several hours trying to wrap a Leaflet map in React Native Web WebView. Eventually I realized that it is possible; just not on the iOS Simulator in the devapp / phonegap (<iframe>s simply don't show up. I searched this issue extensively and no one seems to know why or care).

So yes, wrapping things in WebViews is technically an option, but I think this would be a huge pain for development purposes - until we are able to officially ditch Cordova and move to Expo (but I think that will be some time from now)

For maps, we do have the alternate option to use react-native-maps/react-native-web-maps - which would probably give a smoother/sleeker result in the end anyway - but I think we'd have to use Google Maps, and that requires using API keys.
-- At the scale that OpenPATH is at, I don't think it would actually cost anything, but it's still annoying to deal with
-- Extra work that I'd like to avoid if possible

For surveys, I haven't really seen any options for ODK-compliant forms in the RN ecosystem.
So I don't think we can get away from Enketo, and I think this necessitates that at least part of the app will be rendered in a WebView anyway..

Not really sure where we go from here. Whatever we do, I think it's going to be a "lesser of two evils" kind of decision.

@shankari
Copy link
Contributor Author

shankari commented May 25, 2023

So for enketo, I think that a webview would be fine, since we always launch it as a full-screen view anyway. Either in a popup or in the ion-view directly.

Leaflet is trickier and I'd forgotten about it because I got so used to using it everywhere. I do think we want to avoid Google Maps because (i) we want to avoid changing our implementation and (ii) as an open source project, it is better to use open source components and not introduce any requirements for closed source APIs if possible.

Having said all that, I am a bit confused.

  1. As you said, we will be migrating to Expo/React Native plugins later, so we will initially be running react components (to be precise, React Native components compiled into reactJS) in a webview to be compatible with the cordova plugins. So there will be a DOM anyway right? So why can't we continue to use leaflet?
  2. why do we need to use iframes? why can't we render the leaflet map directly into the webview? I'd haven't played with this code, so I don't understand why.
  3. Assuming raw leaflet doesn't work for some reason (since presumably you have already tried it), it looks like react-native-web-map is a thin native wrapper over react-google-maps.
    • there is a react-leaflet that seems to be similar to react-google-maps in terms of a react wrapper around leaflet that doesn't use any iframes. It seems like we have two choices
      • it seems like we can use react-leaflet in angular (using react2angular) directly to show the maps. This will work until we have removed all the angular stuff and need to switch to full react native (including Expo/React native plugins). And at that point, I guess we would use native maps (no API key needed) anyway?
      • if react-leaflet doesn't work directly for some reason, it seems like we can write a react native wrapper modeled on react-native-web-maps (which is not that complicated - 4 source files) to create react-native-web-leaflet. It looks like react-native-web-maps may be abandoned (see issue 71 in their repo), so we could contribute it to the community as well.

But first, I want to see if react-leaflet can work in directly with react2angular as a stopgap until we switch to Expo and true react native.

@shankari
Copy link
Contributor Author

shankari commented May 25, 2023

correction: wrt

And at that point, I guess we would use native maps (no API key needed) anyway?

It's been a while since I've written a native UI (I think we moved to hybrid ~ 2015), and things have certainly changed since then. It looks like an API key is now required even just to show a google map in Android. This is not a requirement of the plugin but of the underlying google library - e.g.
https://developers.google.com/maps/documentation/android-sdk/map#to_add_a_map

Ah but then we could just use
https://github.com/pavel-corsaghin/react-native-leaflet
which appears to have already handled creating a webview to display leaflet maps

I am not 100% sure if we can have multiple of those components on the screen at the same time (as we would need for the label screen); we would need to experiment with it to find out.

@JGreenlee
Copy link

Good news! As it turns out, React Native Web is more flexible than I thought - sorry for raising false alarm.

I didn't think that putting raw HTML inside React Native Web was going to work, but it does as long it's ultimately being rendered as HTML. This wouldn't work with native rendering directly, but we won't need to do that until later. As long as we're operating over Cordova, we can use HTML alongside (and within) React Native Web components.
-- Of course, we should still put as much of it in React Native Web as we can, so that it's easier to go truly native down the road.

I got this working with Leaflet, so we can just work with that for now. The same should work for Enketo. When it comes time to switch to Expo, we will need to wrap these in WebViews, but at that point we won't have to worry about compatibility issues with Cordova and Phonegap.

@JGreenlee
Copy link

--For the record:--

why do we need to use iframes? why can't we render the leaflet map directly into the webview?

This is how react-native-web-webview works to support different platforms. On native rendering, it puts the content in an Android WebView or iOS WebView. With web rendering, it places the content inside an <iframe>.
Ideally this would just work, and we wouldn't have to do anything extra when we transition. But the <iframe>s didn't show up, so we won't use them for now.

I want to see if react-leaflet can work in directly with react2angular as a stopgap

I am not sure if we can use 'pure' ReactJS libraries right now. It might work, but only temporarily. We should try to implement as much as possible with React Native Web libraries, that way it's guaranteed to work with Expo web later.

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

No branches or pull requests

5 participants