1. Next. Introduction of js

[The React Framework for Production] Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

The bottom line is that Next. Js gives you the best experience in both production and development environments, out of the box, without any configuration

2. Why choose next.js

Dude, what’s going on, isn’t Vue enough, what’s with this stuff, vuepress writing a static blog site? Xiang, it’s simpler than that, but allow me to finish this Next. Js

2.1 What are the advantages of Next. Js?

  • Image optimization
  • Support internationalization
  • Zero configuration
  • Supports SSG + SSR
  • File system Routing
  • Too many advantages…

2.2 How is Next. Js different from the single page created by Vue and React?

  1. Vue and React created a single page application called SEO, which is not friendly. Search engines can’t capture HTML content, it’s all in JS
  2. The first blank screen of a single page created by Vue and React was too long. Without special optimization of the project Webpack, the bundle.js was very large, which seriously affected the experience

Conclusion: If the project has high SEO requirements, I suggest Next or Nuxt

2.3 What is the difference between Next-js and traditional PHP and JSP?

Simple to understand

  1. Client-side rendering

The front and back ends are separated to interact with data via Ajax, as vUE and React do

  1. Server side template rendering

PHP and JSP parse the template file, render the data to the file, and finally turn the template file into HTML, which is returned to the browser. The front and back ends do not have the same set of code

  1. Isomorphic rendering of front and back ends

The server also generates the HTML and returns it to the browser. The difference is that the front and back end share some component code logic, which can be used by both the server and the client, while the template rendering is two sets of code

3. Next. Js main API to get started quickly

Note: Node.js starts with version 12.22.0

3.1 the use ofcreate-next-appScaffold creation project

npx create-next-app@latest
# or
yarn create next-app
Copy the code

3.2 Project directory structure

│ ├─ Pages # ├.eslintrc.json │ ├.gitignore │ next │ package.json │ md │ yarn │ ├─ ├─ ├─ ├─public # ├─ favicon Globals.css # global style home.module.cssCopy the code

3.3 the routing

  1. File system Routing
  • /pages/index.jsPath for/
  • /pages/posts/about.jsPath for/posts/about
  • /pages/posts/[id].jsThe dynamic path is/posts/fooor/posts/bar, etc.
  1. Link component

The Link component automatically performs prefetch preloading

import Link from "next/link";

export default function Home() {
  return (
    <Link href="/posts/about">
      <a>about page</a>
    </Link>
  );
}

// If the a tag is not used, pass the example
<Link
  href={{
    pathname: "/about".query: { name: "test" },
  }}
  passHref
>
  <p>about page</p>
</Link>;
Copy the code
  1. useRouter
import { useRouter } from "next/router";
import { useCallback, useEffect } from 'react';

export default List() {
  const router = useRouter();

  const gotoDetail = useCallback((data) = > {
    const { fileName: detailid } = data;

    // https://www.nextjs.cn/docs/api-reference/next/router#with-url-object
    router.push({
      pathname: "/posts/[detailid]".query: { detailid, }, }); } []); useEffect(() = > {
    // Prefetch the dashboard page
    router.prefetch('/dashboard'); } []);return (
    <div>.</div>)}Copy the code
  1. Dynamic routing

/pages/posts/[id].js

import { getAllPostIds, getPostData } from "@/lib/posts";

export async function getStaticPaths() {
  const allListData = await getAllPostIds();
  const paths = allListData.map((item) = > {
    return {
      params: { id: item.fileName },
    };
  });

  return {
    paths,
    fallback: false}; }export async function getStaticProps({ params }) {
  const postData = await getPostData(params.id);

  return {
    props: {
      postData,
    },
  };
}

export default function List({ postData }) {
  // ...
}
Copy the code

3.4 the Head component

Use to customize the content of the HEAD tag

import Head from "next/head";

export default function Layout({ children }) {
  return (
    <div>
      <Head>
        <meta charSet="UTF-8" />
        <meta
          name="viewport"
          content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1.0, user - scalable = 0"
        />
        <meta name="keywords" content="Next.js" />
        <meta name="description" content="Next.js" />
        <title>Next.js</title>
      </Head>
      <main>{children}</main>
    </div>
  );
}
Copy the code

3.5 the Image components

With the right attributes, you can dramatically optimize images and improve page rendering

import Image from "next/image";

export default function MyImg() {
  return (
    <Image
      className={styles.homeBgImg}
      src={bgImg}
      layout="fill"
      objectFit="cover"
      objectPosition="center"
      quality={65}
      priority={true}
      placeholder="blur"
      blurDataURL={DEFAULT_BASE64}
      alt="img"
    />
  );
}
Copy the code

3.6 the Script component

import Script from "next/script";

export default function Home() {
  return (
    <>
      <Script
        src="https://Jquery.js"
        onLoad={()= > {
          $.ajax({
            // ...}); }} / > < / a >
  );
}
Copy the code

3.7 CSS

  1. CSS Modules (built-in)
  2. Sass (built in)
  3. Styled – JSX (built in)
  4. Styled – Components (self-styled)
  5. Tailwind CSS (self-configured)

3.8 3 basic renderings of next.js

  1. Client-side Rendering

This is the common separation of the front and back ends

import useSWR from "swr";

const fetcher = (url) = > fetch(url).then((res) = > res.json());

function Profile() {
  const { data, error } = useSWR("/api/user", fetcher);

  if (error) return <div>failed to load</div>;
  if(! data)return <div>loading...</div>;
  return <div>hello {data.name}!</div>;
}
Copy the code
  1. Static Generation (Recommended)

It typically presents static, fixed data that is generated directly when packaged, such as blog pages, fixed marketing pages, help documents, etc

import { getAllPostIds } from "@/lib/posts";

export async function getStaticProps() {
  const allListData = await getAllPostIds();

  return {
    props: {
      allListData,
    },
  };
}

export default function List({ allListData }) {
  // ...
}
Copy the code
  1. Server-side Rendering

    Dynamic data is the main data, each request is executed on the server, the server pressure is relatively large

export async function getServerSideProps(context) {
  return {
    props: {
      list: [...]. }}}export default function List({ list }) {
  // ...
}
Copy the code

Deployment of 4.

4.1 Rapid Deployment with Vercel

Use your Github account to register and log in to Vercel’s official website and authorize access to the repository for rapid deployment. You can also see the deployment logs.

4.2 Deploying ebackup on its Own Server

4.2.1 Make the Docker image on the server and then deploy it

Centos is used as an example

Step 1: Dockerfile file
  1. Use the Next. Js official Dockerfile

Note: If you use the official Dockerfile, such as the deployment on Alicloud, you will encounter network problems, and some packages will be slow to download, just like if you visit github’s official website locally, so you need to set up the domestic image download, the speed will be faster

# Install dependencies only when needed FROM node:alpine AS deps # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. RUN apk add --no-cache libc6-compat WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile # Rebuild the source code only when needed FROM node:alpine AS builder WORKDIR /app COPY . . COPY --from=deps /app/node_modules ./node_modules RUN yarn build && yarn install --production --ignore-scripts --prefer-offline # Production image, copy all the files and run next FROM node:alpine AS runner WORKDIR /app ENV NODE_ENV production RUN addgroup -g 1001 -S nodejs RUN adduser -S nextjs -u 1001 # You only need to copy next.config.js if you are NOT using the default configuration # COPY --from=builder /app/next.config.js ./ COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json USER nextjs EXPOSE 3000 ENV PORT 3000 # Next.js collects completely anonymous telemetry  data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry. # ENV NEXT_TELEMETRY_DISABLED 1 CMD ["node_modules/.bin/next", "start"]Copy the code
  1. Use your own Dockerfile

Here Docker can be built in multiple stages to make the packaged image smaller

# 1. Build the base imageThe FROM alpine: 3.15 AS the base# Pure mirror

ENV NODE_ENV=production \
  APP_PATH=/app

WORKDIR $APP_PATH

# Use a domestic image to speed up the installation of Alpine instability by downloading the following APK add
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

Install nodejs and YARN using the apk command
RUN apk add --no-cache --update nodejs=16.13.1-r0 yarn=1.22.17-r0

# 2. Install project dependencies based on the base image
FROM base AS install

COPY package.json yarn.lock ./

RUN yarn install

# 3. Final build based on the base image
FROM base

Copy the node_modules folder to the final working directory
COPY --from=install $APP_PATH/node_modules ./node_modules

Copy all files in the current directory (except those excluded by.dockerignore) to the working directory
COPY . .

RUN yarn build

EXPOSE 3000

CMD ["yarn"."start"]
Copy the code
Step 2: Get the source code to the server
  1. usescpCommand to manually upload the local source code to the server
scp -r local_dir [email protected]:remote_dir
Copy the code
  1. Or on a remote serverwgetDownload the Github source and unzip it
wget https://github.com/xxx/main.zip -O main.zip && unzip main.zip -d .
Copy the code
  1. usexshellThe tool uploads files to the server

The preceding three methods can transfer local files to the corresponding directory on the server

Step 3: Docker image creation

The premise is that docker is installed and started

# Switch all source directory execution
docker image build -t blog-demo .
Copy the code

You will then see that the image creation process is in progress on the command line, and if it works, it is successful

# Not surprisingly, you can see the image you just made
docker image ls
Copy the code
Step 4: Start the container

Security groups must be enabled on the server

Docker container run -d -p 80:3000 -it blog-demo # -d: run container # -p: open port of the local server, 3000: exposed port of the container # --name: name the containerCopy the code

Without accident, the container runs successfully. You can now access it in your browser.

4.2.2 usegithub actionsAutomatic deployment

The above manual steps are too cumbersome, need to free hands

Here you can also choose DockerHub, registered, create a warehouse, you can push. Ali cloud’s mirror container service also needs to be opened and prepared in advance (namespace + private warehouse).

Step 1: Prepare in advance
  • Container login account + password
  • HOST, login account, and password of the server
  • Ali Cloud or DockerHub’s image container warehouse
Step 2: Github The repository Settings->Secrets add the secret keys, which are the 5 prepared above

What I bought here is the diaosi 1 core 2G machine of Ali Cloud. Don’t play like this in the production environment, the account password may be leaked

Step 3: Add the project root directorygithub ymlThe configuration file

.github/workflows/deploy.yml

name: Docker Image CI

on:
  push: Trigger CI when # push
    branches: [main] # applies to the main branch
  # pull_request:
  # branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # pull main branch code
      - name: Checkout
        uses: actions/checkout@v2

      # Make docker image and push it to Ali Cloud container image service
      - name: build and push docker image
        run: |
          echo ${{ secrets.ALIYUN_DOCKER_PASSWORD }} | docker login registry.cn-hangzhou.aliyuncs.com --username ${{ secrets.ALIYUN_DOCKER_USERNAME }} --password-stdin

          docker image build -t myblog:latest .
          docker tag myblog registry.cn-hangzhou.aliyuncs.com/test-blog/myblog:latest
          docker push registry.cn-hangzhou.aliyuncs.com/test-blog/myblog:latest
          docker logout
      Log in to the remote server, pull the image, make and restart the container
      # https://github.com/marketplace/actions/remote-ssh-commands
      - name: ssh remote deploy
        uses: fifsky/ssh-action@master
        with:
          command: |
            cd /
            echo -e "1.docker login start==>"
            echo ${{ secrets.ALIYUN_DOCKER_PASSWORD }} | docker login registry.cn-hangzhou.aliyuncs.com --username ${{ secrets.ALIYUN_DOCKER_USERNAME }} --password-stdin

            echo -e "2.docker stop myblog container==>"
            docker container stop myblog

            echo -e "3.docker conatainer rm==>"
            docker container rm myblog

            echo -e "4.docker image rm==>"
            docker image rm registry.cn-hangzhou.aliyuncs.com/test-blog/myblog:latest

            echo -e "5.docker pull==>"
            docker pull registry.cn-hangzhou.aliyuncs.com/test-blog/myblog:latest

            echo -e "6.docker container create and start==>"
            docker container run -d -p 80:3000 --name myblog registry.cn-hangzhou.aliyuncs.com/test-blog/myblog:latest

            echo -e "7.docker logout==>"
            docker logout
          host: ${{ secrets.HOST }}
          user: ${{ secrets.USER }}
          pass: ${{ secrets.PASSWORD }}

Copy the code
Step 4: Commit code for automatic deployment

No surprise, everything is ok in Actions for the warehouse

git add .
git commit -m "chore: add github actions yml"
git push -u origin main
Copy the code

Current blog click preview

5. Reference materials

  1. Next. Js official documentation

  2. How to optimize docker image of Node project

  3. Docker tutorial

  4. What’s the difference between front and back end isomorphism and template rendering?

  5. A step-by-step guide to deploying front-end projects using Github Actions