Solito – React Native and Next.js unified
solito.dev
solito.dev
Navigation is the hardest piece of sharing code across platforms. Web has plain URLs for navigation state, whereas apps have complex sets of nested navigation patterns (stacks, tabs, modals, drawers). By combining the approaches into a single mental model and API, devs can build for Web and Mobile with ease. This is touched on at length in the "Methodology" and "Gradual Adoption" sections of the Solito docs.
The gap between web devs and native devs is shrinking. This stack enables you to ship native apps and websites with a single codebase. I'm the only frontend engineer at our startup, and I was able to do just that as we scaled to thousands of users (see https://beatgig.com). My goal with Solito is to 1) provide the code to let others do it, and 2) perhaps more importantly, document clear patterns to deal with platform differences.
I built our entire product from scratch for iOS, Android and Web. Rather than rushing to hire a team to do each thing, I felt that if I built the right abstraction layers, it could all be done by one person.
It can be a lonely road when you’re the only one, but Solito helps you feel a little less solo
The benefit over using RN for this is being able to use libraries like Tailwind on all platforms and having a true single codebase.
That said, I'm sure there are good arguments for Capacitor!
Also check out tailwind-rn for using Tailwind classes in React Native. The latest version even supports Tailwind 3 JIT compilation so you're bundling minimal TW class adapters.
The README says: "SSR is currently disabled for the Next.js app as the app will be fully client-side rendered for iOS and Android. This is a limitation we are working to address in a future update."
I guess it's because CapacitorJS pre-bundles the entire PWA for the App Stores:
"Of course, you also could load the app completely remotely by changing the server.url configuration for Capacitor to point to your SSR'ed Next.js app, but that has other challenges such as App Store approval if the app doesn't check the boxes for Apple to qualify it as an app that has enough native integration (at that point this is on you, not Capacitor)"
https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-st...
But I don't understand why SSR would be disabled for the NextJS PWA on the web?
Maybe the creator Max Lynch aka. @mlynch aka. @yesimahuman could provide some insight here.
Currently, I like to have the API and web pages (signup, marketing, policies, etc.) made with Remix.
Then, the cross-platform app (native & web) can be made with React Native / React Native Web using React Navigation as the router.
I can certainly see being able to combine those two into one as a plus, but React Router / Next Router and React Navigation conflict. React Navigation is needed for a nice app experience.
That said, I opened this discussion on the Remix repo a while ago: https://github.com/remix-run/remix/discussions/1578
If you're using shared screens outside of Remix marketing pages, though, then I imagine a solito/remix could exist to bring the same features the Next integration has to a Remix one.
This is why I currently separate web pages & API from the cross-platform native/web app.
Adapting Remix to React Navigation would be the solution if possible.
But this is more about navigation if I see this correct? So more in the direction of react-router
The hardest part of sharing code between apps and websites, however, is the navigation code. Websites have flat navigation. You have one page mounted at a time. When you navigate to another page, the original one unmounts and a new one renders.
Native navigation has a different paradigm altogether. Rather than use simple URLs to account for most of the navigation state, native apps have complex tabs, stacks, and more. When you change tabs on Spotify, you expect the previous tab to maintain its state, scroll position, nested screen, etc.
Given all of these considerations, it's previously considered impossible to use the same code for apps and websites, even if they're all written with React.
Solito solves the navigation problem by offering a unified API across Web and Native. This lets you write your code one time with React Native, and use it on both iOS, Android and Web.
From the docs:
> Solito treats URLs as your source of truth. Your Next.js app and React Native app don't communicate at all. They live in total isolation. Solito works by doing this: give me a URL, I'll detect what platform you're using, and then I'll figure out how to navigate to the screen for that URL.
The problem has never been SSR but the divergent navigation patterns/state between web and mobile, for which it's not easy to build a shared abstraction.
Looks like you feel clickbaited because you are looking at this on the surface
I don't use react-navigation, so I won't be able to use the library. I actually arrived at a very similar setup of a Link component that is a different implementation per platform. I think it will become even more similar after learning from this code and documentation.
There are also experiments in the works to make React Navigation lazy load code with suspense on the Native side by bringing Webpack to Native: https://github.com/EvanBacon/expo-auto-navigation-webpack
Another added bonus of this approach is that it will have a pages/ folder API like Next.js.
I don't see why Solito won't be able to support these use-cases as they arise.
However, as much as it's convenient to get up and running (with bundle splitting), the file-system based router is in my opinion probably the weakest part of Next.js. It would be top priority on my list of things to go. The main issue is it's fundamentally not type safe.
For example, Solito's useParams() is fragile because refactoring can easily cause param substitution to come out of sync with param consumption (in another component). My most recent solution (not in Next.js) for this is:
const {partnerId} = useRouteParams(routes.tails.partner);
That's 100% type-checked. Creating a URL for that route is also type checked and done like: routes.tails.partner({partnerId: "blah"});
I'd really like to see routing libraries adopt type safe practices.EDIT: I suppose the file-system based routing could be kept if you pair it with code generation. Maybe that's an option?
Maybe I'll wait another few years for it to settle down before looking again...
lmao!!!!! foreal man
What was missing though?
It seems like Solito could have prevented a significant amount of work, reduced code duplication, and let us release our mobile app a lot sooner.
If Solito does what it says well and porting to it wouldn’t be difficult, I wouldn’t be surprised if we made the move. This is a very compelling pitch to a team with a next.JS app and a React native app sharing the same business logic.
None of that is needed on a native platform.
Rookie question from a Web dev here - what functionality does react native provide that isn't available on Web?
1) No HTML elements. React Native provides some low level elements for views, text, etc. The rest depends on the platforms and packages you have installed. 2) You can't use CSS, so you use something that is similar to CSS (including flex box), but isn't cascading. 3) Since ultimately React Native results in native views being rendered, you can also use some of the native view debugging that exists. 4) Changes made in React are batched up and sent to the native side of things, which results in some performance characteristics you don't see on the web or native mobile. There is also a difference between iOS and Android performance. You feel this a lot more on mobile than on the web.
there are many other reasons, I touch on all of them in my Next.js + React Native talk at Next.js Conf: https://www.youtube.com/watch?v=0lnbdRweJtA
I built https://beatgig.com with React Native and Next.js as the only front-end engineer and designer, and our iOS app and website share 99% of code across hundreds of screens.
I have personally drunken the kool-aid to the extend that I'd rather develop a pure web project with react-native-web because I like the choices/constraints it introduces but I don't think that's the case for most people.