Add "What I'm enjoying using for mobile app development"
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
This commit is contained in:
parent
0bcc672bbe
commit
be2e215b39
208
content/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md
Normal file
208
content/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md
Normal file
|
@ -0,0 +1,208 @@
|
|||
---
|
||||
title: "What I'm enjoying using for mobile app development"
|
||||
date: 2024-01-02T04:33:55Z
|
||||
draft: false
|
||||
toc: false
|
||||
images:
|
||||
tags:
|
||||
- dev
|
||||
- react
|
||||
- mobile
|
||||
- typescript
|
||||
---
|
||||
|
||||
I like baking bread. Well, most of all I love bread, and baking it myself is
|
||||
more convenient than tracking down a good bakery nearby. I used to bake a lot
|
||||
--and as a hipster I'll tell you that it was before everyone else started doing
|
||||
it at the start of the pandemic-- but I got bored of it some time ago and quit.
|
||||
But I've been eating more bread recently, and decided I could bake something
|
||||
better, and cheaper, than the bread from the grocery store. I'm pretty happy
|
||||
with what I've been baking too, they are all turning out with a good crust and
|
||||
soft insides. What's the inside of the bread called? Anyway, my bread is good
|
||||
but a little bland, so I decided to also get back into sourdough bread to get
|
||||
some nice flavor.
|
||||
|
||||
Sourdough bread is made with sourdough starter, a live culture of yeast and
|
||||
bacteria that needs to be maintained with regular feedings of flour. So before
|
||||
you can bake sourdough bread, you must first prepare your starter and grow it
|
||||
for a few weeks to get its strength up, then keep it alive for as long as you
|
||||
want to keep baking. And before you can prepare a sourdough starter, you must
|
||||
first develop a mobile app.
|
||||
|
||||
Well, of course I could have just set up reminder in my calendar and skip having
|
||||
to develop an actual app. Or just use on of the proprietary ones. But why do the
|
||||
easy thing when you can waste tens --if not hundreds-- of hours developing an
|
||||
app to maybe save a few seconds of your time or to make a point about using open
|
||||
source software? At least it will teach me some stuff along the way.
|
||||
|
||||
## What tech to use?
|
||||
|
||||
But before I could start developing an app, I had to decide what to build it
|
||||
with. My first two requirements: it had to be cross platform, and it had to be
|
||||
able to show scheduled notifications on my phone. My first thought was to use a
|
||||
PWA. PWAs are web apps that can be "installed" on your phone like a regular app,
|
||||
but run entirely on your browser. It's sort of an Electron-lite. That would be
|
||||
great since I already know a lot about web development, alas PWAs can't send
|
||||
scheduled notifications while the app is in the background. That's a pretty
|
||||
vital part of this project so that rules out PWAs. Also I think Safari has some
|
||||
problems with PWAs? So that also would have ruled it out if I somehow worked
|
||||
around the notifications.
|
||||
|
||||
Similar to PWAs, I could have used something like Electron to develop an app
|
||||
using web technologies. In this case it would be an actual app, so I could
|
||||
actually run code in the background and send scheduled notifications. Hurray!
|
||||
Except that I wasn't sure I wanted to do this. My experience with apps developed
|
||||
this way is terrible, and it's often very obvious someone basically put a web
|
||||
browser in kiosk mode. These apps are often slow, the UIs are completely devoid
|
||||
of the native look and feel, and they are often full of weird browserisms like
|
||||
being able to hold and select the text on the page. Maybe this perception is a form of [Survivorship bias](https://en.wikipedia.org/wiki/Survivorship_bias#In_the_military)
|
||||
and there are lots of apps I used developed with these technologies that work great,
|
||||
but I decided to see what else was available first.
|
||||
|
||||
After more digging, I finally narrowed my choices down to 2 options: React
|
||||
Native and Flutter. React Native takes the usual React, and instead of rendering the virtual DOM into a real DOM it renders it
|
||||
to native UI components. React Native is something I used before, with my [Bulgur Cloud](https://bulgur-cloud.github.io) project.
|
||||
While I liked React Native, I actually ended up rewriting Bulgur Cloud --in Next.js-- so I was a little hesitant.
|
||||
Flutter on the other hand uses Dart, and is developed by Google with a focus on cross platform apps.
|
||||
Flutter works by rendering everything to a canvas... which sort of surprised me.
|
||||
My biggest concern with this was performance and accessibility, using native components
|
||||
gives you both out of the box. If you render everything yourself, then it's
|
||||
your responsibility to handle accessibility and optimize rendering.
|
||||
Articles and discussions I came across online reassure me that Flutter is "doing better" at all of these,
|
||||
so hopefully it's not a problem.
|
||||
|
||||
At this point I was still paralyzed by this decision, so I ended up creating a project with both to check out
|
||||
the out of the box example. Which really did not help, they both work and look fine.
|
||||
The code is pretty easy to understand with both. I have concerns with the future of both projects,
|
||||
because React Native feels too under control of Expo and Flutter feels too under control of Google.
|
||||
|
||||
I finally broke my paralysis by just going with React Native. I already know
|
||||
React, I know a ton of stuff about the React ecosystem, I've already used React
|
||||
Native before. Flutter and the Dart language look fine and I'm sure I could
|
||||
learn them, but it's just easier for me to get this project off the ground if I
|
||||
use what I already know. I also remembered that the reason why I rewrote Bulgur
|
||||
Cloud was because React Native for Web is a bad experience, but in this case I
|
||||
don't care about the web so it's not a problem.
|
||||
|
||||
## To Expo, or not to Expo?
|
||||
|
||||
When you start using React Native, the first thing you see is Expo. Look at the
|
||||
official getting started guide for React Native and it immediately recommends
|
||||
you use Expo. Expo then keeps coming up again and again in the docs. It's easy
|
||||
to see why:
|
||||
|
||||
- Expo solves a major getting started hurdle: installing Android Studio or XCode
|
||||
and connecting it to your phone so you can run it. Instead, you install the
|
||||
Expo Go app from your phones app store and scan a QR code to get started
|
||||
immediately.
|
||||
- Expo comes with a lot of built-in packages. If you go with Expo, you can use
|
||||
all these packages *and* you can still use all the regular React Native
|
||||
packages.
|
||||
- Expo doesn't technically lock you into anything, you can "eject" from Expo at
|
||||
any time.
|
||||
|
||||
I decided to use Expo. While I have some concerns that Expo is an
|
||||
investor-backed company and not a community effort, the Expo packages are all
|
||||
open source. Expo Go is open source. And you can still install Android Studio
|
||||
and XCode and build everything yourself.
|
||||
|
||||
## What else?
|
||||
|
||||
Expo comes with a lot out of the box, but there were some packages I wanted to
|
||||
play with and some packages I knew I wanted on top of that. Some of these include:
|
||||
|
||||
### Tamagui
|
||||
|
||||
[Tamagui](https://tamagui.dev) is a UI kit for React Native. I first saw it
|
||||
advertised as a "headless" library meaning that it implements all the
|
||||
functionality but comes with no styles, so you style everything yourself. I
|
||||
later found out that this was not entirely correct though because Tamagui does
|
||||
come with default styles, but lets you opt out of them or customize them.
|
||||
|
||||
I really like Tamagui because it comes as a complete package. It's not just UI
|
||||
components but also animations, CSS shorthands and a token based design system.
|
||||
It also comes with a cool "sub-theme" system that allows you to have variants of
|
||||
your themes, so you don't just have a "dark" theme but you can also have
|
||||
"dark-forest" and "dark-blue" and "dark-whatever" to create different themes for
|
||||
different sections of you app without having to hand-code everything.
|
||||
|
||||
### Expo-Sqlite
|
||||
|
||||
[Expo-sqlite](https://docs.expo.dev/versions/latest/sdk/sqlite/) is an expo package, but it's an optional one.
|
||||
It gives you Sqlite. That's about all. Sqlite is awesome, so why not.
|
||||
There are some other options for storage, some even support additional features like encryption
|
||||
if that's something you need. But I don't think it's crucial if I encrypt
|
||||
my sourdough starter data, so I'd rather take the Sqlite features.
|
||||
|
||||
### nearform/sql
|
||||
|
||||
[@nearform/sql](https://github.com/nearform/sql) is a library for SQL injection
|
||||
prevention. What's cool about it is that you get to write SQL queries with the
|
||||
javascript string interpolation without risking SQL injection. So you can do:
|
||||
|
||||
```js
|
||||
DB.query(SQL`INSERT INTO students(name) VALUES (${name})`);
|
||||
```
|
||||
|
||||
without little [Bobby Tables](https://xkcd.com/327/) ruining your day.
|
||||
|
||||
nearform/sql is not compatible with Expo-sqlite out of the box, but a basic
|
||||
wrapper function can easily get you there. Here it is, I'd
|
||||
publish it on npm but it's so short you might as well just copy and paste it.
|
||||
|
||||
```ts
|
||||
export function sql(strings: any, ...values: any[]): Query {
|
||||
const statement = SQL(strings, ...values);
|
||||
return {
|
||||
sql: statement.text,
|
||||
args: statement.values,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### SWR
|
||||
|
||||
[SWR](https://swr.vercel.app) describes itself as "React Hooks for Data
|
||||
Fetching". My little app is local only and doesn't need to fetch data from
|
||||
anywhere, so why SWR? Well, SWR is great whenever you need to get data from
|
||||
anywhere outside of your apps own state. In my case, I need to get data out of
|
||||
SQLite and into my app, so I use SWR to fetch the data from the database.
|
||||
|
||||
The main use case for me is the caching and deduplication. SWR caches results
|
||||
and won't fetch again if the same hook is called multiple times, so you can use
|
||||
your hooks everywhere without having to worry about the same data being fetched
|
||||
multiple times for no reason. You can also invalidate the cache whenever you
|
||||
want, which will invalidate all users of the hook and fetch the data just once
|
||||
to update everything.
|
||||
|
||||
You need some workarounds to get SWR working in React Native, but [official docs have you covered](https://swr.vercel.app/docs/advanced/react-native.en-US).
|
||||
|
||||
### Formik
|
||||
|
||||
I was hesitant and I dragged my feet the very first time I encountered
|
||||
[Formik](https://formik.org), but after trying it once I actually fell in love
|
||||
with it. It really does everything you need a form to do. The best part to me is
|
||||
that you get to avoid having a million `useState`s in your form, and thanks to
|
||||
the Formik context you can organize your code without drilling values and
|
||||
setters down into components.
|
||||
|
||||
You have to do a bit of work for Formik to work in React Native, but the [official guide tells you what to do](https://formik.org/docs/guides/react-native)
|
||||
so it's an easy change. Wrap that in a custom form input component and you can forget
|
||||
the incompatibility exists at all.
|
||||
|
||||
## Some More Packages
|
||||
|
||||
This is getting really long (for my usual posts), so a few more quick mentions:
|
||||
|
||||
- `date-fns` is the definitive date & time library. It's incredible.
|
||||
- `radash` is like lodash. I'm honestly not fully sure if it's better or worse, but I do keep coming back to it.
|
||||
- `rrule` makes calculating recurring dates easy. You can serialize and deserialize your rrule's which I also appreciate.
|
||||
- `ulidx` is a random ID generator. It's like nanoid, but at the cost of just a few more characters they are ordered by creation date.
|
||||
- `zod` is my favorite schema tool. Never leave home without it.
|
||||
|
||||
## Fin
|
||||
|
||||
I'm about done with the basic functionality I wanted for this app, so I'm hoping
|
||||
to have a version of this up on the Google Play store by the end of the week.
|
||||
|
||||
Oh and I still haven't made that sourdough starter,
|
Loading…
Reference in a new issue