12 KiB
next.js
Next.js
is a minimalistic framework for server-rendered React applications.
How to use
The file-system is the main API. Every .js
file becomes a route that gets automatically processed and rendered.
Populate ./pages/index.js
inside your project:
import React from 'react'
export default () => (
<div>Welcome to next.js!</div>
)
and then just run next
and go to http://localhost:3000
So far, we get:
- Automatic transpilation and bundling (with webpack and babel)
- Hot code reloading
- Server rendering and indexing of
./pages
- Static file serving.
./static/
is mapped to/static/
Bundling (code splitting)
Every import
you declare gets bundled and served with each page
import React from 'react'
import cowsay from 'cowsay-browser'
export default () => (
<pre>{ cowsay({ text: 'hi there!' }) }</pre>
)
That means pages never load unneccessary code!
CSS
We use glamor to provide a great built-in solution for CSS isolation and modularization without trading off any CSS features
import React from 'react'
import { style } from 'next/css'
export default () => (
<div className={style}>
Hello world
</div>
)
const style = style({
main: {
background: 'red',
':hover': {
background: 'gray'
}
'@media (max-width: 600px)': {
background: 'blue'
}
}
})
<head>
side effects
We expose a built-in component for appending elements to the <head>
of the page.
import React from 'react'
import Head from 'next/head'
export default () => (
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<p>Hello world!</p>
</div>
)
Lifecycle components
When you need state, lifecycle hooks or initial data population you can export a React.Component
:
import React from 'react'
export default class extends React.Component {
static async getInitialProps ({ req }) {
return req
? { userAgent: req.headers.userAgent }
: { userAgent: navigator.userAgent }
}
render () {
return <div>
Hello World {this.props.userAgent}
</div>
}
}
Routing
Client-side transitions between routes are enabled via a <Link>
component
pages/index.js
import React from 'react'
import Link from 'next/link'
export default () => (
<div>Click <Link href="/about"><a>here</a></Link> to read more</div>
)
pages/about.js
import React from 'react'
export default () => (
<p>Welcome to About!</p>
)
Client-side routing behaves exactly like the native UA:
- The component is fetched
- If it defines
getInitialProps
, data is fetched. If an error occurs,_error.js
is rendered - After 1 and 2 complete,
pushState
is performed and the new component rendered
Each top-level component receives a url
property with the following API:
path
-String
of the current path excluding the query stringquery
-Object
with the parsed query string. Defaults to{}
push(url)
- performs apushState
call associated with the current componentreplace(url)
- performs areplaceState
call associated with the current componentpushTo(url)
- performs apushState
call that renders the newurl
. This is equivalent to following a<Link>
replaceTo(url)
- performs areplaceState
call that renders the newurl
Error handling
404 or 500 errors are handled both client and server side by a default component error.js
. If you wish to override it, define a _error.js
:
import React from 'react'
export default class Error extends React.Component {
static getInitialProps ({ res, xhr }) {
const statusCode = res ? res.statusCode : xhr.status
return { statusCode }
}
render () {
return (
<p>An error { this.props.statusCode } occurred</p>
)
}
}
Production deployment
To deploy, instead of running next
, you probably want to build ahead of time. Therefore, building and starting are separate commands:
next build
next start
For example, to deploy with now
a package.json
like follows is recommended:
{
"name": "my-app",
"dependencies": {
"next": "latest"
},
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
Then run now
and enjoy!
Note: we recommend putting .next
in .npmignore
or .gitigore
. Otherwise, use files
or now.files
to opt-into a whitelist of files you want to deploy (and obviously exclude .next
)
FAQ
Is this production ready?
Next.js has been powering `https://zeit.co` since its inception.We’re ecstatic about both the developer experience and end-user performance, so we decided to share it with the community.
How big is it?
The client side next bundle, which includes React and Glamor is ${X}kb gzipped.
The Next runtime (lazy loading, routing, <Head>
) contributes ${Y}% to the size of that bundle.
The codebase is ~1500LOC (excluding CLI programs).
Is this like `create-react-app`?
Yes and No.
Yes in that both make your life easier.
No in that it enforces a structure so that we can do more advanced things like: - Server side rendering - Automatic code splitting
In addition, Next.js provides two built-in features that are critical for every single website:
- Routing with lazy component loading: <Link>
(by importing next/link
)
- A way for components to alter <head>
: <Head>
(by importing next/head
)
Next is not suitable right now for creating reusable components that every single React app can use. But we consider that a feature, since your re-usable components should live in separate repositories and then import
ed.
In the future, we might consider a next export
feature that produces a re-usable build of a component, to take advantage of Glamor and our simple and easy-to-use build system.
Why CSS-in-JS?
next/css
is powered by Glamor. While it exposes a JavaScript API, it produces regular CSS and therefore important features like :hover
, animations, media queries all work.
There’s no tradeoff in power. Instead, we gain the power of simpler composition and usage of JavaScript expressions.
Compiling regular CSS files would be counter-productive to some of our goals. Some of these are listed below.
In the future, however, we might be able to take advantage of custom elements / shadow DOM to also support the full CSS syntax once browser support is wide enough.
Compilation performance
Parsing, prefixing, modularizing and hot-code-reloading CSS can be avoided by just using JavaScript.
This results in better compilation performance and less memory usage, specially for large projects. No cssom
, postcss
, cssnext
or transformation plugins.
It also means fewer dependencies and fewer things for Next to do. Everything is Just JavaScript® (since JSX is completely optional)
Lifecycle performance
Since every class name is invoked with the css()
helper, Next.js can intelligently add or remove <style>
elements that are not being used.
This is important for server-side rendering, but also during the lifecycle of the page. Since Next.js
enables pushState
transitions that load components dynamically, unnecessary <style>
elements would bring down performance over time.
This is a very signifcant benefit over approaches like require(‘xxxxx.css')
.
Correctness
Since the class names and styles are defined as JavaScript objects, a variety of aids for correctness are much more easily enabled:
- Linting
- Type checking
- Autocompletion
While these are tractable for CSS itself, we don’t need to duplicate the efforts in tooling and libraries to accomplish them.
What syntactic features are transpiled? How do I change them?
We track V8. Since V8 has wide support for ES6 and async
and await
, we transpile those. Since V8 doesn’t support class decorators, we don’t transpile those.
See [this](link to default babel config we use) and [this](link to issue that tracks the ability to change babel options)
Why a new Router?
Next.js is special in that:
- Routes don’t need to be known ahead of time
- Routes are always be lazy-loadable
- Top-level components can define
getInitialProps
that should block the loading of the route (either when server-rendering or lazy-loading)
As a result, we were able to introduce a very simple approach to routing that consists of two pieces:
- Every top level component receives a
url
object to inspect the url or perform modifications to the history - A
<Link />
component is used to wrap elements like anchors (<a/>
) to perform client-side transitions
We tested the flexibility of the routing with some interesting scenarios. For an example, check out nextgram.
How do I define a custom fancy route?
We’re adding the ability to map between an arbitrary URL and any component by supplying a request handler: #25
On the client side, we'll add a parameter to <Link>
so that it decorates the URL differently from the URL it fetches.
How do I fetch data?
It’s up to you. getInitialProps
is an async
function (or a regular function that returns a Promise
). It can retrieve data from anywhere.
Why does it load the runtime from a CDN by default?
We intend for Next.js
to be a great starting point for any website or app, no matter how small.
If you’re building a very small mostly-content website, you still want to benefit from features like lazy-loading, a component architecture and module bundling.
But in some cases, the size of React itself would far exceed the content of the page!
For this reason we want to promote a situation where users can share the cache for the basic runtime across internet properties. The application code continues to load from your server as usual.
We are committed to providing a great uptime and levels of security for our CDN. Even so, we also automatically fall back if the CDN script fails to load with a simple trick.
To turn the CDN off, just set { “next”: { “cdn”: false } }
in package.json
.
What is this inspired by?
Many of the goals we set out to accomplish were the ones listed in The 7 principles of Rich Web Applications by Guillermo Rauch.
The ease-of-use of PHP is a great inspiration. We feel Next.js is a suitable replacement for many scenarios where you otherwise would use PHP to output HTML.
Unlike PHP, we benefit from the ES6 module system and every file exports a component or function that can be easily imported for lazy evaluation or testing.
As we were researching options for server-rendering React that didn’t involve a large number of steps, we came across react-page (now deprecated), a similar approach to Next.js by the creator of React Jordan Walke.
Future directions
The following issues are currently being explored and input from the community is appreciated:
- Support for pluggable renderers [#20]
- Style isolation through Shadow DOM or "full css support" [#22]
- Better JSX [#22]
- Custom server logic and routing [#25]
- Custom babel config [#26]
- Custom webpack config [#40]
Authors
- Naoyuki Kanezawa (@nkzawa) – ▲ZEIT
- Tony Kovanen (@rase-) – ▲ZEIT
- Guillermo Rauch (@rauchg) – ▲ZEIT
- Dan Zajdband (@impronunciable) – Knight-Mozilla / Coral Project