reading-notes

View on GitHub

NextJs

Create a Next.js app

To create a Next.js app, open your terminal, cd into the directory you’d like to create the app in, and run the following command:

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"

Under the hood, this uses the tool called create-next-app, which bootstraps a Next.js app for you. It uses this template through the –example flag.

Run the development server

You now have a new directory called nextjs-blog. Let’s cd into it:

cd nextjs-blog

Then, run the following command:

npm run dev

This starts your Next.js app’s “development server” (more on this later) on port 3000.

Let’s check to see if it’s working. Open http://localhost:3000 from your browser.

Welcome to Next.js

You should see a page like this when you access http://localhost:3000. This is the starter template page which shows some helpful information about Next.js.

image

Editing the Page

Let’s try editing the starter page.

Create a New Page

Create the posts directory under pages.

Create a file called first-post.js inside the posts directory with the following content:

export default function FirstPost() {
  return <h1>First Post</h1>
}

The component can have any name, but you must export it as a default export.

Now, make sure that the development server is running and visit http://localhost:3000/posts/first-post. You should see the page.

When linking between pages on websites, you use the < a> HTML tag.

import Link from 'next/link'

Then find the h1 tag that looks like this:

<h1 className="title">
  Learn <a href="https://nextjs.org">Next.js!</a>
</h1>

And change it to:

<h1 className="title">
  Read{' '}
  <Link href="/posts/first-post">
    <a>this page!</a>
  </Link>
</h1>

{‘ ‘} adds an empty space, which is used to divide text over multiple lines.

Next, open pages/posts/first-post.js and replace its content with the following:

import Link from 'next/link'

export default function FirstPost() {
  return (
    <>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </>
  )
}

Code splitting and prefetching

Next.js does code splitting automatically, so each page only loads what’s necessary for that page. That means when the homepage is rendered, the code for other pages is not served initially.

This ensures that the homepage loads quickly even if you have hundreds of pages.

Only loading the code for the page you request also means that pages become isolated. If a certain page throws an error, the rest of the application would still work.

Assets

First, let’s talk about how Next.js handles static assets such as images.

Next.js can serve static files, like images, under the top-level public directory. Files inside public can be referenced from the root of the application similar to pages.

< img src="/vercel.svg" alt="Vercel Logo" className="logo" />

The logo image exists inside the public directory at the top level of your application.

Metadata

What if we wanted to modify the metadata of the page, such as the < title> HTML tag?

< title> is part of the < head> HTML tag, so let’s dive into how we can modify the < head> tag in a Next.js page.

Open pages/index.js in your editor and find the following lines:

<Head>
  <title>Create Next App</title>
  <link rel="icon" href="/favicon.ico" />
</Head>

Notice that < Head> is used instead of the lowercase < head>. < Head> is a React Component that is built into Next.js. It allows you to modify the < head> of a page.

You can import the Head component from the next/head module.

Adding Head to first-post.js

We haven’t added a < title> to our /posts/first-post route. Let’s add one.

Open the pages/posts/first-post.js file and add an import for Head from next/head at the beginning of the file:

import Head from 'next/head'

Then, update the exported FirstPost component to include the Head component. For now, we‘ll add just the title tag:

export default function FirstPost() {
  return (
    <>
      <Head>
        <title>First Post</title>
      </Head>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </>
  )
}

Try accessing http://localhost:3000/posts/first-post. The browser tab should now say “First Post”. By using your browser’s developer tools, you should see that the title tag is added to < head>.

CSS Styling

Let’s now talk about CSS styling.

As you can see, our index page (http://localhost:3000) already has some styles. If you take a look at pages/index.js, you should see code like this:

<style jsx>{`
  …
`}</style>

This page is using a library called styled-jsx. It’s a “CSS-in-JS” library — it lets you write CSS within a React component, and the CSS styles will be scoped (other components won’t be affected).

Layout Component

First, Let’s create a Layout component which will be shared across all pages.

Create a top-level directory called components.

Inside components, create a file called layout.js with the following content:

export default function Layout({ children }) {
  return <div>{children}</div>
}

Then, open pages/posts/first-post.js, add an import for the Layout component, and make it the outermost component:

import Head from 'next/head'
import Link from 'next/link'
import Layout from '../../components/layout'

export default function FirstPost() {
  return (
    <Layout>
      <Head>
        <title>First Post</title>
      </Head>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </Layout>
  )
}

Adding CSS

Now, let’s add some styles to the Layout component. To do so, we’ll use CSS Modules, which lets you import CSS files in a React component.

Create a file called components/layout.module.css with the following content:

.container {
  max-width: 36rem;
  padding: 0 1rem;
  margin: 3rem auto 6rem;
}

Important: To use CSS Modules, the CSS file name must end with .module.css.

To use this container class inside components/layout.js, you need to:

Import the CSS file and assign a name to it, like styles

Use styles.container as the className

Open components/layout.js and replace its content with the following:

import styles from './layout.module.css'

export default function Layout({ children }) {
  return <div className={styles.container}>{children}</div>
}

If you go to http://localhost:3000/posts/first-post now, you should see that the text is now inside a centered container.

Global Styles

CSS Modules are useful for component-level styles. But if you want some CSS to be loaded by every page, Next.js has support for that as well.

To load global CSS files, create a file called pages/_app.js with the following content:

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

This App component is the top-level component which will be common across all the different pages. You can use this App component to keep state when navigating between pages, for example.

Restart the Development Server

Important: You need to restart the development server when you add pages/_app.js. Press Ctrl + c to stop the server and run:

npm run dev

Adding Global CSS

In Next.js, you can add global CSS files by importing them from pages/_app.js. You cannot import global CSS anywhere else.

The reason that global CSS can’t be imported outside of pages/_app.js is that global CSS affects all elements on the page.

If you were to navigate from the homepage to the /posts/first-post page, global styles from the homepage would affect /posts/first-post unintentionally.

You can place the global CSS file anywhere and use any name. So let’s do the following:

a { color: #0070f3; text-decoration: none; }

a:hover { text-decoration: underline; }

img { max-width: 100%; display: block; }

### Finally, open pages/_app.js add import the CSS file like so:
```js
import '../styles/global.css'

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Polishing Layout

So far, we’ve only added minimal React and CSS code just to illustrate concepts such as CSS Modules. Before we move on to our next lesson about data fetching, let’s polish our page styling and code.

Download Your Profile Picture

First, we’ll be using your profile picture for the final design.

.header { display: flex; flex-direction: column; align-items: center; }

.headerImage { width: 6rem; height: 6rem; }

.headerHomeImage { width: 8rem; height: 8rem; }

.backToHome { margin: 3rem 0 0; }

## Create styles/utils.module.css
### Third, let’s create a set of utility CSS classes for typography and others that will be useful across multiple components.

### Let’s add a new CSS file called styles/utils.module.css with the following content:
```css
.heading2Xl {
  font-size: 2.5rem;
  line-height: 1.2;
  font-weight: 800;
  letter-spacing: -0.05rem;
  margin: 1rem 0;
}

.headingXl {
  font-size: 2rem;
  line-height: 1.3;
  font-weight: 800;
  letter-spacing: -0.05rem;
  margin: 1rem 0;
}

.headingLg {
  font-size: 1.5rem;
  line-height: 1.4;
  margin: 1rem 0;
}

.headingMd {
  font-size: 1.2rem;
  line-height: 1.5;
}

.borderCircle {
  border-radius: 9999px;
}

.colorInherit {
  color: inherit;
}

.padding1px {
  padding-top: 1px;
}

.list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.listItem {
  margin: 0 0 1.25rem;
}

.lightText {
  color: #999;
}

Update components/layout.js

Fourth, open components/layout.js and replace its content with the following code, change Your Name at the top to your name:

import Head from 'next/head'
import styles from './layout.module.css'
import utilStyles from '../styles/utils.module.css'
import Link from 'next/link'

const name = 'Your Name'
export const siteTitle = 'Next.js Sample Website'

export default function Layout({ children, home }) {
  return (
    <div className={styles.container}>
      <Head>
        <link rel="icon" href="/favicon.ico" />
        <meta
          name="description"
          content="Learn how to build a personal website using Next.js"
        />
        <meta
          property="og:image"
          content={`https://og-image.now.sh/${encodeURI(
            siteTitle
          )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`}
        />
        <meta name="og:title" content={siteTitle} />
        <meta name="twitter:card" content="summary_large_image" />
      </Head>
      <header className={styles.header}>
        {home ? (
          <>
            <img
              src="/images/profile.jpg"
              className={`${styles.headerHomeImage} ${utilStyles.borderCircle}`}
              alt={name}
            />
            <h1 className={utilStyles.heading2Xl}>{name}</h1>
          </>
        ) : (
          <>
            <Link href="/">
              <a>
                <img
                  src="/images/profile.jpg"
                  className={`${styles.headerImage} ${utilStyles.borderCircle}`}
                  alt={name}
                />
              </a>
            </Link>
            <h2 className={utilStyles.headingLg}>
              <Link href="/">
                <a className={utilStyles.colorInherit}>{name}</a>
              </Link>
            </h2>
          </>
        )}
      </header>
      <main>{children}</main>
      {!home && (
        <div className={styles.backToHome}>
          <Link href="/">
            <a> Back to home</a>
          </Link>
        </div>
      )}
    </div>
  )
}

Here’s what’s new:

Open pages/index.js and replace its content with:

import Head from 'next/head'
import Layout, { siteTitle } from '../components/layout'
import utilStyles from '../styles/utils.module.css'

export default function Home() {
  return (
    <Layout home>
      <Head>
        <title>{siteTitle}</title>
      </Head>
      <section className={utilStyles.headingMd}>
        <p>[Your Self Introduction]</p>
        <p>
          (This is a sample website - youll be building a site like this on{' '}
          <a href="https://nextjs.org/learn">our Next.js tutorial</a>.)
        </p>
      </section>
    </Layout>
  )
}

Then replace [Your Self Introduction] with your self introduction.