As you may know, Paper is the name of my new blog platform. I built it because I want flexibility in customizing my blog capability, with great experience when writing a post. Being flexible doesn't mean that Paper will have all features that other blog platform has. It's never going to be a full blown CMS that could create an e-commerce website.
Instead, I will focus on what is important on writing a blog. I'll only add features that is relevant on writing blog, especially technical post, because this is what I mostly write.
This post is a high level overview over what tech stack, languages, and libraries I use to build Paper. This is by no mean the best tools that you can use. Most of them are just the ones I'm comfortable with. The rest are the easiest one to grasp and implement.
Paper was built as three different micro services. The editor dashboard, the API endpoint, and the blog frontend. All those three services are nodejs app. Each of them is deployed to different host and communicate using http(s) request.
I didn't have any previous experience in deploying microservice before. Thanks to this post, I tried now and it was awesome. They offer immutable deployment and DNS aliasing for switching between deploys. I'll talk about
now more in another post.
So, how do I manage dependencies between services?
Yes, Paper repository is a monorepo. I use Lerna for bootstrapping and managing npm scripts across packages. In my local machine I just run
npm start and those 3 services will run in different port.
I use code name for all services for easier issue tracking and deployment. Paper itself is actually a internal code name for the editor dashboard. Pen is the API endpoint, and Lens is the blog frontend.
Let's take a look at each services.
The dashboard is a single page app that is built using awesome create-react-app tools from Facebook. If you're just starting to learn React, I suggest you use this.
For the core editor, I use Draft.js. Draft provide clean abstraction over ContentEditable that use core concept of React. Instead of storing the state in the DOM, Draft use Immutable record and re-render the component inside ContentEditable if the state changes.
I use React Router for client side routing. I really like their new API because it's composable. It's still in beta at this time of writing, but it's usable and I haven't noticed any bug.
I don't use redux because at the moment using setState is enough.
For security reason, the dashboard is protected behind a login screen. I use auth0 for this because it's easier to setup. In the future, authentication endpoint will be moved to Pen.
The dashboard itself is deployed as a single static html file and served using pushstate-server so all URL will be rendered using the same index.html.
Pen is a simple REST API on top of express that uses mongodb to store blog data. Why mongodb? There is a solid mongodb library in node.js called mongoose, and I already have mongodb setup in my local machine. So no, it's not because I like it. It's just happen to be the quickest to implement.
I use mLab for production database because they offer free tier and managed services so I don't have to worry about configuring mongodb in production. You can also use compose.io for alternative. I haven't compared those two. I only tried mLab and it works well for me.
The blog frontend is also an express app which uses React for server-side rendering. You might be wondering why I use React if I only need SSR. I have a plan in the future that navigating between blog uses client side routing. React allows me to use the same component in both server and client side to render the layout.
Both Lens and Pen use Gulp as build system. I use Gulp instead of plain Babel CLI because I need it to build CSS using autoprefixer and minifier for the blog frontend. The build system for editor dashboard is already using react-scripts from CRA so I don't have to think about it.
Three services may seems overkill for a blog. But instead, this approach allows me to optimize each layers differently. The editor is a SPA so I can optimize this for offline scenario using PWA approach.
For now, I'm going to continue fixing all the bugs and achieve feature parity with Medium editor.