Building Zitrone, part 1

Tech stuff behind Zitrone app

Edit: I moved the app to:

Zitrone is a project that attempts to enhance the meetings and events experience for decentralized organizations. It solves my own frustration, but the idea had a very good reception among organizations I am part of, so there is a hope that it is a useful thing to build. There is a short (first 5 minutes) video where I am pitching it. Further on, I’ll touch product topics very briefly, goal of these articles is to share hurdles I came through and possibly share some knowledge about current technologies you can use to build web apps.

Days Before

So the current version is not the first, I started a few months ago with a building mockup solution on Next.js and Mantine and it was good for presenting the idea to some degree. When I was trying to add backend layer, I decided to start over and move back to the tailwind that I usually prefer. I don’t think there is a valuable lesson in this part, except for “do not use Mantine, if you have poor knowledge of CSS”.

Day 1-4:

So I re-started with an idea that I’ll create a super simple framework to bootstrap web3 projects. And as I take all the projects as learning opportunities, I dipped into Deno and newly announced Fresh framework. I love it. Both are great projects built by very talented people. So I built the “framework” you can see linked below.

It does not do much, but it may help speed up your development as I had to solve some basic issues, e.g declaring Window.ethereum type in order to get ethers.js running. I had to abandon this path very soon unfortunately. A beauty of Fresh framework is that it uses an “interactivity islands” - in React terminology it hydrates only the specific parts of pages. This is awesome for performance, but it makes UX way worse for any applications with shared parts like navigation (especially if the navigation does something, like connecting a wallet in my case), because on every navigation event you re-render the whole page.

Fresh is fast. This fast.
Fresh is fast. This fast.

There is a lesson number one hidden in this experience - performance isn’t everything :) Not if it hurts user experience. If you are building a regular “admin like” application, your users will be more happy with the plain old React app than super optimized static pages (consider preact though).

I have a long time experience with building projects with Next.js, combination of Next.js and Tailwind is my usual choice. With a wonderful Vercel deployment and a lot of sample code around, your developer experience would probably beat anything else.

But I decided to try Remix.run again, because it solves very elegantly the problem I had with Fresh: Remix is the exact opposite in the rendering logic. It renders everything on the server and hydrates it similarly as Next.js to the React application. The difference here is that Remix has a different logic of routing+templating (Next.js actually recently introduced the same idea).

Routing the Remix way
Routing the Remix way

Remix uses nested routes and every “parent” route that has an Outlet component renders its child inside. Translated to the logic of my app, you have the app template that includes (probably) navigation and Outlet. All pages further on the routing tree will therefore include navigation. Then you want a master-detail page (calendar and list of events). Remix lets you repeat the logic with navigation one level below in the routing tree. So you’ll have a template that inherits navigation, add a calendar picker and render it’s own children in another Outlet component. So as a result, as you are clicking on the calendar, only inner content is re-rendered. Calendar itself and navigation never refreshes until you do that with browser reload. For bigger applications, there is another hidden gem: the pages inside the routing tree are not bundled inside the first javascript you send to the client. It is lazy loaded and Remix has some pre-fetching mechanisms that will allow you to tune user experience.

Remix can fetch the data and whole routing paths in advance
Remix can fetch the data and whole routing paths in advance

Remix has routing well explained here, you just need to wrap your head around it (or at least I had to). If you want to try Remix, especially if you are web3 developer, I recommend reading gotchas as a mandatory and you will probably need to patch the Remix to allow some badly written libraries to run. A good start reference is a wonderful wagmi library example:

I’ll dig into details more in the next article, along with shilling Cloudflare Pages, KV and other technologies I use in the project. I promise some code samples as well. Stay tuned and ask me anything here or on Twitter.

Subscribe to Adam Sobotka
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.