“This is my fourth day of participating in the First Challenge 2022. For more details: First Challenge 2022.”

Next. Js is a React based application framework created and maintained by Vercel. This tutorial will learn how to build a small blog site from scratch using next.js:

  • Basic page creation
  • fromMarkdownFile generated dynamic routing
  • Statically generated (rendered at build time)
  • Server-side rendering (render on request)

The address of the codebase mentioned in this article: github.com/QuintionTan…

Is Next. Js suitable for blogs?

This tutorial will demonstrate the functionality of next.js by creating a simple blog. Is next.js suitable for such blog development? Let’s start by understanding what a typical blog needs.

  • WordPress is a content management system (CMS) that supports one-third of all web sites and serves pages by rendering editable database content into PHP templates on each request. It’s great for regularly updated content, but performance, security, and data backup require some customization.

  • Static site Builders (SSGS) such as Eleventy or Gatsby create pre-rendered files and quickly build static sites without a server side or database. They are excellent in version control, performance, and security, but the build steps and developer-centric process can slow down release times, especially on large sites.

Next. Js is a React based application framework that has few blog-specific features. However, it can provide an implementation mechanism:

  1. Where possible,Next.jsGenerate static content, such as SSG, pages that load very quickly, can be quickly indexed by search engines, and can be read on any device with or without JavaScript.
  2. After the first load,Next.jsThe application behaves like a one-page application (SPA) in that subsequent pages and code are downloaded incrementally without the need to refresh the entire page.
  3. Next.jsProviding server-side rendering (SSR) for each request makes it easier to provide real-time CMS updates or customizations for individual users.

If the site is likely to iterate from a basic blog to a more complex site, such as an online store, a news aggregation service, a social media platform, etc., consider Next.

start

The complete code for what this tutorial is building can be found on GitHub. You can download, install, and start it on Windows, macOS, or Linux by entering the following commands in your terminal:

git clone [email protected]:QuintionTang/react-blog.git
cd react-blog
npm i
npm run dev
Copy the code

Then type localhost:3000 in your browser to open the home page.

Next. Js provides a create-next-app tool to get started using application templates quickly. This tutorial will show you how to build a site from scratch, such as adding static resources or pages.

Install Next. Js and React

As with any node.js or VUE project, first create a directory and initialize the package.json file:

mkdir react-blog
cd react-blog
npm init
Copy the code

Then install Next. Js and React as dependencies:

npm install next react react-dom --save 
Copy the code

Add the development build script Settings, as shown below, to the scripts property of package.json file:

"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
}
Copy the code
Create the first page

Next. Js has a file system-based router. Any React component files created in the project’s Pages directory are automatically rendered as a page.

To create a page, add an index.js file to the Pages directory. Add the following code to the./pages/index.js file to return the functional React component of the JSX code:

Export default function Home() {return (<> <h1>Next. Js </h1> <p Href = "https://nextjs.org/" > Next. Js < / a >. </p> </> ); }Copy the code

JSX must be returned within a single containing element, such as

. < >… The notation defines a document fragment, so no additional containers are required.

To start the next.js development server, run NPM run dev from the root of the project in a terminal (you can use NPX Next dev), then open http://localhost:3000/ in a browser:

Next. Js has determined that the page can be pre-rendered, so it displays a lightning bolt icon in development mode.

You can create a similar file in the auto-routing page directory as follows:

  • pages/index.jsUsed to present the main blog
  • pages/about.jsPresent a/aboutpage
Adding links

Use standard HTML tags in JSX code to create a hyperlink to another page. If the page is in the same Next. Js site, the browser will refresh the entire page. You can use the < link > component in Next/Link to jump to pages. Create a link to the /about page on the root page /index.js as follows:

import Link from "next/link"; Export default function Home() {return (<> <h1>Next. Js </h1> <p Href = "https://nextjs.org/" > Next. Js < / a >. < / p > < p > more information please click {" "} < Link href = "/ about" > < a > about us... </a> </Link> </p> </> ); }Copy the code

When clicking about us… When linking, next.js will use Ajax to request the downloaded /about content once, cache it, and then render it on the page.

Add elements

You can use the < head > component in next/ Head to change the page title and meta tag as follows:

import Head from "next/head"; import Link from "next/link"; Export default function Home() {return (<> <Head> <title>Next. Js 网 址 </title> <meta name="description" content= Next. Js driven website "/> </Head> <h1>Next. Js blog site </h1> <p> This blog site will use <a href="https://nextjs.org/">Next. < / p > < p > more information please click {" "} < Link href = "/ about" > < a > about us... </a> </Link> </p> </> ); }Copy the code

Click on the browser to view the source code and see the relevant HTML tags.

Adding static Resources

The public directory is used to store static resources, such as ICONS, robots.txt, or other files that are not updated frequently. You can add your own files or copy the Favicon.ico and image subdirectories from the original project repository.

Create a template

Next, create a new components folder in the project root directory and add layout.js to define a new < layout > component:

import Header from "./header";
import Footer from "./footer";

export default function Layout({ children, title }) {
    return (
        <>
            <Header title={title} />
            <main>{children}</main>
            <Footer />
        </>
    );
}
Copy the code

Any page that uses this component passes a props object that contains the content as a child value of children.

also references two other components,

in Component /header.js, which render a

, Contains home page links, inline SVG logos, and images that default to /images/header.jpg:

import Link from "next/link"; export default function Header({ title }) { const headerImg = "/images/" + (title || "header.jpg"); return ( <header> <p className="logo"> <Link href="/"> <a> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" Width ="50" height="50" > <path d="M10.394 2.08a1 10 00-.788 0L-7 3A1 10 000 1.84l5.25 8.051a.999.999 0 01.356-.257l4-1.714a1 1 0 11.788 1.838L7.667 9.088l1.94.831a1 1 0 00.787 0l7-3a1 1 0 000-1.838 l-7-3zm3.31 9.397L5 10.12v4.102a8.969 8.969 0 00-1.05-.174 11 0 01-.89-.89 11.115 11.115 0 01.25-3.762zM9.3 16.573A9.026 9.026 0 007 14.935v-3.957l1.818.78 A3 3 0 002.364 0l5.508-2.361a11.026 11.026 0 01.25 3.762 11 0 01-.89.89 8.968 8.968 0 00-5.35 2.524 1 1 0 01-1.4 0zM6 18A1 1 0 001-1v-2.065a8.935 8.935 0 00-2-.712v17a1 1 0 001z "></path> </ SVG > next.js blog </a> </Link> </p> <figure> <img src={headerImg} height="80" alt="decoration" /> </figure> </header> ); }Copy the code

The second component,

in Component /footer.js, renders the

content, which contains links to the GitHub repository and inline SVG:
export default function Footer() { return ( <footer> <p className="github"> <a href="https://github.com/QuintionTang/react-blog"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" Width ="50" height="50" > <path d="M256 32C132.3 32 32 134.9 32 261.7a229.3 229.3 0 00153.2 217.9 17.6 17.6 0 003.8.4c8.3 0 11.5-6.1 11.5-11.4 L -.3-39.1a102.4 102.4 0 01-22.6 2.7c-43.1 0-52.9-33.5-52.9-33.5-10.2-26.5-24.9-33.6-24.9-33.6-19.5-13.7-1-14.1-1.4-14.1 h. 1 c22. 5 2 34.3 23.8 34.3 23.8 11.2 19.6 26.2 25.1 39.6 25.1 A63 63 0 0025.6-6c2-14.8 7.8-24.9 14.2-30.7-49.7-5.8-102-25.5-102-113.5 0-25.1 8.7-45.6 23-61.6a84.6 84.6 0 012.2-60.8 18.6 18.6 0 015-.5c8. 10 26.4 3.1 56.6 24.1a208.2 208.2 0 01112.2 0c30.2-21 48.5-24.1 56.6-24.1a18.6 18.6 0 015.5 84.6 84.6 0 012.2 60.8 90.3 90.3 0 0123 61.6 C0 88.2-52.4 107.6-102.3 113.3 8 7.1 15.2 21.1 15.2 42.5 0 30.7-.3 55.5-.3 63 0 5.4 3.1 11.5 11.4 11.5a19.4 19.4 0 004-.4a2292 229.2 0 00480 261.7C480 134.9 379.7 32 256 32z" /> </svg> https://github.com/QuintionTang/react-blog </a> </p> </footer> ); }Copy the code

Next update pages/index.js with a custom

component:

import Layout from ".. /components/layout"; import Head from "next/head"; import Link from "next/link"; Export default function Home() {return (<Layout> <Head> <title> next.js </title> <meta name="description" Content =" This is a website driven by Next. Js "/> </Head> <h1>Next. Js blog site </h1> <p> This blog site will use <a href="https://nextjs.org/">Next. < / p > < p > more information please click {" "} < Link href = "/ about" > < a > about us... </a> </Link> </p> </Layout> ); }Copy the code

Then do the same for pages/about.js and any other pages you create.

import Layout from ".. /components/layout"; import Head from "next/head"; Export default function Home() {return (<Layout title="share.png"> <Head> <title> </Head> <h1> </h1> < P > WEB development sharing center, with their own enthusiasm to share the Internet bit by bit, so as to encourage themselves to strengthen learning and self-improvement. </p> </Layout> ); }Copy the code
Use dynamic routing to view blog content

Creating content using JSX is not particularly practical, especially for regular blog posts, which developers prefer to blog in the Markdown way. Next. Js can create pages from any source. These can be generated statically at build time and map data to urls using dynamic routing.

Before continuing, let’s create a post directory to hold the Markdown files for your blog. E.g. Articles/articles-01.md:

Description: next.js is a React based application framework created and maintained by Vercel. This tutorial will learn how to build a small blog site from scratch using next.js. Date: 2022-01-22 Tags: -html-CSS-react -- Next-.js is a REACT based application framework created and maintained by Vercel. This tutorial will learn how to build a small blog site from scratch using next.js. This tutorial will demonstrate the functionality of next.js by creating a simple blog. Is next.js suitable for such blog development? Let's start by understanding what a typical blog needs. - WordPress is a content management system (CMS) that supports one in three web sites and serves pages by rendering editable database content into PHP templates on each request. It's great for regularly updated content, but performance, security, and data backup require some customization. - Static site Generator (SSG) such as Eleventy or Gatsby creates pre-rendered files and can quickly build static sites without a server side or database. It is excellent in version control, performance and security, but the build steps and developer-centric process can slow down the release. Especially on large sites. Next. Js is a React based application framework that has few blog-specific features. However, it can provide an implementation mechanism: 1. Where possible, Next. Js generates static content, such as SSG, which loads very quickly, can be quickly indexed by search engines, and can be read on any device with or without JavaScript. 2. After the first load, the Next. Js application behaves like a one-page application (SPA), with subsequent pages and code being progressively downloaded without needing to refresh the entire page. 3. Next. Js provides server-side rendering (SSR) for each request, making it easier to provide real-time CMS updates or customizations for individual users. If the site is likely to iterate from a basic blog to a more complex site, such as an online store, a news aggregation service, a social media platform, etc., consider Next.Copy the code

The content template defines metadata such as the blog’s title and publication date, followed by the blog’s body. Next you need to install the dependencies for parsing content, including front-matter, remark, and remark-html, by executing the following command:

npm install front-matter remark remark-html --save
Copy the code

To read and parse the Markdown file, you need to add the logic to libs/posts-md.js where the code is located.

import { promises as fsp } from "fs"; import path from "path"; import fm from "front-matter"; import { remark } from "remark"; import remarkhtml from "remark-html"; import * as dateformat from "./dateformat"; const fileExt = "md"; Function absPath(dir) {return path.isAbsolute(dir)? dir : path.resolve(process.cwd(), dir); } /** * get the list of Markdown file names in the folder, Return * @param {*} dir * @returns */ export async function getFileIds(dir = "./") {const loc = absPath(dir); const files = await fsp.readdir(loc); return files .filter((fn) => path.extname(fn) === `.${fileExt}`) .map((fn) => path.basename(fn, path.extname(fn))); @param {*} dir * @param {*} id * @returns */ export async function getFileData(dir = "./",  id) { const file = path.join(absPath(dir), `${id}.${fileExt}`), stat = await fsp.stat(file), data = await fsp.readFile(file, "utf8"), matter = fm(data), html = (await remark().use(remarkhtml).process(matter.body)).toString(); / / date formatted const date = matter. The attributes. The date | | stat., ctime. matter.attributes.date = date.toUTCString(); matter.attributes.dateYMD = dateformat.ymd(date); matter.attributes.dateFriendly = dateformat.friendly(date); Const roundTo = 10, readPerMin = 200, numFormat = new intl.numberFormat ("en"), count = matter.body .replace(/\W/g, " ") .replace(/\s+/g, " ") .split(" ").length, words = Math.ceil(count / roundTo) * roundTo, mins = Math.ceil(count / readPerMin); matter.attributes.wordcount = `${numFormat.format( words )} words, ${numFormat.format(mins)}-minute read`; return { id, html, ... matter.attributes, }; }Copy the code

The above code involves date formatting code, file path libs/dateformat.js.

// Time formatting const toMonth = new intl.dateTimeFormat ("en", {month: "long"}); Yyyy-mm-dd export function ymd(date) {return date instanceof date? `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart( 2, "0" )}-${String(date.getUTCDate()).padStart(2, "0")} ` : ""; } // format to DD MMMM, YYYY export function friendly(date) {return date instanceof date? `${date.getUTCDate()} ${toMonth.format( date )}, ${date.getUTCFullYear()}` : ""; }Copy the code

Next.js uses the filename of the identifier contained in [ID] to identify dynamic (generated) routes. Create a file called Pages /articles/[id].js: Next. Js will use id as argument to generate pages at /articles/article-01, the details page route of the blog.

Pages /articles/[id].js defines the function getStaticPaths, which returns the path information to render at build time.

@returns [{params: {id: 'article-01' } } ] */ export async function getStaticPaths() { const paths = (await getFileIds(postsDir)).map((id) => { return { params: { id } }; }); console.log(paths); return { paths, fallback: false, }; }Copy the code

Setting fallback: false causes a 404 page to appear when the path cannot be found.

Next, create the function getStaticProps, which gets the data for a specific ID at build time to generate statically. It passes an ID attribute in the Params object and calls the getFileData() function in libs/posts-md.js to parse the Markdown file.

* @param {*} param0 * @returns */ export async function getStaticProps({params}) {return {props: { postData: await getFileData(postsDir, params.id), }, }; }Copy the code

In addition to parsing blog content, pages/articles/[id].js exports the content as a React component, which renders postData into the template created earlier:

Export default function Article({postData}) {const HTML = '<h1>${postdata. title}</h1> <p class="time"><time datetime="${postData.dateYMD}">${postData.dateFriendly}</time></p> <p class="words">${postData.wordcount}</p> ${postData.html} `; return ( <Layout title="share.png"> <Head> <title>{postData.title}</title> <meta name="description" content={postData.description} /> </Head> <article dangerouslySetInnerHTML={{ __html: html }} /> </Layout> ); }Copy the code

The dangerouslySetInnerHTML property ensures that HTML is not encoded.

Create a blog list page

Create a file called pages/articles/index.js. The function of this page is to parse the list of blogs and return it as a React component. Before implementing the page functionality, create a link component, Pagelink.

The Pagelink component implements the layout of a single blog in the list of blogs and creates a file components/pagelink.js with the following code:

import Link from "next/link"; export default function Pagelink(props) { const link = `/${props.postsdir}/${props.id}`; Return (<article> <h2> <Link href={Link}> <a>{props. Title}</a> </Link> </h2> <p className="time">  <time dateTime={props.datefriendly}>{props.dateymd}</time> </p> <p>{props.description}</p> </article> ); }Copy the code

After completing the individual blog layout, take a look at the blog list page, which looks like this:

import { getAllFiles } from ".. /.. /libs/posts-md"; import Layout from ".. /.. /components/layout"; import Pagelink from ".. /.. /components/pagelink"; import Head from "next/head"; const postsDir = "articles"; Export default function ArticleIndex({postData}) {return (<Layout title="share.png"> <Head> <title> <meta name="description" content="A list of articles published on this site." /> </Head> <h1 className="pagelist"> {postData.map((post) => ( <Pagelink key={post.id} postsdir={postsDir} id={post.id} title={post.title} description={post.description} dateymd={post.dateYMD} datefriendly={post.dateFriendly} /> ))} </aside> </Layout> ); } / * * * to get all articles articles @ returns an array of * * / export async function getStaticProps () {return {props: {postData: await getAllFiles(postsDir), }, }; }Copy the code
Create a navigation

A complete blog site, need a navigation menu, easy to switch content. Next, create a navigation component, create a file components/navs.js, and export a < navs > component as follows:

import { useRouter } from "next/router"; import Link from "next/link"; // menu name and link const menu = [{text: "网 页", link: "/"}, {text: "about us ", link: "/about"}, {text:" ", link: "/articles"},]; export default function Navs() { const router = useRouter(), currentPage = router.pathname; return ( <nav> <ul> {menu.map((item) => ( <NavItem key={item.link} text={item.text} link={item.link} currentpage={currentPage} /> ))} </ul> </nav> ); } function NavItem({ text, link, currentpage }) { if (link === currentpage) { return ( <li className="active"> <strong>{text}</strong> </li> ); } else { return ( <li> <Link href={link}> <a>{text}</a> </Link> </li> ); }}Copy the code

Add the Navs component to the component Header as follows:

import Link from "next/link"; import Navs from "./navs"; / / navigation menu to export the default function Header ({title} {const headerImg = "/ images/" + (title | |" cover. PNG "); return ( <header> <p className="logo"> <Link href="/"> <a> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" Width ="50" height="50" > <path d="M10.394 2.08a1 10 00-.788 0L-7 3A1 10 000 1.84l5.25 8.051a.999.999 0 01.356-.257l4-1.714a1 1 0 11.788 1.838L7.667 9.088l1.94.831a1 1 0 00.787 0l7-3a1 1 0 000-1.838 l-7-3zm3.31 9.397L5 10.12v4.102a8.969 8.969 0 00-1.05-.174 11 0 01-.89-.89 11.115 11.115 0 01.25-3.762zM9.3 16.573A9.026 9.026 0 007 14.935v-3.957l1.818.78 A3 3 0 002.364 0l5.508-2.361a11.026 11.026 0 01.25 3.762 11 0 01-.89.89 8.968 8.968 0 00-5.35 2.524 1 1 0 01-1.4 0zM6 18A1 1 0 001-1v-2.065a8.935 8.935 0 00-2-.712v17a1 1 0 001z "></path> </ SVG > next.js blog </a> </Link> </p> <Navs /> <figure> <img src={headerImg} width="400" alt="decoration" /> </figure> </header> ); }Copy the code

At this point a simple blog site feature has been implemented.

Add the style

Next.js provides a series of style options, including Sass, Less, PostCSS, Styled JSX, CSS modules, and regular CSS. Sass is easy to use because no configuration is required according to dependencies:

npm install sass --save  
Copy the code

Create a folder styles under the root directory where all the style files will be stored. Style entry not seen as master.scss.

Then create file _app.js under folder pages and import the style file. The complete code is as follows:

import ".. /styles/master.scss"; export default function App({ Component, pageProps }) { return <Component {... pageProps} />; }Copy the code

Full repository address: github.com/QuintionTan…