Hj CCtalk video address: www.cctalk.com/v/151149238…

Specification and deployment

Lazy people promote social progress.


In this article, we’ll cover three things

  • Custom writing specification
  • Development environment Running
  • How to deploy and run


Custom writing specification

The writing specification mentioned in this article is for reference only, not necessary for the project.


As Node has become popular, JavaScript coding specifications have matured and the community has generated a variety of coding specifications. But what we’re doing here is not “limit the number of Spaces” or “add a semicolon or not.” The specification we want to talk about is the specification of the project structure.


Our current project structure is as follows:

├─ API // API // API // API // API // API // API // API // API // API // Error Response page ├─ logs/ // / Project application of log data ├─ Middleware │ ├─ mi-http-error/ │ ├─ ├─ mi-send/ │ ├─ mi-send/ │ ├─ ├─ ├─ ├─ ├─ ├─ │ ├─ mi-send/ │ ├─ ├─ ├─ │ ├─ mi-send/ │ ├─ ├─ ├─ router.js // Configure URL routing rules for customizable startup initialization, such as starting HTTPS, calling middleware, starting routing, etcCopy the code


After the architect has prepared the project structure, the developers only need to change the code at the business level. For example, when we add a business scenario, we need to change about three areas:

  1. service/Create a new file in the directory, process the business code of the logical layer, and return tocontroller
  2. controller/Directory to create a new file, simple processing under the request data, pass toservice
  3. Modifying a Routing Filerouter.jsTo add the processor corresponding to the route


As the volume of business increases, we find that there is a repetitive operation – “constantly require the file, constantly parse the functions in the file”. When the volume of business reaches a certain level, more than 10 external files may be added to a file:

const controller1 = require('... ')
const controller2 = require('... ')
const controller3 = require('... ')
const controller4 = require('... ')... app.get('/fn1', controller1.fn1() )
app.get('/fn2', controller2.fn2() )
app.get('/fn3', controller3.fn3() )
app.get('/fn4', controller4.fn4() )
Copy the code

Just choosing a name is already a headache!


So, what we need to do is to agree on the code structure specification and save the headaches, such as router.js:

// const router = require('koa-router')()
// const HomeController = require('./controller/home')
// module.exports = (app) => {
// router.get( '/', HomeController.index )
// router.get('/home', HomeController.home)
// router.get('/home/:id/:name', HomeController.homeParams)
// router.get('/user', HomeController.login)
// router.post('/user/register', HomeController.register)
// app.use(router.routes())
// .use(router.allowedMethods())
// }
const router = require('koa-router') ()module.exports = (app) = > {
  router.get( '/', app.controller.home.index )
  router.get('/home', app.controller.home.home)
  router.get('/home/:id/:name', app.controller.home.homeParams)
  router.get('/user', app.controller.home.login)
  router.post('/user/register', app.controller.home.register)
  app.use(router.routes())
     .use(router.allowedMethods())
}
Copy the code

Smart students may have discovered, app. Controller. Home. The index is cotroller/home. The index function of js.


Design ideas

The implementation idea is very simple, when the application starts, read the JS file under the specified directory, take the filename as the attribute name, mount it on the instance APP, and then extend the interface function in the file to the file object.

There are generally two ways to start, one is to execute the program when it starts, and the other is to read the request when it comes in.

In traditional writing, the project would load the specified directory file according to require at startup and then cache it, which is the same idea as the first method. If the middleware way, when the request to read, the first read will be relatively slow together. Overall consideration, we use the first method: program start time read.


Code implementation

Create the middleware/mi-rule/index.js directory to implement the following code:

const Path = require("path");
const fs = require('fs');
module.exports = function (opts) {
  let { app, rules = []} = opts

  // If the argument lacks the instance app, an error is thrown
  if(! app) {throw new Error("the app params is necessary!")}// Extract the property name from the app instance object
  const appKeys = Object.keys(app)
  rules.forEach((item) = > {
    let { path, name} = item
    // If the app instance already has an incoming attribute name, an error will be thrown
    if (appKeys.includes(name)) {
      throw new Error(`the name of ${name}already exists! `)}let content = {};
    // Read all files in the specified folder (dir) and traverse
    fs.readdirSync(path).forEach(filename= > {
      // Retrieve the file suffix
      let extname = Path.extname(filename);
      // Only js files are processed
      if (extname === '.js') {
        // Remove the suffix from the file name
        let name = Path.basename(filename, extname);
        // Read the contents of the file and assign the binding
        content[name] = require(Path.join(path, filename)); }}); app[name] = content }) }Copy the code

Opts is a parameter object that contains the instance app used to mount the specified directory file. Rules is the directory rule we specify.

To modify middleware/index.js:

// Introduce rules between components
const miRule = require('./mi-rule')

module.exports = (app) = > {
  /** * At the beginning of the interface calls js files in the controller folder, mounted in the app.controller property, js files in the service folder, mounted in the app.service property 
  miRule({
    app,
    rules: [{path: path.join(__dirname, '.. /controller'),
        name: 'controller'
      },
      {
        path: path.join(__dirname, '.. /service'),
        name: 'service'}]})// The following code is omitted
}
Copy the code


Business code application

1. Modifyrouter.js:

const router = require('koa-router') ()module.exports = (app) = > {
  router.get( '/', app.controller.home.index )
  router.get('/home', app.controller.home.home)
  router.get('/home/:id/:name', app.controller.home.homeParams)
  router.get('/user', app.controller.home.login)
  router.post('/user/register', app.controller.home.register)
  app.use(router.routes()).use(router.allowedMethods())
}
Copy the code

2. Modifycontroller/home.js:

module.exports = {
  index: async(ctx, next) => {
    await ctx.render("home/index", {title: "Welcome to iKcamp."})},home: async(ctx, next) => {
    ctx.response.body = '<h1>HOME page</h1>'
  },
  homeParams: async(ctx, next) => {
    ctx.response.body = '<h1>HOME page /:id/:name</h1>'
  },
  login: async(ctx, next) => {
    await ctx.render('home/login', {
      btnName: 'GoGoGo'})},register: async(ctx, next) => {
    // Deconstruct the app instance object
    const { app } = ctx

    let params = ctx.request.body
    let name = params.name
    let password = params.password

    // Notice how the service layer is called
    let res = await app.service.home.register(name,password)
    if(res.status == "1") {await ctx.render("home/login", res.data)
    }else{
      ctx.state.title = "Personal Center"
      await ctx.render("home/success", res.data)
    }
  }
}
Copy the code

It is not necessary to introduce this structural specification in the project, after all, people have different ideas. When the iKcamp team came up with the idea, there were disagreements. Put forward such a train of thought, offer everybody reference only.


Development environment Running

As a back-end code language, every time a file is modified in the development environment, you need to manually restart the application, which is not as clean as the front-end browser. To reduce the cost of manual restart, we suggest that Nodemon be used instead of Node to start the application. When the code changes, Nodemon will automatically restart it for us.


Install Nodemon globally:

npm i nodemon -g
Copy the code


Local projects also need to install:

npm i nodemon -S
Copy the code


For more details on usage, please refer to the official documentation


The deployment of running


There are many ways to deploy and run online, and we recommend using PM2.

Pm2 is a process manager for Node applications with load balancing function.


The installation method is similar to that of Nodemon, requiring global installation:

npm i pm2 -g
Copy the code


Operation method:

pm2 start app.js
Copy the code


For more details on usage, please refer to the official documentation

Translation project Master:

1. Dry goods | Everyone is the Master of translation project

2. IKcamp produces a total of 5 chapters and 16 sections of wechat mini program teaching (video included)


In 2019, iKcamp’s original new book Koa and Node.js Development Actual Combat has been sold on JD.com, Tmall, Amazon and Dangdang!