Let’s start by reviewing how we moved from server-side rendering using PHP/JSP to client-side rendering with separate front and back ends, and why we moved back to server-side rendering. In fact, it is not accurate to call next.js/nust. Js as SSR (Server Side Render), which should be Isomorphic Render. Server Side Render is not a complex technology, and Server rendering and Server isomorphism are two different concepts, the key lies in: isomorphism.
-
Server-side rendering: The rendering process is completed on the server side, and the final rendering HTML page is sent to the client through HTTP protocol. As far as the client is concerned, you just see the final HTML page, no data, no template.
-
Client-side rendering: The server sends the template and data to the client, where the rendering process is completed.
Why isomorphism?
Usually isomorphic rendering is mainly for:
- Conducive to SEO search engine collection
- Speed up first screen display time
- At the same time
Single page (SPA)
andMultipage routing
User experience
Front-end isomorphism is having a set of javascript code running on both the server and the client
Why a modern front-end isomorphic framework?
Modern front-end frameworks (React, Vue, Angular) all have server-side rendering apis. Why do we need a homogeneous framework? The reason is that for a normal isomorphic requirement, we need:
- Front-end components render as HTML strings, streams
- The loading of server and client resources is handled differently. (The first screen may not load all JS…)
- Server, client state data transfer
- Pack tool chain
- Performance optimization
- …
The React SSR API has only four functions: RenderToString (), renderToStaticMarkup(), renderToNodeStream(), and renderToStaticNodeStream() (Vue is similar) can only meet the first requirement, we need more, The front-end isomorphic framework represented by Next. Js can not only meet the above basic requirements, but also bring us:
- Excellent development experience, do the same as development SPA, (yes this is the first important, otherwise it is better to choose traditional template rendering scheme)
- The first server rendering is extremely efficient and requires as little JS as possible.
- Later client rendering can make the best use of the data brought down by the server.
- Convenient Static Site Generation (SSG) support.
- Support the TypeScript
- …
In other words, make development more dynamic and flexible, and render more statically efficient. Here’s an example:
- In CMS systems such as WordPress, dynamic requirements are easy to meet, but static cache optimization is difficult to achieve.
- Hexo, for example, renders the page completely static (landing as a file), but the need to be a little more dynamic is almost impossible.
Among themNext.jsIt can be said that the front isomorphism in the mountains, the leader level framework, dependentReactRender component. Of course the VueNuxt.js, presents aAngular Universal.Next. Js is highly recommended before we startThe official documentationIt’s very clear and easy to understand. Next, jsThe official Blog, is also highly recommended, each version of the update detailed and timely, exemplary.The official makingThere are also nearly 100 cases, you can follow the official documents step by step, you can quickly learn.
This article will blog system as an example, does not involve principle, record the development process.
Create a project
yarn create next-app next-start
cd next-start
yarn dev
Copy the code
At this time visit http://localhost:3000, my next project has been successfully created, the first step to create the project will be slow, you can first set the NPM mirror source as taobao’s NPM source
npm config set registry https://registry.npm.taobao.org
Copy the code
typescript
If you want to use typescript, you can create a tsconfig.json file by executing TSC –init in the root directory. Yarn Dev will prompt you to install the TS dependencies
yarn add --dev typescript @types/react @types/node
Copy the code
Try starting the development server again. After starting the server, next.js will:
- Populate the tsconfig.json file for you. You can also customize this file.
- Create a next-env.d.ts file to ensure that the TypeScript compiler selects the correct next-.js types.
Routing based on file path
page
The general front-end Web application can be simplified into two parts, routing based page and API interface. Next’s routing system is automatically mapped based on file paths and does not require neutral configuration. This is convention over configuration.
It is generally agreed to be in the root directory pages folder:
./pages/index.tsx
— > home page/
./pages/admin/index.tsx
–>/admin
./pages/admin/post.tsx
–>/admin/post
The React component is exported by default, and Next will generate the routing page for you by default.
- You don’t have to worry about how resources are configured to load in head
- You can use CSS-in-JS, CSS Module, less, SASS, and so on, just like a SPA application
import
Way.
Navigation between pages
import Link from 'next/link'
function Home() {
return (
<ul>
<li>
<Link href="/about">
<a>About Us</a>
</Link>
</li>
</ul>)}export default Home
Copy the code
Note that it is best to wrap the A element separately in Link.
To increase the Head
import Head from 'next/head'
function About() {
return (
<div>
<Head>
<title>Hipo Log - {props.post? .name ?? ''}</title>
</Head>
content
</div>
);
}
export default About
Copy the code
Dynamic import code split
Next also supports ES2020’s Dynamic Import () syntax, which can be used to split code or to elaborate server-side rendering when some third-party components rely on browser apis (SSR: false)
import dynamic from 'next/dynamic'
const DynamicComponentWithCustomLoading = dynamic(
() = > import('.. /components/hello'),
{
loading: () = > <p>.</p>,
ssr: false})function Home() {
return (
<div>
<Header />
<DynamicComponentWithCustomLoading />
<p>HOME PAGE is here!</p>
</div>)}export default Home
Copy the code
👉 Note: be careful in page code import code!!
The more hooks are introduced, the more JS will be loaded after the online access, especially the following hook functions should be careful not to introduce extra code
API
The API type routing convention is in the./pages/ API folder, and next is automatically mapped to the API of the/API /* path
import { NextApiRequest, NextApiResponse } from 'next'
export default (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ name: 'John Doe'})}Copy the code
The request method is retrieved from the REQ.
This way you can easily generate an API.
Dynamic routing
Normal applications, there are dynamic routing, next clever use of file naming way to support.
./pages/post/create.js --> /post/create
/pages/post/[pid].js --> /post/1, /post/ ABC, etc., but will not match /post/create
. / pages/post/slug [...] js - > / post / 1/2, / post/a/b/c, but not match/post/create, / post/ABC
Query ({pid}, {slug: [‘a’, ‘b’]}). Router hook
import { useRouter } from 'next/router';
function About() {
const router = useRouter();
const { bID, pID } = router.query
return <div>About</div>
}
Copy the code
Page SSR hooks and SSG
Most of the application content is not purely static, we need data query to render that page, and this needs to be satisfied by the homogeneous hook functions, with these hook functions, we can make a great experience of the web application under different requirements.
getServerSideProps
(SSR) Request data on each visit
Export an async getServerSideProps method, which next calls on the server side on each request.
- Methods are only run on the server, once per request
getServerSideProps
methods - If the page through the browser side
Link
As the component navigates in, Next makes a request to the server and runs it on the servergetServerSideProps
Method, and return JSON to the browser.
👉getServerSideProps
Methods are mostly pre-9.3 upgradesgetInitialProps
methods
A major drawback of the pre-9.3 getInitialProps method is that the req and RES objects will be undefined in the browser. The page that uses it, if it’s a browser rendering you need to explicitly request it again within the component. The development experience was not great. If there are no special problems, it is recommended to use getServerSideProps instead of the getInitialProps method.
Example:
import { GetServerSideProps, NextPage } from 'next'
interface PostProps {
list: Post[]
}
const App: NextPage<PostProps> = props= > {
return <div></div>
}
export const getServerSideProps: GetServerSideProps<PostProps> = async context => {
const list = await context.req.service.post.getPost(context.params.postID)
return {
props: {
list
}
}
}
export default App
Copy the code
getStaticProps
andgetStaticPaths
(SSG) Request data at build time
SSG stands for static site generation, and things like Hexo or GatsbyJS build pages into static HTML files at build stage, allowing direct online access to HTML files for high performance.
In 9.0, next.js introduced automatic static optimization, which means that if a page doesn’t use the getServerSideProps and getInitialProps methods, Next generates HTML during the build phase to improve performance.
However, as mentioned above, application pages require dynamic content, so automatic static optimization is very limited.
Next went a step further in 9.3, introducing the getStaticProps and getStaticPaths methods to let developers specify which pages can be optimized for SSG.
- use
getStaticProps
Method returns the data required for the page during the build phase. - If the page is dynamically routed, use
getStaticPaths
Method to return all the route parameters and whether a fallback mechanism is required.
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://... /posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map(post= > ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: true };
}
export const getStaticProps: GetStaticProps<InitProps> = async ({ params }) => {
const data = await fetch(
`http://... /api/p/${params.bookUUID }/${ params.postUUID }`
);
return {
props: {
post: data,
},
};
};
Copy the code
Very simple to use, note that:
-
The fallback returned by the getStaticPaths method is useful: if fallback is false, accessing routes that the method does not return would be 404
-
However, if you do not want or inconvenient to get route parameters during build phase, you can set fallback to true. Next, when accessing dynamic routes that do not appear in build phase, the browser will load first, and then the server will build the information on the page, and then return to browser rendering. The cache takes effect when the route is accessed again, powerful!!
-
Static caches cannot be updated flexibly at present!For example, if blog content changes after build or fallback takes effect, there is no way to easily replace the cache. -
After 9.5.0, the getStaticProps method could add the revalidate attribute to regenerate the cache. This is powerful: pages still load quickly, pages never go offline, and even if the regenerate fails, the old ones are still accessible, and the load on the database and server can be significantly reduced.
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>)}// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
const res = await fetch('https://... /posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every second
revalidate: 1.// In seconds}}export default Blog
Copy the code
How to choose SSR or SSG?
- If the page content is truly dynamic (for example, the source database, and changes frequently), use
getServerSideProps
Methods SSR. - SSG can be used if the page is static or pseudo-dynamic (for example, a source database, but does not change).
That’s the main part of next.js, but here are some of the customizations that might be used.
Custom App
Use./pages/_app.tsx to customize the App, configure global CSS, or the getServerSideProps method to add data to each page.
function MyApp({ Component, pageProps }) {
return <Component {. pageProps} / >
}
export default MyApp
Copy the code
The custom Document
You can use./pages/_document. TSX to customize the Document of the page, configure the page HTML, head properties, or use the renderPage method in the static getInitialProps method to include the entire React application.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>)}}export default MyDocument
<Html>`, `<Head />`, `<Main />` and `<NextScript /> are both required.Copy the code
- Used in app and Document above
getServerSideProps
orgetInitialProps
Method prevents the entire application from being automatically static optimized - The above app and Document do not execute in the browser, including the React hooks or lifecycle functions.
Custom build
The root directory uses next.config.js to configure webpack, which can be used to support less compilation, load on demand, path alias, etc.
The following configuration supports custom styles of Antd Design.
const withLess = require('@zeit/next-less')
const fs = require('fs')
const path = require('path')
const rewrites = [
{
source: '/page/:path*'.destination: ` /? pageNum=:path*`}, {source: '/post/:id/edit'.destination: `/create`,},]const lessToJS = require('less-vars-to-js')
const themeVariables =lessToJS(
fs.readFileSync(
path.resolve(__dirname, './src/styles/antd-custom.less'),
'utf8'))if(process.env.NODE_ENV ! = ='production') {
rewrites.push({
source: '/api/:path*'.destination: `http://localhost:4000/api/:path*`})},module.exports = withLess({
async rewrites() {
return rewrites
},
lessLoaderOptions: {
javascriptEnabled: true.importLoaders: 1.localIdentName: '[local]___[hash:base64:5]'.modifyVars: themeVariables, // make your antd custom effective
},
distDir: 'build'.target: 'serverless',})Copy the code
Custom service
Next also supports Node startup to work with other frameworks for more complex server-side functionality, such as using it to bind databases such as Typeorm.
/ server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
constdev = process.env.NODE_ENV ! = ='production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() = > {
createServer((req, res) = > {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/a') {
app.render(req, res, '/b', query)
} else if (pathname === '/b') {
app.render(req, res, '/a', query)
} else {
handle(req, res, parsedUrl)
}
}).listen(3000.err= > {
if (err) throw err
console.log('> Ready on http://localhost:3000')})})Copy the code
reference
zhuanlan.zhihu.com/p/130247139
www.zhihu.com/search?type…