From Curious to Coding 2: Building a Blog with Next.js, Sanity, TypeScript, and Tailwind

A detailed account of the development of this blog, what I learned, and what I used to build it.

The Author's selected photo to represent them.
Steven
Software Engineer
A person shining a light into a dark tunnel that says From Curious to Coding #2

A Quick Overview

This article will cover a brief description of each of the technologies and some of the techniques that I learned and used to make this website that you are reading this article on, Tsundoku. It might look like a simple blog, but it is the culmination of learning about and properly integrating many technologies, concepts, and abstractions.

A lot of work went into researching, planning, building, and testing to make all of this work - and it is worth my time to write it all down. It’s been about ten months since I started learning about web development from the most fundamental concepts, and the completion of this project is something I feel proud of.

I will record my learning path on this project to organize my thoughts and information, save them for future reference, and ideally share them with people who are interested. Whether you are someone who might gain some use from reading about learning new things, web development, or just reading to pass the time, I hope this article helps you in some way.

In this article I will discuss;

1. Conceptualizing Tsundoku

My partner and I wanted a resource where we could summarize and save information for ourselves to revisit as learners, share with others, and develop and refine our writing skills. We decided to make a blog site - and she already had a design in mind.

This being my second project and learning from the setbacks I experienced in my first, I planned how I wanted to structure the project and got to work. After about a week or two of creating and styling pages and adding interactivity, we were discussing how to publish new information to the website once it was deployed.

I still hadn't planned well enough

I assumed I would have a template file in which I would input all the information, create a new page link, and add it to a list on the website. She is much more experienced than I am with the web development process. She advised me to look into content management systems (CMS) and how to implement one into our project.

A work table with people writing notes and discussing a CMS

2. The Need for a Content Management System (CMS)

CMS are services or platforms that enable the storage and management of information organized as content. This information is fetched from an application or website and then dynamically displayed - allowing for customizable, adaptable, and scaleable content presentation. One key benefit of CMS is that it eliminates the need to manually create a new page every time you want to publish an article or update content.

They also often provide version control for published content and additional security for authentication, validation, and access to view and manage content between collaborators and users. They are extremely useful tools, and I learned that they can all be classified as either a ‘traditional’ CMS, a “headless” CMS, or a hybrid between the two.

A display on a desktop computer being built piece by piece.

Traditional CMS

Traditional CMS are full-service, front-end to back-end systems that allow for someone to take pre-built components and adjust their placement, size, and style, then overlay them to build an aesthetic that they are looking for in the data presentation on their website. Generally; traditional CMS services assume responsibility for rendering the HTML, which can lead to limitations in terms of responsive design, accessibility, and performance.

However, they are typically quite flexible with customization for how data is displayed on a webpage. They usually require little-to-no coding knowledge, and are sometimes referred to as ‘No-Code Software.’ Wordpress is an example of a traditional CMS service. I have even seen it listed as a requirement for some front-end developer roles.

Headless CMS

Headless CMS services are exclusively back-end systems that provide content storage and delivery. They do not include a pre-built front-end to render to the user. The front-end portions are created completely by a software engineer using a framework like Next.js, Remix, or Angular. The data is fetched from an API and then the engineer working with the data has to write the structure, functions, classes, and styles to organize and present the data in a meaningful way.

I had to choose a type of CMS for our project. If I have to choose between some technologies to learn, I always prefer to learn whichever has the broadest range of varied use cases. With a headless CMS, a knowledgeable developer can manipulate and display data with fewer limitations over a traditional CMS; so that is what I chose.

A visual representation of each CMS type serving content.

Traditional CMS builds and serves HTML to the local machine / Headless CMS serve data that is rendered as HTML on the local machine

3. Choosing a Headless CMS: Sanity

I found a headless CMS called Sanity that offered all of the features that I would need for this project, and it seemed to scale to whatever kind of project I worked on in the future that would require a CMS. It is a headless CMS in that it provides a service to upload data into a database that Sanity calls ‘The Content Lake.’

Data is pushed to the Lake from a studio that is created and customized by the developer. The published data can then be fetched from any application or website on any device any where, and can then be organized and styled with predefined structure and styling code.

Getting technical

In an empty freshly started Sanity studio, an engineer will create fields called SchemaTypes. Each schema type represents a type of document, such as a Blog Post type, a Video Post type, an Event Post type, etc. In each SchemaType, the engineer creates many input fields that have attributes like Name, description, date, etc. Each input field in each schema type can be given options for customization like minimum and maximum character length, warning messages, validation, error messages, etc.

All of the information input into the studio is saved in a JSON object that can be fetched with a custom query language that sanity created called GROQ. Once fetched, it can then be filtered, mapped, or manipulated like any other JSON object in JavaScript. I had no idea the amount of things I needed to learn to use something like this.

A stylized picture of the Sanity CMS brand

The limitations of core react

During my research on how to implement Sanity into my existing React application for our blog site, I found that all of the recent guides on how to use sanity were using Next.js as the integrated framework.

While reviewing the official React documentation to learn more about how I could make this integration work anyway, I noticed in the official React documentation there is a recommendation to start projects with a React framework such as Next.js, Remix, or Gatsby to gain support for features like routing, data fetching, and HTML generation.

I wanted more built-in functionality

These standard functionalities are missing from the React core library and require 3rd party libraries to be installed as dependencies. I would prefer to limit the amount of dependencies that my project relies on, and using just core React to build apps or websites isn’t even recommended in the official React documentation.

At this point I decided it would probably be easier and better to start a new project with Next.js. I had documentation to help me set up a project with Sanity as my CMS, and I could scale my web development toolkit. I previously had enough experience with JavaScript to start a few projects with React, so now with a few React projects finished - it was time to get comfortable with Next.js.

Spiderman pointing at spiderman pointing at spiderman.

Next is React plus some extra stuff, and React is JavaScript with extra stuff - so Next is just JavaScript with double extra stuff

A Full-Stack JavaScript Framework

Next.js is a React framework that is becoming a popular choice for JavaScript developers to build frontend-to-backend web applications. It offers the built-in routing, data-fetching, and HTML generation features mentioned before, along with server-side rendering (SSR) for faster loading times for the content on the webpage compared to a React application with client-side rendering.

SSR generally improves Search Engine Optimization (SEO) scores given to websites by search engines. Higher scores make a website more visible in search result lists from related searches. Now knowing all this, Next.js seemed like a technology I that would benefit future projects and opportunities if I knew how to use it. I added it to the 'Learn This' list for Tsundoku's tech stack and got back to researching what else I needed before starting the project again.

4. Why I Chose TypeScript for my Studio and Website

While doing a preliminary reading through the documentation on how to set up Sanity Studio for the first time, I noticed all of them saying to enable and use TypeScript. I realized then that a lot of the tech YouTubers that I was learning from were also mentioning TypeScript as an almost need-to-know, and that a lot of job requirements that I was viewing had TypeScript mentioned.

I watched a few Programming with Mosh videos on YouTube and read some of the TypeScript Docs to learn about what TypeScript is and how to use it. I mentioned TypeScript briefly in an earlier article when discussing Angular, but it deserves a fuller explanation than the basic "who made it and when."

Plain visual with the TypeScript logo

A Bit About TypeScript

It should be noted that since 1997, JavaScript has set the standard for web development as a language and technology. It runs within all web browsers, and built-in compilers execute code to render web pages and enable interactive features.

However, it is generally a dynamically-typed scripting language; meaning the data types assigned to each variable are checked only at runtime. This can lead to errors when functions expect an input of a certain data type but receive another. It can especially complicate maintaining and scaling a large codebase, and these were big issues that TypeScript solved.

Microsoft introduced TypeScript in 2012 as a more robust and maintainable alternative to JavaScript while maintaining full compatibility with existing JavaScript code. TypeScript's emphasis on type safety enhances code maintainability, scalability, testability, and comprehension relative to JavaScript. Its compatibility with IDEs also improves code completion functionality over JavaScript.

Circle graph showing the relation between JavaScript and TypeScript

TypeScript is a superset of JavaScript

Is it easy to move from JS to TS?

Conceptually, it is easy to make the change; but in existing large scale projects it can be a massive chore to assign types to all variables. On the surface, all JavaScript code is valid TypeScript code, but not all TypeScript code is valid JavaScript code. Along with TypeScript requiring all variables to have a declared type, it also offers some major benefits over JavaScript - such as its support for object-oriented programming, generics, and advanced type features. These benefits do not translate to JavaScript.

While JavaScript still has use cases over TypeScript like rapid prototyping or when dynamic typing is preferable, for the reasons mentioned above (and more), TypeScript is currently filling the gap of some of JavaScripts inadequacies in type-safe required use cases and especially in large-scale applications. It is increasing in popularity and demand as a preference over JavaScript and even a work requirement for some employers in modern web development.

People discussing something technical.

5. Completing the Tech Stack: TailwindCSS

After learning about TypeScript, I just threw TailwindCSS into my stack. I wanted to use it for elements that needed quick and simple styling, and maybe learn more about it through its use. Tailwind is classified as a utility-first CSS framework that allows developers to quickly add styling to elements through predefined class names rather than in a linked CSS module file or at the bottom of the working file itself.

Doing so removes the need for extra custom CSS code to add simple styling to an element. Tailwind works great for adding a few CSS attributes to an element, but can become cumbersome if many attributes are added to a lot of elements in the working file.

I didn't end up using it as much as I intended, because I kept running into issues with the tailwind classes overriding my custom classes that I assigned through react-responsive's useMediaQuery(). I'm confident that when I go back through and optimize the code, it will help me quite a bit - and there are also a lot of features and uses outside of what I mentioned left for me to explore.

The logo for the tailwindcss framework

I did the research

At this point, it has been a bit over a month since I started researching what a CMS is. Now that I knew I was going to use Next.js as a framework for the website and Sanity for the CMS with TypeScript for type-safe variables and Tailwind for simple element styling, I started the blog site.

I opened my coding environment, opened the projects directory, and created a new Next.js application with the npx create-next-app simple_blog_site command. Navigating back to the parent directory, I then created a sanity studio with npx create-sanity init simpleBlog_studio.

A CLI executing npx create-next-app

6. My Experience with Next.js and How it Improved my Project

'next/link'

Next.js has some cool components built in, like a Link component that preloads the route tied to that Link component and serves it through client-side routing when clicked. This means that links on the current page are fetched from the server on page load and stored on the user’s device, which allows for the linked pages to load without having to call back to the server.

Combining this feature with server side rendering (SSR) leads to much faster page load times and therefore a better user experience. Link can be used on internal and external links, and also includes handling the URL formatting, aria-labeling, and SEO by ensuring proper navigation and indexing by search engines. While traditional anchor tags may still be suitable in some cases, the Link component offers additional features and benefits that make it a great alternative for many scenarios.

'next/image'

Next.js's Image component serves images in the best format and size for the user's device - utilizing features like automatic resizing, lazy loading, and WebP support. It also loads images only when they enter the viewport, so initial page load times are generally reduced. It also improves SEO and accessibility with alt text options.

Image also supports responsive images through the sizes and srcSet attributes, allowing developers to define multiple image variants for different screen sizes. It integrates seamlessly with the Next.js framework, ensuring smooth interactions with a simple API that requires minimal configuration. Image is an excellent alternative to traditional img tags for many use cases

File-based routing

Next.js v14 with the app router has intuitive file based routing. Adding a new page to the site is very straightforward. First, go to the app folder and create a new directory. The name of the directory will also serve as the relative URL path. Inside that directory, make a page.tsx file containing the component that renders a page for the new path; and that's it.

Now any anchor or Link element in the website will lead to that page if it's href value is equal to that directory path relative to the root. This is a very easy and effective way to expand your website or application.

A connecting chart that shows the top features of Next.js

How I Integrated the CMS with Next.js

In Next.js, directory names surrounded by brackets can be used as route parameters, allowing for dynamic routing. For example, let's say I made a SchemaType in Sanity Studio called Post.

In the studio and in the Post SchemaType I have 10 posts that each have a field called ‘slug.’ I can create a directory in my Next.js app folder called “posts” and then another directory in “posts” called “[slug].” Inside “[slug]” I create a file called page.tsx.

In posts/[slug]/page.tsx, I can fetch all of the Post objects from Sanity Studio using a GROQ query, configure the page to use the slug as a route parameter by passing the slug field value from each post into the page as params, and for each Post that I have in the studio that has a slug field completed - a new page will be created with a URL endpoint identical to what that slug is for the post; https://www.tsudoku.blog/posts/[slug]

Then I can build the rest of the structure of each page in the page.tsx file which will be fed the data from each Post in the SchemaType when it is called from the server and each page will be built dynamically on the spot.

That was a lot of words

I want to state it simply - now every time I create content in my studio and publish it, a new page is created on my website automatically with the information input from the studio sent to my website. The pages are filtered through my pre-built structures and styles so it looks exactly how I want it to look, and it can be visited without any additional setup outside of the studio.

The studio the authors use to publish content to Tsundoku.

The studio we use to publish content to Tsundoku.

7. New Interests and Future Plans

There were some features and functionalities in this project that I implemented which sparked a new interest for me in how data is retrieved, organized, and displayed. Using the query language with sanity against the information provided to me about the inputs in the studio was very fun and informative.

I also made a simple function that organizes an array of fetched posts by an injected custom variable. A function matches the currently displayed post object's categories against the category values of the other post objects in the fetched array, and assigns a variable that increases in value when categories are matched.

The point system prioritizes matches in earlier categories, so two posts with matching ‘category 1’ values increase the custom variable more than if the current post and the compared post matched in both “category 2” and “category 3” values. The array was then organized by the value of the object's injected variable and sliced up to the first three positions. The top three related articles were then mapped in a content container at the bottom of each article page.

A screenshot of the realted articles at the bottom of an article page.

For example; these articles would show at the bottom of a post with Category1 as UI Design and Category2 as UX.

Features, Functionality, and Fulfillment

I wanted to ensure that the most relevant content was recommended to the user once they finished reading the article in the case they wanted to read more content of a similar nature. I was able to understand what was happening in my project and make decisions on what features or functionalities I could introduce to improve the project.

I was also able to successfully write and implement those changes. Solving problems like this gives me such a sense of satisfaction. Even if they are small solutions that I am implementing, it shows me that I have the mindset to solve problems in a technical way - and I am just getting started. I’m only on my second major project, and I love what I am doing.

Finally, Tsundoku is finished

Everything is coming together. I have my studio that I customized to store and deliver information relevant to the content my partner and I want to publish, we have a website that is structured and styled to display the information exactly how we want it, and I learned some valuable information and implemented some helpful features that I was able to write about in this article. I have also discovered a deeper interest in back-end technologies and using programming to solve complicated problems.

A person completing a task on a computer.

The Learning Journey Never Ends

After this project, I feel my focus is moving from web development to a much broader view of software development as a whole. I will still be using everything I have learned to build web projects and maybe even mobile applications; of course. My partner and I already have another website/service that we plan to start soon.

But I do want to start learning a programming language like python that has broader applications, so maybe I will be writing about that in the near future. Thank you for reading to the end. I hope that the information I discussed here will help you in some way, either through some insight on a new developer’s thought process, a direction to take your learning path, a new technology that might fit your use case, or just a good read to pass the time.

A cup of coffee and a computer sitting on a wooden desk in front of a window.

Caffiene and Computers really do make the world a better place.

Related Articles