engineering

Migrating My Blog from Jekyll to Next.js and Tailwind CSS

A modern web development workflow for blogging, Introducing Tailwind Nextjs Starter Blog

Last Edited on

10 min read

After a few years of running my blog on Loading ..., I decided it was time for an upgrade. Jekyll served me well, but as my needs evolved, I found myself wanting more flexibility, better performance, and a more modern development workflow. Enter Loading ..., Loading ..., and a host of other modern web development tools that have transformed my blogging experience. Here's a rundown of the migration process and the benefits I’ve enjoyed since making the switch.

Why Migrate from Jekyll?

Jekyll is a static site generator that is simple, reliable, and supported by GitHub Pages. However, it has its limitations:

  • Performance: While Jekyll is fast for simple blogs, it can become sluggish as your content grows.
  • Customization: Advanced customization often requires diving into Liquid templates and custom plugins, which can be cumbersome.
  • Modern Workflow: Jekyll lacks some modern development features like hot-reloading and advanced state management.

Choosing Next.js and Tailwind CSS

Next.js, a React-based framework, offers the perfect balance of flexibility and performance:

  • Server-Side Rendering (SSR) and Static Site Generation (SSG): Next.js allows you to choose between SSR and SSG, optimizing performance and SEO.
  • Dynamic Routing: Easy creation of dynamic routes without complex configuration.
  • API Routes: Built-in API routes simplify backend logic integration.
  • Tailwind CSS complements Next.js by providing a utility-first CSS framework that speeds up styling and ensures consistency.

Tailwind Nextjs Starter Blog

I believe in reusing existing solutions to save time and effort, and a quick search led me to an amazing starting point: the Loading .... This starter template provided a solid foundation, integrating Next.js and Tailwind CSS with additional features like MDX support, theme switching, and pre-configured styles.

This is a Loading ... 13+In version 13, Next.js introduced a new App Router built on React Server Components, which supports shared layouts, nested routing, loading states, error handling, and more. The App Router works in a new directory named app. The app directory works alongside the pages directory to allow for incremental adoption. This allows you to opt some routes of your application into the new behavior while keeping other routes in the pages directory for previous behavior. If your application uses the pages directory, please also see the Pages Router documentation., Loading ... blogging starter template. Probably the most feature-rich Next.js markdown blogging template out there. Comes out of the box configured with the latest technologies to make technical writing a breeze. Easily configurable and customizable. Perfect as a replacement to existing Jekyll and Hugo individual blogs. The main features that I relied and extended on are:

  • Easy styling customization and Mobile-friendly view with Loading ... and primary color attribute
  • Loading ...
  • Loading ... for managing content
  • Server-side syntax highlighting with line numbers and line highlighting via Loading ...
  • Math display supported via Loading ...
  • Citation and bibliography support via Loading ...
  • Automatic image optimization via Loading ...
  • Flexible data retrieval with Loading ...
  • Preconfigured security headers
  • SEO friendly with RSS feed, sitemaps

The Template Structure

First, lets understand the different folders/components of the template:

static

Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL /.

For our template, we have a static folder that contains images to be used in the blog, logos,icons and favicons.

scripts

This folder contains scripts to help with the development and maintenance of the blog.

  • The build.mjs script is used to perform a bunch of steps post the yarn run build command. It is used to generate the RSS feed and the tags and categories pages.
  • The rss.mjs script is used to generate the RSS feed for the blog.

NOTE

Why .mjs extension?

Since Node.js was created, the ECMAScript module system (which uses import and export) has become standard and Node.js has added support for it. However, Node. will treat .js files as CommonJS (which is the default module system for the project) unless package.json says "type": "module" or the file extension is .mjs.

data

The data folder contains the site metadata, authors, and blog posts in .mdx. The markdownToHtml function is used to convert markdown .mdx to HTML.

  • authors: contains the author information for the blog posts and is used to populate the about page. This can be extended to allow multiple authors.
  • blog: contains the blog posts in mdx format. The folders are used to categorize the blog posts.
  • metadata: contains the site metadata like navigation links, site title, description, etc. We will discuss this in more details in the metadata section

layouts

The layouts folder contains the main templates used in the pages. The main layout is MainLayout.js which is used to wrap all the pages. The PostLayout.js is used to wrap all the blog posts.

lib

The lib folder contains utility functions and configurations used throughout the blog.

  • contentLayer: contains the content layer "plugins"/"scripts" for the blog posts and projects.
    • computedFields.js: contains the computed fields for the blog posts. Those are fields that are generated based on the content of the blog post or its metadata like the readingTime or toc (table of contents).
    • contentFields.js: defined the fields that appear in the frontmatter for the different types of content (author, post, project, etc.).
    • generatedCategories.mjs: Loops through all the posts and generates the categories for the blog posts.
    • generatedTags.mjs - generates the tags for the blog posts.
    • projectFields.js - contains the project fields for the projects page.
    • structuredData.js - contains the structured data for the blog posts.
  • mdx - contains the utility functions for the MDX files.
    • remark-code-title.js - adds a title to the code blocks.
    • rehype-citation.js - adds citation support to the MDX files.
    • rehype-katex.js - adds math display support to the MDX files.

components

The components folder contains the React components used in the blog. The MDXComponents.js file contains the components used to render the MDX files. The social-icons folder contains the SVG icons for social media.

css

The css folder contains the tailwind.css file which contains the tailwind stylesheet. The prism.css file contains the styles associated with the code blocks.

app

The app folder contains the main application files. The pages folder contains the pages to route to. The api folder contains the API routes. The components folder contains the components used in the pages. The styles folder contains the global styles.

Sample posts

  • Loading ...
  • Loading ...
  • Loading ...
  • Loading ...
  • Loading ...
  • Loading ...

Quick Start Guide

  1. Try installing the starter using the new Loading ...:
npm i -g @pliny/cli
pliny new --template=starter-blog my-blog

It supports the updated version of the blog with Contentlayer, optional choice of TS/JS and different package managers as well as more modularized components which will be the basis of the template going forward.

Alternatively to stick with the current version, TypeScript and Contentlayer:

npx degit 'timlrx/tailwind-nextjs-starter-blog#contentlayer'

or JS (official support)

npx degit https://github.com/timlrx/tailwind-nextjs-starter-blog.git
  1. Personalize siteMetadata.js (site related information)
  2. Modify the content security policy in next.config.js if you want to use any analytics provider or a commenting solution other than giscus.
  3. Personalize authors/default.md (main author)
  4. Modify projectsData.js
  5. Modify headerNavLinks.js to customize navigation links
  6. Add blog posts
  7. Deploy on Vercel

Development

First, run the development server:

npm start
# or
npm run dev

Open Loading ... with your browser to see the result.

You can start editing the page by modifying pages/index.js. The page auto-updates as you edit the file.

Extend / Customize

data/siteMetadata.js - contains most of the site related information which should be modified for a user's need.

data/authors/default.md - default author information (required). Additional authors can be added as files in data/authors.

data/projectsData.js - data used to generate styled card on the projects page.

data/headerNavLinks.js - navigation links.

data/logo.svg - replace with your own logo.

data/blog - replace with your own blog posts.

public/static - store assets such as images and favicons.

tailwind.config.js and css/tailwind.css - contain the tailwind stylesheet which can be modified to change the overall look and feel of the site.

css/prism.css - controls the styles associated with the code blocks. Feel free to customize it and use your preferred prismjs theme e.g. Loading ....

components/social-icons - to add other icons, simply copy an svg file from Loading ... and map them in index.js. Other icons use Loading ....

components/MDXComponents.js - pass your own JSX code or React component by specifying it over here. You can then call them directly in the .mdx or .md file. By default, a custom link and image component is passed.

layouts - main templates used in pages.

pages - pages to route to. Read the Loading ... for more information.

next.config.js - configuration related to Next.js. You need to adapt the Content Security Policy if you want to load scripts, images etc. from other domains.

Post

Frontmatter

Frontmatter follows Loading ....

Currently 7 fields are supported.

title (required)
date (required)
tags (required, can be empty array)
lastmod (optional)
draft (optional)
summary (optional)
images (optional, if none provided defaults to socialBanner in siteMetadata config)
authors (optional list which should correspond to the file names in `data/authors`. Uses `default` if none is specified)
layout (optional list which should correspond to the file names in `data/layouts`)
canonicalUrl (optional, canonical url for the post for SEO)

Here's an example of a post's frontmatter:

---
title: 'Introducing Tailwind Nexjs Starter Blog'
date: '2021-01-12'
lastmod: '2021-01-18'
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'Looking for a performant, out of the box template, with all the best in web technology to support your blogging needs? Checkout the Tailwind Nextjs Starter Blog template.'
images: ['/static/images/canada/mountains.jpg', '/static/images/canada/toronto.jpg']
authors: ['default', 'sparrowhawk']
layout: PostLayout
canonicalUrl: https://tailwind-nextjs-starter-blog.vercel.app/blog/introducing-tailwind-nextjs-starter-blog
---

Compose

Run node ./scripts/compose.js to bootstrap a new post.

Follow the interactive prompt to generate a post with pre-filled front matter.

Deploy

Vercel
The easiest way to deploy the template is to use the Loading ... from the creators of Next.js. Check out the Loading ... for more details.

Netlify / GitHub Pages / Firebase etc.
As the template uses next/image for image optimization, additional configurations have to be made to deploy on other popular static hosting websites like Loading ... or Loading .... An alternative image optimization provider such as Imgix, Cloudinary or Akamai has to be used. Alternatively, replace the next/image component with a standard <img> tag. See Loading ... for more details.

The API routes used in the newsletter component cannot be used in a static site export. You will need to use a form API endpoint provider and substitute the route in the newsletter component accordingly. Other hosting platforms such as Netlify also offer alternative solutions - please refer to their docs for more information.

Support

Using the template? Support this effort by giving a star on GitHub, sharing your own blog and giving a shoutout on Twitter or be a project Loading ....

Licence

Loading ... © Loading ...

The opinions and views expressed on this blog are solely my own and do not reflect the opinions, views, or positions of my employer or any affiliated organizations. All content provided on this blog is for informational purposes only