The Building of Campanula
Campanula is a Pomodoro timer application I built over the timespan of a few months starting in late January 2022. The idea of creating a new and better Pomodoro timer app came to me while I was trying to find a competent solution that could accomplish the goal of being decent at its purported job.
What is the Pomodoro technique?
For the uninitiated, the Pomodoro (lit. tomato in Italian) technique is a task management technique created by author Francesco Cirillo in the 1980s. The aim of the technique is to provide a work-break balance by separating a task into intervals— each interval containing a work period and a break period. After a set amount of those periods, one would be rewarded with an enlengthened break; then, the cycle would start over again.
The technique has seen widespread popularity for all types of people doing all types of tasks in all types of places. Most commonly, the Pomodoro technique is used by people trying to complete a task assigned to them at work or to study/do a school assignment.
Despite the immense amount of popularity it has received, (at least from my research and in my opinion) there don’t seem to be many Pomodoro apps that cover all the bases: being simplistic enough to have a decent user interface that isn’t crowded, having enough features to be useful to the average user, and being at a reasonable price (generally free).
A lot of these apps either have a less-than-desirable user interface, a very basic set of features, or a subscription model (or, better yet, a combination of the above). I attempted to design Campanula to be none of the above.
Designing Campanula
I didn’t really have too much of an idea of what I wanted Campanula to be like when I first had the idea of creating it. I knew what the concept would be like and a strange idea of what the design language of the site would be— “futuristic” and techy, which didn’t really come to fruition (except for remants of it, like the giant spinning tomato)— but aside from that, I was open to pretty much anything.
I built the large majority of the UI before implementing any of the logic, unlike every project I had made prior to then. Maybe it is just the amount that I’d learned with the prior experience I’d gained, but I feel that Campanula was a large step over my previous projects in terms of looks, functionality, and codebase cleanliness— possibly due to my UI-first approach at building it.
For some of my previous projects, I would build out what I thought the UI should look like in PowerPoint (yes, I know), but since I wasn’t sure what it’d look like, I didn’t really make a mockup before diving straight into making the UI. I kept building on a vision I had in my head and kept modifying it slightly until I was satisfied. Eventually, I got the modern-ish rectangular design that the site has now with the hexa-color palette, thick borders, and funny-looking vector people.
Developing Campanula
Campanula, currently, is only a web application that runs in the browser. I tried to avoid making it platform-dependent to make it accessible to as many people as possible. However, this results in a slightly less-than-optimal experience on certain devices where using the native elements would be better. Of the two, though, I’d rather have that than it being platform-dependent.
As you may expect, this section about the development of Campanula includes a lot of technical jargon, so brace yourself for the incoming nerdiness!
The nerdy stuff
The stack
Campanula is built using the MERN stack, with the main driver being React, a JavaScript frontend web framework that has become very popular among web developers in recent years.
Compared to vanilla JavaScript, React offers a large advantage in multiple departments— most prominently in the way that it handles splitting up the UI. The UI is broken down into developer-created components, which represent parts of the UI, allowing code to be reusable, clean, and maintainable.
The way that vanilla JavaScript handles DOM manipulation is unintuitive in my opinion— running querySelector
every time you want to change an element instead of declaratively writing it out in JSX and keeping state centralized in the component rather than in the running script is less than optimal in terms of intuivity.
create-react-app
is one of the most popular tools used when working with no-frills React. It creates a barebones project with a few extra features that allow you to get started building a webapp pretty fast. However, there are a few missing features that developers generally want, like routing, static site generation, a dynamic head
, and more that you can get by using a metaframework like Gatsby or Next.js. I had to use extra libraries like React Router and React Helmet for routing and dynamic head
functionalities, respectively.
For the backend, Campanula uses Express— a minimal framework that is used commonly in tandem with React (or most other projects that need a backend framework also using a frontend JS framework and Node.js) and has a plethora of features useful for those developing a web application. For Campanula, I didn’t use it extensively, only using it to connect with my database and do a little bit of server-side routing.
The M part of the MERN is the popular NoSQL database management system MongoDB. Storing the codes that correlate with each timer was done with Mongo in a free-tier MongoDB Atlas instance. I chose Mongo because it is popular, offers an easy way to connect a database in an instance with a Node app and I believe that a document model fits my use case more than a traditional relational database solution like MySQL (also, I don’t know how to write SQL 😊).
Additionally, the entire logic portion of the codebase was written using TypeScript, a superset of JavaScript that adds a static typing system, making for more predictable code when running and a better debugging experience.
Additional stuff
In addition to the stack mentioned above, I made use of a few other libraries.
react-router
As mentioned before, I had to use React Router for all my routing needs. React Router is the most popular library for adding client and server-side routing to React applications. Unlike traditional webpages, routing in most front-end libraries today doesn’t require that the page completely reload. Only the elements in the page that are supposed to change (generally grouped into components) will change when the state of the page or a component changes. Because not everything is getting reloaded, this allows for the application to be efficient and performant, while also looking nice as there isn’t a white screen while the user is navigating to another page.
These apps are called single-page applications, or SPAs, due to the fact that they are technically a single page that only changes components within the page to give the effect of navigating to a different web page. For certain implementations, this comes with drawbacks— most noticeably the impact that is has on an application’s SEO. Because not all pages have a unique URL (unless you are deliberately making it so), search engines cannot really index pages other than the homepage.
However, if the library being used uses the web browser’s history/location API (Next.js and React Router both do this), rather than hashtag URL fragments or plain not changing the URL at all, search engines will see different URLs as different pages and the crawler should be able to see your pages.
Also however, this does not mean that your SPA pages will necessarily rank as high as they would if they were traditional pages. Because content is delivered via JavaScript and isn’t static HTML, the crawler doesn’t know what to index ahead of time. This problem can, however, be fixed by statically rendering the JavaScript when the application is building, which is one of the approaches that Next.js takes out of the box. React Router also has support for this with a third-party library like react-snapshot
or react-snap
.
React Router can be installed via npm
.
react-helmet
React Helmet is a very popular library used for managing the document head for pages in your web app. With many web pages in your app, managing the document head for each page can get cumbersome and lead to unnecesary boilerplate between files. Enter React Helmet: one reusable <Helmet>
component between multiple pages where you can dynamically set the value of head tags.
React Helmet is a pretty simple library that has very little learning curve and proves useful for pretty much any React web application. All you need to do is import the Helmet
component and then wrapping all your document head tags in a Helmet
component. On child pages, a Helmet
tag can be added anywhere to change the head
of the respective page. This allows dynamically setting the title and meta tags of a page very easy. Any children of Helmet
components in child pages will override duplicate parent tags.
Currently, per the v6 documentation, React Helmet supports all of the valid HTML5 head tags (title
, base
, meta
, link
, script
, noscript
, style
), attributes for body
, html
, and title
, server-side rendering, and callbacks.
React Helmet can be installed via npm
.
three.js
The funny-looking, spinning, low-poly tomato that greets you on every load of the Campanula website was created using Three.js, the most popular JS library for creating 3-dimensional graphics on web pages. Three.js can be used for both simple 3D objects (like the aforementioned tomato) and complex scenes, as it has a wide range of features for all calibers of web app.
Three.js itself is a library for use in vanilla JS, so I used react-three-fiber
instead of the regular Three.js to work with my React project.
Generally, simple and medium-complexity Three.js scenes will run decently well on modern computers, but higher-caliber scenes will generally be choppy, slow, and/or long to load on some computers. Additionally, complex 3D objects can be pretty large in file size, so some sites that use Three.js heavily or irresponsibly can end up sending hundreds of megabytes of data through hundreds of HTTP requests. Often, on lower-end devices or slower connections, these sites are unusable. While using Three can make your site look cool and add novelty to it, make sure to be responsible while doing so!
Three.js can be installed via npm
. React Three Fiber can, as well.
Final thoughts
In my opinion, Campanula was a large step up from the projects I’d previously created (although, of course, with much room for improvement). I am proud to have created something that can reasonably be used by the everyday person that beats at least some of the competitors in the space. Learning and applying the skills required to make Campanula was also great for me and will hopefully help me sometime along the line.
Campanula is available at campanula.literaiiy.me.
Special thanks to Ralph Hunter, Kelly Sikkema, Marvin Meyer, and Green Chameleon for their stock photography.