Project background
There are a lot of query class interface in the project, our project background is JAVA, as we all know, static language flexibility and JS are much worse, in order to be more flexible to provide services, but also in order to expand their own skill pool, as a front-end development I volunteered to complete the node background development. I’ve listed some of the methods and pitfalls I’ve encountered in the development process here, hoping to help some beginners get started quickly.
1. Technical selection
Framework selection: Expres
Language choice: typescript
Database: mysql
In-memory database: Redis
2. Configure environment variables
Generally, the development environment can be divided into various environments. In terms of our company’s business, we are divided into DEV (development environment), Beta (pre-release) and PROD (formal environment). As these three environments are all run online on the company’s server, our mysql and Redis configurations are all Intranet addresses. Therefore, a debug mode, also known as the local development environment, was added during development to connect the database address on the line.
Why set environment variables
Since there are multiple environments in each project, the database address or other data in each environment may be different. At this time, we need to distinguish the current environment through environment variables and obtain specific data.
How do I get environment variables
Process.env.node_env is used to obtain the current running environment in node. And that’s how we get it here. So we need to pass in the current environment variable at startup time.
There are two ways to set environment variables
1. The first method: add export NODE_ENV=debug to the scripts startup command of package.json. Debug can be dev, beta, prod, etc.
2. Second method: If using pM2 launcher. You need to add the pM2 configuration file in the root directory of the project. The name can be customized, I named it file.json, and the content is as follows.
{
"apps": [{"name": "tal_pac_node"."script": "./dist/index.js"."exec_mode": "cluster"// The application startup mode is set to cluster_mode. The default is fork"instances": "4", // Number of started instances"watch": false// Whether to listen for file changes and then restart"instance_var": "INSTANCE_ID"// This must be set otherwise it conflicts with config.js"ignore_watch": [// do not listen to the file"node_modules"."logs"]."min_uptime": "60s"// An application running less than that time is considered to have started abnormally"max_memory_restart": "500M"// Maximum memory limit"max_restarts": 30, // The maximum number of abnormal restarts, that is, the number of restarts during min_uptime;"autorestart": true// The default istrue, automatically restarts when an exception occurs"env_development": {
"NODE_ENV": "development",},"env_production": {
"NODE_ENV": "production",},"env_beta": {
"NODE_ENV": "beta",}}]}Copy the code
2.1. Differences between fork mode and Cluster mode
2.1.1. The fork mode
Fork mode uses the most basic process running mode, only a single instance runs the server, cannot realize TCP connection sharing; The advantage is that you can modify exec_interpreter to run a language other than JS using PM2, such as PHP or Python
2.1.2. Cluster mode
Using node.js Cluster module implementation, can only be used to start the Node process, can not be applied to other languages. Multiple server instances can be started and load balancing and TCP connections can be shared among them to improve server response performance.
2.2 Setting Environment Variables
Env_development, ENv_production, and env_beta are the environment variables we defined. Start process.env.node_env with the corresponding development, production, and beta. Note: Env_ must be added before the configuration.
"scripts": {
"clean": "rimraf ./dist"."build": "npm run clean && npm run build-ts && npm run tslint"."production": "pm2 startOrRestart ecosystem.json --env production"."beta": "pm2 startOrRestart ecosystem.json --env beta"."development": "pm2 startOrRestart ecosystem.json --env development"
}
Copy the code
2.3 How to Obtain Data based on Environment Variables
I’m using the config library here. Method of use
npm i config -S
Copy the code
After installation, create a new config folder under the root of your project. Create ‘Environment variable name ‘.json under the folder. Such as development. Json beta. Json.
Note that if process.env.node_env is undefined, the data in development.json will be retrieved by default.
How to obtain configuration file data
import config from 'config'// Get db parameterslet db: any = config.get('db')
Copy the code
3. Configure routes
The project uses the ExPREs framework. As to why exPRSS is used, there is a comprehensive consideration. Simplicity and lack of problems are the most important factors.
If you have used Express, you know that express uses routing in the following ways
const app = express()
app.use('/api' , router)
Copy the code
The old way of doing it is to add one by one, for example
app.use('/api1' , router)
app.use('/api2' , router)
app.use('/api3' , router)
Copy the code
This approach is cumbersome to implement. It’s also bad for maintenance. Therefore, I use dynamic loading method in this project to achieve. In fact, the principle is very simple. It is to read the folder where routes are defined, traverse the files in the folder, and obtain the file name. For example, I define XXX.routes. ts as the name of the route file. I can use regular expressions to match routing files.
import fs from 'fs'
import path from 'path'
import glob from 'glob'
export functionInitRouters (app: any) {// Initialize routeslet routers: any = getApiRouters()
Object.keys(routers).forEach((api: string) => {
let router = require(routers[api])
app.use('/' + api, router)
})
}
function getApiRouters() {
let res: any = {}
let apiDir = path.posix.join(__dirname, '.. /controllers')
let files = glob.sync(apiDir + '/*/*routes.js')
files.forEach(file => {
let api: string = file.split('/')[file.split('/').length - 1].split('. ')[0]
res[api] = file
})
return res
}
Copy the code
Obtain the routing object, where XXX is key and the file address is value. It then iterates through the keys of the object, dynamically loading the route via require. Glob is used to traverse the folder. Because my directory structure is as follows.
+-- config
+-- src
| +-- controllers
| +-- xxx
| +-- xxx.controllers.ts
| +-- xxx.routes.ts
| +-- init
| +-- index.ts
| +-- mysql.ts
| +-- redis.ts
| +-- router.ts
Copy the code
Finally, call the initRouters method when the project is started. Notice Different call files may cause the path of the routing folder to change. You need to modify the path before using it. So what I’m doing here is I’m in init folder, and when the project starts, it’s uniformly initialized.
import { init } from './init/index'
const app = express()
init(app)
Copy the code
4. Mysql initialization
The operations on the database in the project are sequelize. Support promise, ORM, SQL statement query, perfect ~ need to pay attention to is to carry out the authentication operation.
import { Sequelize } from 'sequelize'
import config from 'config'// Get db parameterslet db: any = config.get('db'* host: indicates the database address. * Max: indicates the maximum number of connections in the connection pool. * min: indicates the minimum number of connections in the connection pooltype {Sequelize}
*/
export const sequelize = new Sequelize(db.dbName, db.user, db.password, {
host: db.host,
dialect: 'mysql',
port: db.port,
logging: false,
pool: {
max: 20,
min: 0,
idle: 20000
}
})
sequelize
.authenticate()
.then(err => {
console.log(process.env.NODE_ENV + '-- mysql database connected successfully ')
})
.catch(err => {
console.log('Unable to connect to database', err)
})
Copy the code
Error code
The return value of the interface is defined as
{
code: Number,
result: Any,
message: String
}
Copy the code
My personal interface habit is that unless there is an uncaught problem, HTTP STAus returns 200 followed by business code 0 to indicate success. Error codes are maintained through errorcode.js
const codes: any = {
'0': 'success'.'20001': 'Failed to get Kanban data'
}
export functiongenerateResult( code: number, data? : any, message? : string ): object {return {
code: +code,
message: message || codes[`${code}`],
result: data
}
}
Copy the code
Return the result by using generateResult in the method.
Res. The status (200). The json (generateResult (0, data))Copy the code
6. Project deployment and operation
The company now has a unified publishing platform called Jenkins, so the Node project is also compiled and released through Jenkins. General train of thought is compiled in Jenkins server, then posted to the deployment server code, the final executive NPM run development/beta/prodection Jenkins how to deploy there is not much wrote, please leave a message if necessary.
There is no Jenkins for an individual, so the best thing to do is for the server to pull up the project code, perform a build (if necessary), and finally start the project. These can also be achieved through PM2.
Start by creating a new file.json file in the project root directory
{
"apps": [{
"name": "app-name"."script": "index.js"}]."deploy": {
"production": {
"user": "server user name"."host": ["sever ip"]."port": "SSH port"."ref": "origin/master"// Project branch"repo": "[email protected]:XXX/XXX.git"."path": "/www/XXX/production"."ssh_options": "StrictHostKeyChecking=no"."post-deploy": "npm install --registry=https://registry.npm.taobao.org && pm2 startOrRestart ecosystem.json --env production"."env": {
"NODE_ENV": "production"}}}}Copy the code
You can add multiple environment variables under “deploy”. You can add only one production.
It is best to add Git SSH support to your server so that you do not need to enter a Git username and password. Git how to configure SSH please search by yourself.
This command needs to be executed for the first time. You can change the corresponding environment variables
pm2 deploy ecosystem.json production setup
Copy the code
In the future, you only need to execute the following, no need to add setup.
pm2 deploy ecosystem.json production
Copy the code
The Node project is then started on the server.
7. Common PM2 commands
Pm2 ls // View all running programs pm2 logs // View project output pm2 delete all // Delete all programs pm2 start app-name // Start the programCopy the code