Learning Next.js
Two days have passed since I started building this website on Next.js
and I'm very surprised about what I have been able to achieve in so little time:
- Server Side Rendering
- Code splitting
- Isolated styles components, as well as just one place to manage global styling
- Theming
- Test driven development with
Jest
- Incredibly fast and responsive development workflow
We will discuss some of this points in the post and I will discuss others in future posts, but let me first explain you a bit better about how is this site built.
In this git repository I keep the code for the whole app, and using GitHub as my database, I'm using issues to store the blog posts, which are then retrieved and rendered as HTML. I enjoy writing posts in Markdown, and I'm getting a comments system for free, but I haven't yet implemented this.
So, getting started, Next.js
is built upon a very simple premise that you might find familiar if you used to build websites in the 90's, and resumes basically to this:
Your file system is your routing system
Taking this into account, my project structure looks like this:
.
├── components
├── config.js
├── lib
├── node_modules
├── package.json
├── pages
├── providers
├── routes.js
├── server.js
├── static
└── yarn.lock
But pay especial attention to the pages
folder, this is actually the only thing Next.js
enforces to start a new project, you need this folder. Mine looks like the following:
.
├── pages
│ ├── changelog.js
│ ├── index.js
│ ├── photos.js
│ ├── post.js
│ └── work.js
This leads to the first point in the top list on this post, server side rendering. Every file inside the pages
folder is mapped to an URL
in your app. The only requirement in this file is to export a React
component. It might be a class extending React
's Component
or as well a stateless component.
Let's check the code inside index.js
// external
import React from "react";
// internal
import Page from "../components/Page";
import Title from "../components/Title";
import Subtitle from "../components/Subtitle";
import Chart from "../components/Chart";
import { dark } from "../lib/themes";
import { ThemeProvider } from "../providers/Theme";
const Index = () => (
<ThemeProvider theme={dark}>
<Page title="analogic.al">
<section className="intro">
<Title>Hello!</Title>
{/* Omitting the rest of code here for brevity */}
</section>
<section className="grid charts">
<Chart
title={"Methodologies"}
data={[
{ label: "Kanban", value: 50 },
{ label: "Scrum", value: 30 },
{ label: "Waterfall", value: 20 }
]}
/>
{/* Omitting the rest of code here for brevity */}
</section>
</Page>
</ThemeProvider>
);
export default Index;
Do not care much about the inner components, but just pay attention to the default export Index
, which is just a stateless component.
Go ahead and try for yourself!
npm init
npm install react react-dom next
Create a pages
folder, with an index.js
file that exports some React
component:
export default () => <h1>Hello world</h1>
That's it, run $(npm bin)/next
from your console, go to your browser, hit http://localhost:3000/
and you will see a server side rendered home page.
Neat!
Code splitting
But wait, this leads to the second topic in the list: code splitting. For those who might not know, code splitting is a technique to reduce the amount of code that needs to be delivered to the client in order to render the resource they have requested for.
Simply put, your app might have a blog, a login page and maybe and admin dashboard to manage the posts. We can suppose that users hitting the /blog
endpoint of your app, are interested primarily in reading your articles, so there is no need for you to deliver code that belongs to the admin dashboard or login page, that's why we split the bundles into chunks containing all necessary code to render just one resource, like the blog, for example.
All of this comes out of the box with Next.js
by the simple fact that you are organizing your app into pages. So every page already has everything it needs to render itself. When navigating to another page, new chunks belonging to the requested resource will be downloaded on the fly in order to render.
But now, let's imagine that you hit /login
page, you are probably planning to login and manage your blog posts or comments. Next.js
is smart enough to let you make predictions about the next resources your users will ask for, so in this case you are able to download them in advance using a nice little feature of the next/Link
component.
By adding the property prefetch
to Link
, Next.js
will prefetch this page chunk in advance, so in our previous scenario, by the time you finish writing your username and password on the login form and hit the login button, the code needed to render the admin dashboard has probably already been downloaded, providing a seamless experience.
So go ahead and modify your index.js
file to look like this:
import Link from "next/Link";
export default () => <div>
<h1>Hello world</h1>
<Link href="/about" prefetch><a>About</a></Link>
</div>;
And create the new about.js
page:
import Link from "next/Link";
export default () => <div>
<h1>About</h1>
<Link href="/"><a>Back to home</a></Link>
</div>;
The prefetch
function only works in production mode, so this time, run a build using $(npm bin)/next build
and then $(npm bin)/next start
, go to your home page, and check the Network tab inside Chrome developer tools when you refresh the index page. Luckily you will see the about page chunk being downloaded before hand.
Now, sitting on the about page, hit refresh, and notice that since we didn't add prefetch
to the Link
, the home page chunk will not be downloaded in this case.
That's enough for this post already, but I plan to keep writing about my adventures with Next.js
, I hope this encourages you a little bit to start experimenting yourself.
Happy hacking!