Let’s talk about why we built this tool in the first place. Recently, I have learned Typescript and React server rendering respectively. However, due to the lack of practical application scenarios, I suddenly thought of combining Typescript and Next to build a server rendering tool. First, it can play a good role in practice. Second, if there is a corresponding business demand in the future, it can be directly used. Without further ado, let’s begin!

Next characteristics

As a lightweight application framework, next. Js is mainly used to build static websites and back-end rendering websites. Why next? Because Next has several advantages:

  1. Use backend rendering
  2. Automatic code splitting to get faster page loading
  3. Concise front-end routing implementation
  4. Build with WebPack, support for Hot Module Replacement
  5. Connects to mainstream Node servers (such as Express)
  6. You can customize the configuration of Babel and Webpack

Create and initialize the project

I won’t say much here, I believe you are very skilled

mkdir TAN
cd TAN
npm init -y
Copy the code

Install the React

  1. Install dependencies like react and react-dom
npm install react react-dom express next --save
npm install @types/{react,react-dom} --save-dev
Copy the code
  1. Create a new pages folder in the root directory (be sure to name it pages, as is mandatory for next, otherwise pages won’t be found) and create index.js
export default() = ><div>Welcome to next.js!</div>
Copy the code
  1. Add the following script to package.json to start the project
{..."scripts": {
    "dev": "next"}... }Copy the code

To view the initial page, run the NPM run dev command to open http://localhost:3000.

Configuration Typescript

  1. Install the Typescript
npm install typescript --save
Copy the code

@zeit/ Next-typescript is no longer needed because Next-.js has built-in support for typescript

  1. Create.babelrc in the root directory and type the following code
{
  "presets": [
    "next/babel"]}Copy the code
  1. Create tsconfig.json in the root directory and enter the following code
{
  "compileOnSave": false."compilerOptions": {
    "strict": true."target": "esnext"."module": "esnext"."jsx": "preserve"."allowJs": true."moduleResolution": "node"."allowSyntheticDefaultImports": true."experimentalDecorators": true."noUnusedLocals": true."noUnusedParameters": true."removeComments": false."preserveConstEnums": true."sourceMap": true."skipLibCheck": true."baseUrl": "."."typeRoots": [
      "./node_modules/@types/",]."lib": [
      "dom"."es2015"."es2016"]},"exclude": ["node_modules"]}Copy the code

In the above configuration, please note: use “JSX” : “preserve” instead of React-native, since next.js supported.jsx file extensions after 5.0.0, which previously only recognized.js files.

  1. Tslint. json was introduced to help us standardize the style of writing ts with some constraints.
{
    "extends": ["tslint:latest"]."rules": {
      "arrow-parens": false."interface-name": [true."never-prefix"]."no-object-literal-type-assertion": false."no-submodule-imports": false."semicolon": [true."never"]."trailing-comma": [true, {"multiline": "nerver"."singleline": "never"}}}]Copy the code

Change page/index.js to index.tsx and make the following changes

interface Person {
    name: String;
}
const Rashomon: Person = {
    name: 'rashomon',}export default() = ><div>{Rashomon.name}!</div>
Copy the code
  1. Create server.js in the root directory. The server.js file can be used as the entry file to start the user-defined service.
const next = require('next');
const { createServer } = require('http');
const { parse } = require('url')
constdev = process.env.NODE_ENV ! = ='production';
const port = parseInt(process.env.PORT, 10) | |3000;
const app = next({dev})
const handle = app.getRequestHandler()

app.prepare().then((a)= > {
    createServer((req, res) = > {
      const parsedUrl = parse(req.url, true)
      handle(req, res, parsedUrl)
    }).listen(port, err => {
        console.log(err, port)
      if (err) throw err
      console.log(`> Ready on http://localhost:${port}`)})})Copy the code

Change package.json startup command “dev”: “Nodeserver. js”, run NPM run dev, you will see a line error: It looks like you’re trying to use TypeScript but do not have the required package(s) installed. This means trying to use TypeScript but not having the required packages installed. We simply run the following command

npm install --save-dev @types/node
Copy the code

Run the command again to open http://localhost:3000 to see our page.

The introduction of antd

  1. Install ANTD and the babel-plugin-import implementation to load on demand
npm install antd --save
npm install babel-plugin-import --save-dev
Copy the code
  1. Modify the. Babelrc file
{
    "presets": [
      "next/babel"]."plugins": [["import", { "libraryName": "antd"."style": false}}]]Copy the code

The introduction of Less

  1. Install less, @zeit/next-less dependencies
npm install less @zeit/next-less null-loader --save 
Copy the code
  1. Create next. Config. js in the root directory and type the following code
const withLess = require('@zeit/next-less');

module.exports = withLess({
  lessLoaderOptions: {
    javascriptEnabled: true,},webpack: (config, { isServer }) = > {
    if (isServer) {
      const antStyles = /antd\/.*? \/style.*? /
      const origExternals = [...config.externals]
      config.externals = [
        (context, request, callback) = > {
          if (request.match(antStyles)) return callback()
          if (typeof origExternals[0= = ='function') {
            origExternals[0](context, request, callback)
          } else{ callback() } }, ... (typeof origExternals[0= = ='function' ? [] : origExternals),
      ]

      config.module.rules.unshift({
        test: antStyles,
        use: 'null-loader'})},return config
  },
})
Copy the code

Create a new index.less file in the page folder and add antD to the index.tsx file.

@import '~antd/dist/antd.less';
Copy the code

Make the following changes in index. TSX

import {Button} from 'antd';
import './index.less'
interface Person {
    name: String;
}
const Rashomon: Person = {
    name: 'rashomon',}export default() = ><Button type='primary'>{Rashomon.name}!</Button>
Copy the code
  1. To use a custom ANTD theme, for example, let’s change the theme color of ANTD and install less-vars-to-js
npm install less-vars-to-js --save
Copy the code

Create the assets file in the root directory and create antd-custom.less

@primary-color: #08979c;
Copy the code

The style file is read in next.config.js, the contents of the less file are received as a string through less-vars-to-js, and an object containing all the variables is returned. Next.config.js adds the following:

.// Add content
const lessToJS = require('less-vars-to-js');
const fs = require('fs');
const path = require('path');

// Where your antd-custom.less file lives
const themeVariables = lessToJS(
  fs.readFileSync(path.resolve(__dirname, './assets/antd-custom.less'), 'utf8'))... lessLoaderOptions: {javascriptEnabled: true.modifyVars: themeVariables,},...Copy the code

Run the startup command, and the page is as follows:

The introduction of story

  1. Install Redux and redux-Saga. Redux-saga was introduced to handle asynchronous request operations
npm install redux react-redux next-redux-wrapper @types/react-redux --save
npm install redux-saga next-redux-saga @types/next-redux-saga --save
Copy the code

Due to space limitation, the process of creating store, reducers, saga and Action will not be described here. If you are interested, you can check the code on Github. In order to import store when the page is initialized, we need to customize it. In the Pages folder, we create _app.tsx._app.tsx to do the following:

  • Control page initialization
  • Keep the page layout as it changes
  • Keep the page state when the route changes
  • Custom handling errors using componentDidCatch
  • Inject additional data into the page (such as GraphQL queries)

Therefore, create _app. TSX under the Pages file and introduce store, as shown below

import React from 'react'
import App from 'next/app';
import { Provider } from 'react-redux';
import Head from 'next/head'
import withRedux from 'next-redux-wrapper'
import withReduxSaga from 'next-redux-saga'
import Layout from '.. /components/Layout' // Page base layout
import initStore from '.. /redux/store'  // store
import '.. /static/style/index.less' / / antd style

class MyApp extends App {
    // next. Js provides a standard interface for getting remote data :getInitialProps. With getInitialProps, we can get remote data and assign it to the props of the page.
    // getInitialProps can be used on both the server and the front end
    static async getInitialProps({ Component, ctx }: any) {
        let pageProps = {};
        if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps({ ctx });
        }
        return { pageProps };
    }
    render() {
        const { Component, pageProps, store }: any = this.props
        return (
            <Provider store={store}>
                <Head>
                    <title>Tarn</title>
                </Head>
                <Layout>
                    <Component {. pageProps} / >
                </Layout>
            </Provider>
        )
    }
}
export default withRedux(initStore)(withReduxSaga(MyApp))
Copy the code

Finally achieve a counter and list, as shown below:


Custom error handling

404 and 500 errors are handled by the error.js component on both the client and server sides. If you want to override it, create _error.js in the pages file so that the _error page is accessed when the user accesses the wrong route

import React from 'react'
export default class Error extends React.Component {
  static getInitialProps({ res, err }) {
    const statusCode = res ? res.statusCode : err ? err.statusCode : null;
    return { statusCode }
  }
  render() {
    return (
      <p>
        {this.props.statusCode
          ? `An error ${this.props.statusCode} occurred on server`
          : 'An error occurred on client'}
      </p>
    )
  }
}
Copy the code

conclusion

So far, we have basically implemented a server-side rendering framework based on Typescript+ ant-Design + Redux+ Next-.js. We are also familiar with some of the uses of Next. If you want to learn more about Next, you can visit the website at Next-.js. We hope that you can gain, want to learn more about different technologies to implement server-side rendering framework students can see here github.com/zeit/next.j…

The last

GitHub if there are omissions, please correct!!

If feel helpful to you! Please don’t forget to like or follow! Your attention will be my motivation to move forward! Rush duck!!

“Fearless front end” updates the community excellent technical articles from time to time!