My first blog, and main website
The source code for this site can be viewed here
I have purchased a domain before and attempted to create a hub for my work. However, there was just too many new things to learn. Now, I have gotten a good understanding for the technologies involved in building a website. This blog is built in React, using the NextJS framework. This allows for server-side rendering, routing and better SEO (search engine optimization). I am using NextJS's hosting service Vercel (previously Ziet Now). The technologies involved are overkill for a simple blog but I know them and do get some benefits from them. This works as a good practice to make sure I really know what I am doing when building websites. I am using markdown to write these blog posts. This is accomplished using remark, remark-html and gray-matter. I can setup a heading where I define the title, date and cover image. Then that data is interpreted using gray-matter. The markdown is processed to assign proper element tags. This allows me to write paragraphs and paragraphs without creating hundreds of tags. The styling was simple, I am using the same markdown styling from Github. If you have seen how Github styles their README.md files, that is what is being used here. This bloated the CSS file at nearly 1000 lines but css modules help keep things from getting messy.
NextJS has allowed me to easily setup the different pages to the application. If you are unfamiliar to the framework, unlike normal React applications. Where you need to establish a router with many attributes. NextJS has opinionated rules about how to setup pages but allows for simplicity. All that is needed is to create a directory called pages. Once created any folders within /pages will create a new page of the application. For example for this site currently I have blog, posts, contact, projects and about pages. This means I have created a folder for each page. For dynamic pages NextJS requires brackets around the name of the JavaScript file.
Pages Dir
pages/
├── blog/
| ├── index.js
| └── [slug].js
├── api/
| ├── getComments.js
| ├── login.js
| ├── postComment.js
| ├── putComment.js
| └── putPost.js
├── projects/
| ├── index.js
| └── [slug].js
├── _app.js
├── about.js
├── contact.js
└── index.js
Something new is the use of React-Bootstrap for this project. I have used Bootstrap but the use of Bootstrap components is completely new. Instead of creating a div with class container, I import Container from 'react-bootstrap/Container'. This is cleaner but requires learning some new things. For instance I could not apply styles using a CSS module file to the Container component. I learned ways to get the styling I wanted through the documentation online.
Bootstrap Components (Container, Row, Col)
<Container>
<Row className="m-5">
<Col className="col-lg-6 col-12">
<img src="/assets/images/author.jpg" className="aboutAuthorImg" />
</Col>
<Col className="col-lg-6 col-12">
<h1 className="display-1">Hello, 👋</h1>
<h2>I'm a student, ...</h2>
</Col>
</Row>
<Row className="m-5">
<Col className="col-lg-6 col-12">
<h1 className="display-3">Some things about me. 💻</h1>
<h2>I graduate in the Fall of 2020. ...</h2>
</Col>
<Col className="col-lg-6 col-12">
<img src="/assets/images/gamejam.jpg" className="aboutGroupImg" />
</Col>
</Row>
</Container>
A part which took some work was setting up a grid system for the posts in the blog page and a filter system for the posts. Grid systems have been a sticking point for my development. They never seem to work quickly and easily. I did do a write up for my first post on a photography website where I reconstruct a image gallery (post). For this site I was greatly helped with the use of a npm package called lodash which has a function called chunk. Using chunk I was able to split an array of posts into arrays of a set number. The set number would be the number of columns, in my case 2.
Map on an array of post rows
export default function MoreStories({ cols, posts }) {
const rows = chunk(posts, cols)
return (
<>
<h1>More Stories</h1>
{rows.map((cols, index) => (
<Row key={index}>
{cols.map((post, index) => (
<Col sm={12} md={6} key={index}>
<PostPreview
key={post.slug}
title={post.title}
coverImage={post.coverImage}
date={format(post.date)}
author={post.author}
slug={post.slug}
excerpt={post.excerpt}
/>
</Col>
))}
</Row>
))}
</>
)
}
Then using map I iterate over the rows of 2 posts each being its own column. The column is created by using map on the row and you have your posts. There I have a component for the post where I pass all the data to render a post within the grid. I also make use of another npm package in that same file called timeago.js which displays dates in a human readable fashion. This post was created 2020-06-22 but you will likely read it as something like "x years ago".
My most recent update has been adding Syntax Highlighting. This combined with clean styling for code blocks allow me to share code easily in the page. I had some friction with these blogs being written in markdown and passing into a converter which outputs the html into a string which is passed as a child to a outter div tag. Syntax highlighting was done through a downloaded js and css file from Prism. I added some other functionality that I thought was interesting like the ability to replicate the styling of a terminal and its output. Some other plugins were for a easy copy button, line-numbers and a treeview language for showing file structures like I did in this post.
The website is mostly finished I have gotten all the pages finished except the main index page. There I want a interactive experience where the user can scroll and there will be a clean aesthetic presentation. I would want a hacker kind of look with a fake terminal and using ASCII art. Until I complete that I want to keep this website as a top priority outside of my job. I will make another post dealing with exclusively the main presentation index page once I have it completed.
Update
3 Months Later
I have completed the landing page. There are several technologies involved and I expanded the scope of the page. For this reason I am making a seperate post about my development on it. Going to the 'Home' link found at the navigation will show you the page live. Or simply click here
Landing Page
Update
6 Months Later
I have gone through several changes to this blog page. I wanted to add comments and a feature to log the views on the posts. This is persistent data and requires a backend. I was seriously considering changing the host platform to Heroku to help me add a backend. This is due to the serverless nature of the vercel platform combined with Nextjs. The api pages run on AWS Lambdas which cannot create a global reusable instance to pool database connections. If, I tried to create a connection inside the Lambda I would quickly run out of connections. I did create all Heroku code and got a successful version hosted with a backend. The Heroku rebuild used a database bouncer to pool connections and this is best done with Nextjs by creating a custom server. I liked this solution until I figured out about the limitations of Heroku free tier limit. You can only have 1000 hours per month of awake hosts. Running my home page on hereoku always awake would add up to about 750 hours per month. This is fine until I account for the other Heroku projects I have 9 Heroku projects which all can be woken and add to my hours. If I reached the 1000 hour limit all hosts would not be reachable until the next month. Not ideal, so, I switched back to Vercel as a hosting platform and cleverly connected a dedicated database bouncer to another Heroku account which has an always on node server. This node server does database pooling for all my backends and performs the query. Of course this would be a major security concern if these endpoints were public. So, I require an API key which all my applications server-side will know and pass with their requests. Ultimately I should have scalable, performant, and best of all free applications now. The biggest limitation I have is the Heroku PostgresQL limitation of 10,000 rows for Hobby free tier. This can be expanded to 10 million rows for $9 a month if needed.