“This article is participating in the advancement of Node.js for technical topics,Click for details”

preface

Everybody is good! I am front-end dry Yang, I started to learn NodeJS in November last year, for nodeJS powerful feeling is very deep, today found a very interesting topic, 2022nodeJS really cool? I don’t think you’ll have an answer until you get real. Without further ado

Create a Node project

First, you need to have a Node environment, which I’m sure you already have. If you don’t, go to the official website to download it. Create a folder koA-node go to the folder and open terminal execution

npm init -y
Copy the code

The NPM init command helps us quickly initialize package.json files. At the root of each project, there is usually a package.json file that defines the various modules needed for the project, as well as the configuration information for the project (such as name, version, license, and other metadata). Based on this configuration file, the NPM install command automatically downloads the required modules, that is, the runtime and development environment required to configure the project.

Development Environment Configuration

Node.js is known as a javaScript runtime environment based on ChromeV8 engine. So with Node installed, we can run our JS files in the terminal node xxx.js, which gives javaScript the ability to run outside of the browser. However, if you run your files through Node xx.js every time during development, it will affect our development efficiency, so we can use the tool Nodemon to solve this problem. Nodemon can debug node.js-based applications by restarting the application when it automatically detects file changes in the directory. Open terminal execution in the current directory

npm install nodemon
Copy the code

By the way, install our main character koa

npm install koa
Copy the code

Next, create the file SRC /main.js

const Koa = require('koa')
const app = new Koa();

app.use((ctx,next) = > {
    ctx.body = 'hello QianYang'
})

app.listen(3000.() = >{
console.log('We started a 3000 port service.')})Copy the code

The code above is a simple koA service example that will be used to test if our KOA is installed successfully, then configure Nodemon and open package.json

{
  "name": "juejin-node"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "dev": "nodemon ./src/main.js".// Add the nodemon configuration
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": []."author": ""."license": "ISC"."dependencies": {
    "koa": "^ 2.13.4." "."nodemon": "^ 2.0.15"}}Copy the code

Perform the configuration on the terminal

npm run dev
Copy the code

Success is shown in the figure

Type http://localhost:3000 in your browser

Ok, our KOA + Node project construction is complete, goodbye!

Develop actual combat configuration

Just a case of the project, in our actual development certainly not so simple, but many students are not in touch with the node type project development, even if the entry is also very confused, how is the real construction of a node project. This question also bothered me for a long time, but I found some answers through video sites and some Node projects on Github. Not necessarily the best ones, but I feel good about them and I’ll share them.

  • App-management introduces dependencies and middleware
  • Config – Some configuration files for the project
  • Error – Error handling of the project
  • Controller – The controller controls the data that is eventually returned
  • Middleware – Middleware management
  • Router-item Interface routing file
  • Service – Database query
  • Utils – Tool management

Environment Variable Configuration

Let’s first configure the environment variables, create a. Env file in the root directory, and type

PORT=8080
Copy the code

This is our port number, whatever you want. Next is how to use the environment variable configuration file. Here I use the dotenv library to load the configuration file and use it.

npm install dotenv --save
Copy the code

After the installation is complete, to create the SRC/config/config. Dotenv. Js file

require('dotenv').config({path:'.env'})
module.exports = process.env
Copy the code

Then import it in main.js

const {PORT} = require('./config/config.dotenv')/ / import
const Koa = require('koa')
const app = new Koa();
app.use((ctx,next) = > {
    ctx.body = 'hello QianYang'
})
app.listen(PORT,() = >{
    console.log(The port for the service to be started is http://localhost:${PORT}`)})Copy the code

Then run NPM run dev

Route Installation and Configuration

The next step is to install koA routing. Unlike Express, Nest, and other frameworks, KOA doesn’t integrate many of the things it should, so we need to install the routing ourselves

npm i @koa/router
Copy the code

Then create a SRC/router/user. The router. Js file

const Router = require('@koa/router');
const router = new Router({prefix:'/user'})// Set the interface unified module path
router.get('/add'.(ctx,next) = > {
ctx.body = "Route configuration succeeded."
})
module.exports = router// Export routes
Copy the code

The SRC /app/index.js file is created to bring the KOA-Router and subsequent global middleware and third-party libraries into the aggregation to be centrally managed here.

const Koa = require('koa')
const app = new Koa()
const router = require('.. /router/user.router')
app.use(router.routes()).use(router.allowedMethods())//allowedMethods middleware of the KOa-Router for special processing of different request processing modes;

module.exports = app/ / export
Copy the code

Modify main.js to use main.js as a startup file only

const {PORT} = require('./config/config.dotenv')
const app = require('./app/index')// Import the app file
app.listen(PORT,() = >{
    console.log(The port for the service to be started is http://localhost:${PORT}`)})Copy the code

Start the project NPM run dev http://localhost:8080/user/add in your browser url input

The configuration of the route is basically successful, but if we had multiple routing files imported separately, there would be a lot of duplicate code in mounting separately, it would look like this

This is just 2 what if you have multiple modules? I can’t imagine! So we’ll do a simple optimization to create a new router in the Router directoryindex.jsfile

const fs = require('fs')// Node.js file processing module
const Router = require('@koa/router')
const router = new Router();
// Automatically import the router
fs.readdirSync(__dirname).forEach(file= > {
    if(file ! = ='index.js') {
        let r = require('/' + file)
        router.use(r.routes())
    }
})

module.exports = router
Copy the code

Modify the app/index. Js

const Koa = require('koa')
const app = new Koa()
const router = require('.. /router/index')/ / modify
app.use(router.routes()).use(router.allowedMethods());

module.exports = app
Copy the code

To verify success, create a new file called role.router.js

const Router = require('@koa/router');
const router = new Router({prefix:'/role'})// Set the interface unified module path
router.get('/add'.(ctx,next) = > {
    ctx.body = "Route automatic import succeeded."
})
module.exports = router
Copy the code

NPM run dev Starts the project

Connecting to a Database

A real back-end program database is essential, for this I also specially read the mysql will know will wait for books, so here database I choose is mysql, because I think this is a bit more partial to the public database or learn better. Since we chose mysql as the database of this project, we need to install the database first. The installation is very simple to find by yourself. After the installation is successful, we need to choose a fast database ORM tool. There are many Node-based ORM tools on the market, such as TypeORM, Sequelize, etc. So I’m going to Sequelize. Let’s install the official website and go through the installation process

npm i sequelize
npm i mysql2
Copy the code

Once the installation is complete, you must create a Sequelize instance to connect to the database. This can be done by passing the connection parameter separately to the Sequelize constructor or by passing a connection URI:

// Official example
const { Sequelize } = require('sequelize');

// Method 1: Pass a connection URI
const sequelize = new Sequelize('sqlite::memory:') / / Sqlite example
const sequelize = new Sequelize('postgres://user:[email protected]:5432/dbname') / / Postgres example

// Method 2: Pass parameters separately (sqlite)
const sequelize = new Sequelize({
  dialect: 'sqlite'.storage: 'path/to/database.sqlite'
});

// Method 3: Pass parameters separately (other databases)
const sequelize = new Sequelize('database'.'username'.'password', {// Database name, user name, and database password
  host: 'localhost'.dialect: / * choose 'mysql' | 'mariadb' | 'postgres' |' MSSQL one * /// Your database type
});
Copy the code

So let’s create a new file SRC /db/sql.js

const {Sequelize} = require("sequelize")
const seq = new Sequelize("baobei"."root"."xxxx", {host:"localhost".dialect: "mysql"
})// instantiate, XXXX is your database password
Copy the code

Open your favorite database management tool and create a new database

The next step is to call Sequelize to connect to the database, following the official documentation

We can see that authenticate() returns a Promise object so we can write it like this

const {Sequelize} = require("sequelize");
const seq = new Sequelize("baobei".'root'.'root', {host:"localhost".dialect:"mysql"
})

 seq.authenticate().then(() = > {
     console.log("Connected to your data successfully!")
 }).catch((err) = > {
     console.log("Database connection failed",err)
 })

module.exports = seq
Copy the code

Open Terminal Execution

node src/db/sql.js
Copy the code

Your database is connected successfully

Operate the database model authoring interface

Now that we have the database connected, how do we manipulate the database? We’ve introduced Sequelize as a library of ORM models that I can use to manipulate the database through ORM models, which are object maps.

Models can be defined in Sequelize in two equivalent ways:

  • Call Sequelize.define (modelName, Attributes, Options)
  • Extend Model and call init(Attributes, options)

Once a model is defined, it can be used in sequelize.models by its model name.

src/model/user.model.js

const {DataTypes} = require('sequelize')
const seq = require('.. /db/sql')
//username,password is the field of the table
const User = seq.define('baobei_user', {username: {type:DataTypes.STRING,/ / data type more data types reference https://www.sequelize.com.cn/core-concepts/model-basics#%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B
        allowNull:false.// Column arguments - can be null
        unique:true./ / column parameters - create a unique constraint shorthand more columns can refer to https://www.sequelize.com.cn/core-concepts/model-basics#%E5%88%97%E5%8F%82%E6%95%B0
        comment:'Username, unique'
    },
    password: {type:DataTypes.CHAR(64),
        allowNull: false.comment: "User password"
    }
})
 User.sync()// Model synchronization
 //- 'user.sync ()' - Create the table if it does not exist (if it does, do nothing)
 //- 'user.sync ({force: true})' - Creates a table and deletes it first if it already exists
 //- 'user.sync ({alter: true})' - This checks the current state of the table in the database (what columns it has, their data types, etc.) and then makes the necessary changes in the table to match the model.
module.exports = User
Copy the code

Terminal Execution

node src/model/user.model.js
Copy the code

Here we can clearly see that in factSequelizeThe model object we define helps us to implement a table building sentence, that is, our model can correspond to the tables in our database. Correspondingly, we can also operate the data in our table through the model.

The first step to register routing write SRC/router/user. The router. Js

const Router = require('@koa/router');
const router = new Router({prefix:'/user'})// Set the interface unified module path
router.get('/add'.(ctx,next) = > {
    ctx.body = "Route configuration succeeded."
})
router.post('/register'.(ctx,next) = > {
    ctx.body = {
        code:"0".message:"Registration successful"}})module.exports = router
Copy the code

Use API test tools

The second step is to write the controller

src/controller/user.controller.js

class UserController {
    async userRegister(ctx,next) {
        try {// Error capture
            ctx.body = {
                code:0.message:'Registration successful'.result:"ok"}}catch (err) {
            console.log(err)
        }
    }
}
module.exports = new UserController()
Copy the code

In the SRC/router/user. The router. Introduced in js

const {userRegister} = require('.. /controller/user.controller')
router.post('/register',userRegister)
Copy the code

Test successThe controller is usually the last step in our return of data, so error capture and error feedback are very important here, and we need to encapsulate error handling ourselves. insrc/app/index.jsRegister an error response event

const Koa = require('koa')
const app = new Koa()
const router = require('.. /router/index')
app.use(router.routes()).use(router.allowedMethods());
app.on('error'.(err,ctx) = >{/ / new
    let status = 500
    switch(err.code){// You can determine the error code you sent in, and change the status code returned accordingly, so as to better know what type of error occurred
        case '10001':
            status = 400
            break
        case '10002':
            status = 409
            break

        default :
            status = 500
    }
    ctx.status = status
    ctx.body = err
})
module.exports = app
Copy the code

After registering the error error handling event, we need to trigger the event to create SRC /error/error.js

module.exports = {
    UserRegisterError: {code:'10001'.message:'Parameter error or other error'.result:' '}}Copy the code

In the SRC/controller/user. Controller. Js added in

const {UserRegisterError} = require(".. /error/error");

class UserController {
    async userRegister(ctx,next) {
        try {
            console.log(dfsgsd)// There is no such variable so printing this variable will report an error
        }catch (err) {
            console.log(err)
            ctx.app.emit('error',UserRegisterError,ctx)// Raises an error event}}}module.exports = new UserController()
Copy the code

test

Now that we’re done with our controller’s error handling, we need to get down to business, the parameters to receive the POST request, the parameters to receive the request body we need to parse the request body, and that requires a third-party library koA-body to be installed

npm i koa-body
Copy the code

Install it in SRC /app/index.js after it is installed

const koaBody = require('koa-body')
app.use(koaBody())
Copy the code

In the SRC/controller/user. Controller. Receiving parameters in js

const {UserRegisterError} = require(".. /error/error");

class UserController {
    async userRegister(ctx,next) {
        try {
            const {username,password} = ctx.request.body
            console.log(username,password)
            ctx.body={
                message:{
                    username,
                    password
                }
            }
        }catch (err) {
            console.log(err)
            ctx.app.emit('error',UserRegisterError,ctx)
        }
    }
}
module.exports = new UserController()
Copy the code

test

That means we can parse and get the parameters

const User = require('.. /model/user.model')// Introduce the user model

class UserService{
    async createUser(username,password){
        return await User.create({username,password})/ / create database entry more queries, refer to https://www.sequelize.com.cn/core-concepts/model-querying-basics}}module.exports = new UserService()
Copy the code

In the SRC/controller. The user. The controller. Call this method and obtain the return value of js

const {UserRegisterError} = require(".. /error/error");
const {createUser} = require('.. /service/user.service')
class UserController {
    async userRegister(ctx,next) {
        try {
            const {username,password} = ctx.request.body
            console.log(username,password)
            const res = await createUser(username,password)// Call the createUser method to pass in the argument
            ctx.body={
                code:0.message:"Registration successful".result:res
            }
        }catch (err) {
            console.log(err)
            ctx.app.emit('error',UserRegisterError,ctx)
        }
    }
}
module.exports = new UserController()
Copy the code

test

After we passed the postman call interface found successful return value, and view the database also had the new data, explain our interface to write a success, is very simple, you don’t feel trouble is that in front of the iterative step was tested, if is a novice I wish every step test, Deepen your memory and know what results you should get when you do this section, in case the set is written down and you don’t know where the error is. Next, we can quickly write a login interface

Login interface writing

First, let’s examine the requirements for the login interface

  • Obtaining User data
  • User passwords are compared to check whether the user exists
  • token

As usual first registered routing SRC/router/user. The router. Js

router.post('/login'.(ctx,next) = >{
    ctx.body = {
        message:"Login successful"}})Copy the code

Don’t put the test again Then write the SRC/service/user. Service. Js

const User = require('.. /model/user.model')

class UserService{
    async createUser(username,password){
        return await User.create({username,password})
    }
    async getUserinfo({username,id}){
        const whereOpt = {};// Create an object that contains the query criteria
        id && Object.assign(whereOpt,{id})// Merge object, if there is this parameter then merge into the query, can reuse the query
        username && Object.assign(whereOpt,{username})

        const res = await User.findOne({
            attributes: ['id'.'username'.'createdAt'.'updatedAt'].// Field to be returned after the query succeeds
            where:whereOpt// Query conditions
        })
        return res ? res.dataValues : false// If the query is successful, return the data, if not GG}}module.exports = new UserService()
Copy the code

Then write the SRC/controller/user. Controller. Js

const {UserRegisterError} = require(".. /error/error");
const {createUser,getUserinfo} = require('.. /service/user.service')
class UserController {
    async userRegister(ctx,next) {
        try {
            const {username,password} = ctx.request.body
            const res = await createUser(username,password)
            ctx.body={
                code:0.message:"Registration successful".result:res
            }
        }catch (err) {
            console.log(err)
            ctx.app.emit('error',UserRegisterError,ctx)
        }
    }
    async userLogin(ctx,next) {
        try{
            const {username} = ctx.request.body;
            const{password,... res} =await getUserinfo({username})// exclude the password without returning it
            ctx.body = {
                code:0.message:"Login successful".result:res
            }
        }catch (err) {
            console.log(err)
        }
    }
}
module.exports = new UserController()
Copy the code

test

Here I hope to use the form of a middleware, because the problem of checking passwords is likely to be used in multiple places, written as middleware can better reuse code

New SRC/middleware/user. The middleware. The js code middleware

const {getUserinfo} = require('.. /service/user.service')
const {userPasswordError, userIsundefined,userLoginError} = require(".. /error/error");
const verifyLogin = async (ctx,next) => {// Verify cryptographic middleware
    try {
        const {username,password} = ctx.request.body;
        const res = await getUserinfo({username});
        // The user does not exist
        if(! res) {console.log('User does not exist',ctx.request.body)
            ctx.app.emit('error',userIsundefined,ctx)
            return
        }
        if(password! ==res.password){ ctx.app.emit('error',userPasswordError,ctx)
            return}}catch (err) {
        console.error(err);
        ctx.app.emit('error',userLoginError,ctx)
    }
await next();// Go to the next middleware
}

module.exports= {
    verifyLogin
}
Copy the code

Mount the middleware at the route location

const Router = require('@koa/router');
const {userRegister,userLogin} = require('.. /controller/user.controller')
const {verifyLogin} = require('.. /middleware/user.middleware')
const router = new Router({prefix:'/user'})// Set the interface unified module path
router.get('/add'.(ctx,next) = > {
    ctx.body = "Route configuration succeeded."
})
router.post('/register',userRegister)
router.post('/login',verifyLogin,userLogin)// Pay attention to the order of middleware
module.exports = router
Copy the code

test

Error test

How to use jsonWebToken to generate a token and return it

The installation

npm i jsonwebtoken
Copy the code

It’s very simple to use

const {createUser,getUserinfo} = require('.. /service/user.service')
const jwt = require('jsonwebtoken')/ / into the JWT

class UserController {

    async userLogin(ctx,next) {
        try{
            const {username} = ctx.request.body;
            const{password,... res} =await getUserinfo({username})
            ctx.body = {
                code:0.message:"Login successful".result: {token:jwt.sign(res,'fjhtglxt', {expiresIn:'1d'})ExpiresIn expiresIn is the token validity time}}}catch (err) {
            console.log(err)
        }
    }
}
module.exports = new UserController()
Copy the code

test

It can be seen that we have successfully returned the token. Now that we have the token, how to do my token authentication? It is also very simple to register a new routing interface

router.get('/getingo')
Copy the code

Then create a new public middleware file SRC/middleware/auth middleware. Js

const jwt = require('jsonwebtoken')
const {TokenExpiredError,JsonWebTokenError} = require('.. /error/error')
const auth = async (ctx,next) => {
    try {
        const {token} = ctx.request.header
        ctx.state.user = jwt.verify(token,'fjhtglxt')// Token authentication, if valid, in the variable ctx.state.user
    } catch (err) {
        console.log(err)
        switch (err.name) {
            case 'TokenExpiredError':
                console.error('Token has expired', err)
                return ctx.app.emit('error', TokenExpiredError, ctx)
            case 'JsonWebTokenError':
                console.error('Invalid token', err)
                return ctx.app.emit('error', JsonWebTokenError, ctx)
        }
    }
    await next()
    // TokenExpiredError:{
    // code:'405',
    // message:' expired token',
    // result:''
    / /},
    // JsonWebTokenError:{
    // code:'405',
    // message:' invalid token',
    // result:''
    / /},
}
module.exports = {
    auth
}
Copy the code

Write a query method of user information SRC/controller/user. The controller. Js

async getInfo(ctx,next) {
    try {
        const {id} = ctx.state.user;// Since the token contains our personal information, we can deconstruct our id
        const res = await getUserinfo({id})
        ctx.body = {
            code:0.message:'Query successful'.result:res
        }
    }catch (err) {
        console.log(err)
    }
}
Copy the code

Mount the middleware in the route

const Router = require('@koa/router');
const {userRegister,userLogin,getInfo} = require('.. /controller/user.controller')
const {verifyLogin} = require('.. /middleware/user.middleware')
const {auth} = require(".. /middleware/auth.middleware");
const router = new Router({prefix:'/user'})// Set the interface unified module path
router.get('/add'.(ctx,next) = > {
    ctx.body = "Route configuration succeeded."
})
router.post('/register',userRegister)
router.post('/login',verifyLogin,userLogin)
router.get('/getinfo',auth,getInfo)// Token authentication middleware, get personal information controller
module.exports = router
Copy the code

test

This interface to query personal information is just to demonstrate how to verify token, it is not really useful…

extension

Just now, we frequently create files, and the file name is very long in order to be clear. I believe that normal people are beginning to get annoyed. I thought it was very easy to make mistakes before, and there may be a problem with typos in any file. But I saw a nice article in Nuggets @iel take you Hand in hand to develop a scaffold (top) and then thought of nest command line creation file, but I don’t like nest, so I tried to put it in my project.

npm i -D commander inquirer fs-extra kolorist
Copy the code
  • The COMMANDER plug-in provides command registration, parameter resolution, and callback execution
  • Inquirer plug-in for command line interaction (Q&A)
  • The FS-Extra plugin is rightnodejsfileApiFurther encapsulation for easy use
  • The kolorist plugin is used to output color information for friendly prompts

Register the command, then build the command interaction, and create files with fs-extra to make the command look nice

The first step is to register the new SRC /index.js command

#! /usr/bin/env node //#! /usr/bin/env node
const { Command } = require("commander")
const {onCreate} = require("./commands/create")// The event that needs to be called back after we execute the command
// Create a command object
const program = new Command()

// Register commands, parameters, callbacks
// Register the create command
program.command('create')
    // Add the command description
    .description('Create a module file')
    / / add the command parameters - t | - type < type >, < type > says the parameters required, optional [type]
    .option('-t --type <type>'.'Create type. Optional values: Model, Router, Service, Middleware, Controller)
    // Register the command callback
    .action(onCreate)// Callback event

// Execute command line argument parsing
program.parse()
//npm run cli -- -t all
Copy the code

Create a new SRC /commands/create.js file where we need to write our command interface interactions.

const inquirer = require("inquirer")
const {red} = require("kolorist")
const CREATE_TYPES=['model'."service"."router"."middleware"."controller"."all"]
const DoesItExist = require("./createModel")// File creation method, because it is too messy to write inside, I separate out the maintenance
async function onCreate(cmd) {
    console.log(cmd)
    let {type} = cmd
    // If type is not included in the command argument, then ask once
    if(! type) {console.log(type)
        const result = await inquirer.prompt([
            {
                // The name of the property used after the fetch
                name:'type'.// The interaction mode is a list option
                type:"list".// Prompt message
                message:'(Required) Please select create type :'.// List of options
                choices:CREATE_TYPES,
                // The default value is the subscript index
                default:0
            }
        ])
        type = result.type
    }
    // If the type is not supported, print an error message and reselect
    if(CREATE_TYPES.every((t) = >type ! == t)){console.log(
            red('The current type only supports:${CREATE_TYPES.join(', ')}, received not supported"${type}", please choose again! `))return onCreate()
    }
    try {
        switch (type) {
            case 'model'|'service'|'router'|'middleware'|'controller':
                const info = await inquirer.prompt([
                    {
                        name:'name'.type:'input'.message:'(Required) Please select Create${type}Name: `.validate: (value) = > {
                            if (value.trim() === ' ') {
                                return 'Component name is mandatory! '
                            }
                            return true}}])await DoesItExist(info.name,type)
                break
            case 'all':// If it is all, create files in the configured folder
                const all = await inquirer.prompt([
                    {
                        name:'name'.type:'input'.message:'(Required) Please select Create${type}Name: `.validate: (value) = > {
                            if (value.trim() === ' ') {
                                return 'Component name is mandatory! '
                            }
                            return true}}])// Create the model file
                const createModel =  DoesItExist(all.name,"model")
                // Create service file
                const createService =  DoesItExist(all.name,"service")
                // Create a router file
                const createRouter =  DoesItExist(all.name,"router")
                // Create the Middleware file
                const createMiddleware =  DoesItExist(all.name,"middleware")
                // Create the controller file
                const createController =  DoesItExist(all.name,"controller")
                await Promise.all([createModel,createService,createRouter,createMiddleware,createController])
                break
            default:

                break}}catch (e){
        console.error(e)
    }
}
module.exports={
    onCreate
}
Copy the code

Then write we create a file, the method of new SRC/commands/createModel js

const fs = require('fs-extra')
const {blue, red} = require("kolorist")
async function DoesItExist (name,type){
    const exists = await fs.pathExists(`./src/${type}/${name}.${type}.js`)

    if(! exists){// Check whether the file exists
        createModel(name,type)
    } else {
        console.log(red("File already exists"))}}function createModel(name,type) {
    fs.ensureFile(`./src/${type}/${name}.${type}.js`.(err) = > {
        if(err){
            throw  err
        } else {
            console.log(blue(`./src/${type}/${name}.${type}.js, create finished '))}}}module.exports = DoesItExist
Copy the code

Once that’s done, we need to configure our commands and add them to “scripts” in package.json

"cli": "node ./src/index.js create"
Copy the code

Next you can test the command

npm run cli -- -t all
Copy the code

Enter the name of the folder to create, such as Role

You can see on the terminal that we have succeeded because I created a role.router.js file so it will say that the file already exists but other folders that don’t have this file have already been created and we can refresh the folder to see.

The end of the

This is my second post, the content is a little bit too much, I may not write very detailed, but I believe that if you follow the article step by step down will be able to run, of course, if the production environment of the project is not so simple, there will be logs, PM2, deployment and other things. There are a lot of options for these things in the Node ecosystem, and it’s not difficult at all, so you can explore them yourself. The corresponding Node gives JS the ability to be browser-free, and there are many other ways to play it, not just on the back end, but serverless and things like that.

In addition, all code for this article is uploaded to Gitee

Writing is really not easy, I hope to leave a lingering fragrance