node最佳实践1-express初始化

447 阅读6分钟

安装

安装npm install -g express-generator@4 在vueapp下新建server文件夹,切换到server文件夹,执行express node_api && cd node_api ,会新建一个node_api的项目,然后安装依赖npm install

执行npm start启动express

$ npm start

node-api@0.0.0 start /Users/mac/dongzhiqin/vueapp/server/node_api

node ./bin/www

在页面server/node_api/routes/index.js配置路由

var express = require('express');

var router = express.Router();

/* GET home page. */

router.get('/', function(req, res, next) {

  res.render('index', { title: 'Express' });

});

router.get('/hi', function(req, res, next) {

  [req.name](http://req.name) = 'kim';

  next();

})

router.get('/hi', function(req,res) {

  res.send(`hello ${req.name}`)

})

router.get('/request', function(req,res,next){

  res.send(req.query)

})

router.post('/postrequest', function(req, res, next){

  res.send(req.body)

})

router.get('/user', function(req, res, next) {

  console.log('req: ',req)

  res.send({

    name: 'kim',

    address: '广州海珠区',

  })

})

module.exports = router;

用浏览器或者postman访问localhost:3000(默认端口是3000),可以看到有返回【welcome to express】

nodemon实现热启动

安装nodemon实现nodejs热启动 npm install --save-dev nodemon,用nodemon指令替换node指令即可

安装cors,npm install cors --save

安装cross-env实现环境变量设置 npm install --save-dev cross-env,编辑server/node_api/package.json

{
  "name": "node-api",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start:dev": "cross-env NODE_ENV=development nodemon ./bin/www",
    "start:prod": "cross-env NODE_ENV=production node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "cors": "^2.8.5",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "jade": "~1.11.0",
    "morgan": "~1.9.1"
  },
  "devDependencies": {
    "cross-env": "^7.0.3",
    "nodemon": "^2.0.6"
  }
}

跨域

如果有跨域需求,可以修改app.js文件

//跨域问题解决方面
const cors = require('cors');  
app.use(cors({  
    origin:['http://localhost:8080'],
    methods:['GET','POST'],
}));
//跨域问题解决方面
app.all('*',function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
 next(); 
});

支持es6

express现在还不支持es6语法,所以需要修改一番。如果不打算用es6可以略过。

修改目录结构

切换到node-api目录下,新建src文件夹。

  • 创建 src/ 目录
  • 将 bin/ , app.js 和 routes/ 移动到 src 目录
  • 将 bin 目录中的 www 文件重命名为 www.js
  • 将 public/ 移动到项目根目录

语法转换

编辑server/node_api/src/bin/www.js,注释掉头部的require指令修改为import

#!/usr/bin/env node

/**
 * Module dependencies.
 */
import app from '../app'
import debugLib from 'debug'
import http from 'http'
const debug = debugLib('node-api:server')

// var app = require('../app');
// var debug = require('debug')('node-api:server');
// var http = require('http');

编辑server/node_api/src/routes/index.js,用import替换require,export替换module.exports

// var express = require('express')
// var router = express.Router()
import express from 'express'
var router = express.Router()
/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'Express' })
})

// module.exports = router
export default router

server/node_api/src/routes/users.js这个文件本来是也是放路由设置的,但是以后打算要用axios,会大改,就先删除掉或者全部注释掉。 继续编辑server/node_api/src/app.js,同样是用import语法替代require,同时注意因为修改了目录结构,所以views和public的路径也要修改,例如app.set('views', path.join(__dirname, '../views'))

import express from 'express'
import path from 'path'
import cookieParser from 'cookie-parser'
import logger from 'morgan'
import createError from 'http-errors'
import indexRouter from './routes/index'  // 没有引入usersRouter了
import cors from 'cors'

const app =express()
// var app = express()

// view engine setup
app.set('views', path.join(__dirname, '../views'))
app.set('view engine', 'jade')

app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, '../public')))

app.use('/', indexRouter)
// app.use('/users', usersRouter)  // 这个注释掉

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404))
})

...

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message
  res.locals.error = req.app.get('env') === 'development' ? err : {}

  // render the error page
  res.status(err.status || 500)
  res.render('error')
})

export default app

脚本配置

先安装npm-run-all,增加一次运行多个脚本的时候书写便利。 npm install npm-run-all --save-dev

安装 babel 和其他包。Babel 是一个 Javascript 编译器,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中,比如 Node.js。在项目根目录打开终端命令行,输入下面命令,我们会安装最新版的 babel(Babel 7)。

npm install -D @babel/core @babel/cli @babel/preset-env @babel/node

-D是表示安装的包放在devDependency --save是表示安装的包放在dependency下

在node-api根目录创建.babelrc写入以下代码

{ "presets": ["@babel/preset-env"] }

因为我们使用 Babel 来转换不同类型的 js 语法,所以需要在 .babelrc 中配置 preset-env 预设(之前安装的),它会告诉 Babel 去转换哪种类型。

在这些都设置好后,我们就可以测试 node server能否在 ES6 语法环境下运行,首先,在 package.json 中添加 dev 脚本:

  "scripts": {
     "server": "babel-node ./src/bin/www",
     "dev": "NODE_ENV=development npm run server",
    },

注意,路径由./bin/www变为了./src/bin/www,执行run npm dev已经可以正常启动了。

配置nodemon

增加一个watch脚本,通过配置文件,实现自动监听文件编号然后重启服务器,这样更优雅。 安装nodemon npm i -D nodemon 在node_api根目录下新增nodemon.json配置文件

{
  "exec": "npm run dev",
  "watch": ["src/*", "public/*"],
  "ext": "js, html, css, json"
}

添加一个watch脚本

  "scripts": {
    "server": "babel-node ./src/bin/www",
    "server:prod": "node ./dist/bin/www",
    "dev": "NODE_ENV=development npm run server",
    "clean": "rimraf dist",
    "build": "babel ./src --out-dir dist",
    "start": "npm run prod",
    "prod": "NODE_ENV=production npm-run-all clean build server:prod",
    "watch": "nodemon"
  },

生产准备 prod 脚本 和 dev 脚本有点区别,我们需要将 src 目录中的所有 js 文件代码转换为 nodejs 能够识别的语法形式。运行 prod 脚本会生成一个和 src/ 目录结构类似的 dist/ 文件夹,但是每次在运行该脚本之前,我们需要将旧的 dist/ 文件夹删除,确保我们运行的是最新生成的代码。下面是具体步骤:

  • 创建 build 脚本,它会转换 src/ 中的文件代码并生成新的 dist/ 文件夹
  • 安装 rimraf 包,并新建 clean 脚本,用来删除 dist/ 文件夹。
  • 新建 prod 脚本,将 clean,build,start server 脚本组合起来。

我们先要安装 rimraf 包,用来删除某个文件夹 npm install rimraf --save 安装好后,在 package.json 的 scripts 字段中加入 clean 脚本,我们会在 build 脚本中使用到它,现在整个 scripts 字段结构如下

"scripts": {
    "server": "babel-node ./src/bin/www",
    "server:prod": "node ./dist/bin/www",
    "dev": "NODE_ENV=development npm run server",
    "clean": "rimraf dist",
    "build": "babel ./src --out-dir dist",
    "start": "npm run prod",
    "prod": "NODE_ENV=production npm-run-all clean build server:prod"
  },

数据库配置

根据package.json

  "scripts": {
    "server": "babel-node ./src/bin/www",
    "server:prod": "node ./dist/bin/www",
    "dev": "cross-env NODE_ENV=development npm run server",
    "clean": "rimraf dist",
    "build": "babel ./src --out-dir dist",
    "start": "npm run prod",
    "prod": "cross-env NODE_ENV=production npm-run-all clean build server:prod",
    "watch": "nodemon"
  },

执行npm run prod后会清除dist文件夹并重新进行babel编译。编译完成发现项目无法启动,提示缺少dist/config.json文件。

发现是因为babel没有把src/config/config.json文件编译到dist文件夹内,直接的处理办法未知。这里先用别的方法拯救一下。sequelizerc文件可以配置sequelize,我们让数据库的配置文件从json文件换为js文件即可,另外js文件还支持动态配置。

根据the sequelizerc file的说明,在根目录下创建一个.sequelizerc文件

const path = require('path');

module.exports = {
  'config': path.resolve('src', './config/database.js'),
  'models-path': path.resolve('src', './models'),
  'seeders-path': path.resolve('src', './seeders'),
  'migrations-path': path.resolve('src', './migrations')
};

然后新增文件src/config/database.js

module.exports = {
  development: {
    username: "postgres",
    password: "postgres",
    database: "demo_development",
    host: "127.0.0.1",
    dialect: "postgres"
  },
  test: {
    username: "postgres",
    password: "postgres",
    database: "database_test",
    host: "127.0.0.1",
    dialect: "postgres"
  },
  production: {
    username: "postgres",
    password: "postgres",
    database: "demo_development",
    host: "127.0.0.1",
    dialect: "postgres"
  }
}

注意:为了测试目的,production环境下也使用了dev环境的数据库

修改model/index里关于数据库配置的引入

const config = require(__dirname + '/../config/database')[env];
// const config = require(__dirname + '/../config/config.json')[env];

配置完成后就可以执行npm run start

参考

在 Node 和 Express 中使用 ES6 (及以上)语法