I'm building a task management tool called Week. There are few reasons I decided to create yet another todo application. First of all, I love programming and I love to create new things. I do it every day at my job, but there is a downside: at your job you have to do things other people tell you to do, you're limited in your choices. Of course, most often you can decide which library or framework you can choose to accomplish your objective, but it ends there. I wanted to have full control over tools, design and features of my app. Secondly, I haven't found an ideal todo app for my needs and what could be more fun then creating one myself?
Let me tell you a little about the app. Week is a combination of calendar and classical todo application. On the main screen you see a list of unscheduled tasks and a big calendar. You can drag and drop tasks from backlog to the calendar to plan them. Each task can belong to a project and each project has a color. It helps you to see which projects take most of your time. For that reason the app has a statistics tab where analysing distribution of your time becomes even easier.
Now when you know the gist of the application, let's proceed to tech information.
For the structure of my application I decided to go with monorepo instead of polyrepo. It means that I have a single git repository where two projects are stored: client and server. Later I will add React Native app to that list and probably will move some common code from client folder. Monorepo allows me to manage my dependencies easier: I can start all my projects with a single docker-compose command (more on that later), I can make a single merge request with changes in both of my projects, later I will be able to import things from my common folder into my frontend and mobile folders without publishing it.
There are tools for easier work with monorepos such as lerna and nx, but I don't need them yet.
I use docker both for development and for production. It allows me to easily start all of my dependencies like Redis, Postgres and nginx in one command without even installing any of this on my system. I don't have to worry about different versions for different projects and stuff like that. I have docker images for my client and server too. Important thing that I didn't know at the beginning of development is a multistage build. It helps to make images smaller which is always good.
There are downsides of using docker in development. For example, when I install some new library, I have to connect to container and install this library inside of this container as well. You can't just mount node_modules directory from your host machine because some dependencies are installed differently on different operating systems.
On production I use docker swarm instead of docker-compose. My app isn't big enough to use more than one machine, but using docker swarm is a step in that direction. For sensitive information such as Redis secret I use docker secrets which are not available for docker-compose.
I use github workflows to build my docker images every time I push a tag which starts with
server-release . I used to build both images on single tag but this workflow isn't ideal - in this case you have to build server image even if it didn't change. Now I'm able to release my images separately from each other. One more thing I can recommend is to add stale-remover action for github. It will remove old images after creating new ones which can help to keep list of images clean and small.
I use React, react-router and styled-components as my main libraries of choice. These are purely a matter of preference, but I will share a thought or two about my decisions. I took React because this is an instrument I know. I could have taken something new and learn it along the way, but when you want to get things done you should take something you know well. I've chosen styled-components because it makes so much easier to change styles every time you change state. It comes with a cost and I know that, but I prefer to stay with CSS-in-JS anyway. I'm considering migration from styled-components to linaria (linaria don't build styles in runtime which makes this library faster than styled-components), but it is a low priority task and I think that linaria isn't stable enough yet.
I have tried a few bundlers, but I ended up using webpack anyway. I tried vite and it worked like a charm in development mode, but in production I had some problem no one could help me with. I also tried snowpack (no luck here either) and parcel 2. Parcel worked for some time, but one day, all of a sudden it stoped starting in docker so I had to return to old good webpack. I came to a conclusion that it might seem fun to try some libraries and to be on the bleeding edge, but when you need to get a result it would be better to use something mature and stable.
Instead of using some open-source calendar I decided to write my own, because it's quite an interesting task and I wanted to have full control over features and look of the library. It's probably not the best decision I've ever made because third party libraries usually well tested and cover 95% cases. The most challenging things were events layout (you have to take into account overlapping events) and drag-and-drop logic. For implementing drag and drop behaviour I took react-dnd library. If I made choice now I would try new library called dnd-kit because it looks promising.
I took Express as my server library without any research and looks like it was a mistake. I haven't had any problems with it yet, but I might face them in the future. For more information check out this post. I would pick fastify if I made choice now.
I didn't necessarily need GraphQL in my application because I don't have a lot of nested data, but I decided to choose it anyway. It's just such a pleasant experience to work with Apollo GraphQL so I couldn't resist. I use library called graphql-codegen for generating types and hooks from my backend schema. It makes development process even more enjoyable because it's almost impossible to make a mistake when all of your code is typed. I commit my generated file because I deploy server and client simultaneously and therefore I can't generate it on the fly.
That's all I wanted to share with you today. If you have any questions I'm ready to answer them. I'm also planning to share some other details about the process of developing an app so stay tuned.