【Node中间层实践小记(一)】----搭建项目框架

前言:
    本文是学习Node中间层实践的相关笔记,推荐大家可以去阅读Keyon Y大佬的原文Node中间层实践 。开启本文前,也可以先去阅读以下,Node中间层实践(一)——基于NodeJS的全栈式开发,对了解本文内容有所帮助。(PS:继续还债的node小白╮(╯▽╰)╭)

一、脚手架 ?

    我们每次开启一个新项目的时候,可能都需要根据项目需求,搭建一个新的脚手架,根据所选前端框架,来安装官方推荐。比如,使用angular2,vue2的同学,官方推荐的安装方式是,通过专用的angular-cli、vue-cli来快速搭建一个webpack编译、打包的项目框架。
    那么,受工具启发,在项目之初,我们也可以开发一个基于webpack的项目框架:

  • 使用express搭载webpack-dev-middleware和webpack-hot-middleware进行热加载
  • 内置dev(开发环境)和production(生产环境)两种启动方式

二、技术选型

2.1 node开发框架

express和koa 二选一

  • express的更贴近Web Framework这一概念;
  • express功能极简,完全是有路由和中间件构成的一个web开发框架:从本质上来说,一个Express应用就是在调用各种中间件;
  • koa使用co作为底层运行框架,使用它完全忘记了什么时候回调函数或者callbackshell;
  • express历史更久,装机量大,文档完善,第三方的中间件也很多;
    此次,选择express作为node开发框架。

2.2 模板引擎

直接选择pug作为服务器端模板引擎。pug是一个比较灵活的服务端模板,express配置起来也很简单,在根目录的app.js文件中配置。

// 设置模板引擎的类型app.set(‘view engine’,‘pug’); //设置模板文件路径app.set(‘views’,path.resolve(_dirname,‘src/Views’));

  这样,在express渲染时候使用res.render(‘Home/index’,{}),指定对应的页面模板路径就行了,第二个参数是要在pug页面使用的数据内容,json格式。

2.3 中间层与后端的异步通信

  其实,就是个ajax库,所以,我选择了axios,vue2官方推荐的ajax库,内置的axios.all(),可以在中间层代理多个后端请求一并返回,轻松实现Bigpipe。

2.4 模块化

  因为是网站前台页面,需要考虑SEO,无法使用前端框架,所以换个思路,使用webpack+es6/AMD来实现模块化。于是,使用webpack作为打包机+View层的模块化,从前端层面实现了模块化和组件化。es6用在Contorl层的模块化,在node中间层实现了模块化

三、环境配置(启动文件)

  app.js作为项目的启动文件,是express的配置文件,同时也是运行开发环境/生产环境的配置文件。
  通过文件node启动时配置的命令参数,由app.js接收参数,然后运行对应的环境
  我们需要安装cross-env这个插件

npm i --save-dev cross-env

  在package.json的script中配置:

"scripts": {
    
    
    "start": "cross-env NODE_ENV=production node app.js",
    "dev": "cross-env NODE_ENV=dev supervisor -w app.js app",
    "build": "webpack --config build/webpack.prod.config.js"
}

  这样,使用process.env.NODE_ENV就可以获取node启动的环境参数。
  这里,配置了开发环境(dev)和生产环境(production)

  • 开发环境:不压缩代码,开启devtool生成source-map,便于调试代码;
  • 生产环境:是用webpack进行打包、压缩、混淆操作,将最终完整的代码(应用)输出至dist目录中,然后再启动node服务器,运行应用;
    上述代码中还用到了supervisor插件,这是监听node配置文件(app.js)的更改,并自动重启node的。
npm i --save-dev supervisor

前端层面使用webpack-dev-middleware和webpack-hot-middleware,实现了热加载。
这样,从中间层到前端都实现了热加载。

3.1 node中间层配置

在根目录下,新建了config文件夹,将一些常用的配置/参数、方法抽离出来,写在了config/config.js和config/common.js中。
例如,中间层启动端口号、应用的根目录(path.resolve(_dirname,‘…/’))、后端服务器的ip、前端SEO的description和keywords等参数,都放在了config.js中,通过AMD规范在所有使用的文件中统一引入,修改起来也方便。
app.js

var express = require('express');
var cookieParser = require('cookie-parser');
var path = require('path');
var localOptions = require('./build/localOptions');
var config = require('./config/config');
var bodyParser = require('body-parser');
var auth = require('./middleware/auth');
var log4js = require('./config/log4js');

process.env.NODE_ENV = process.env.NODE_ENV ? process.env.NODE_ENV : 'production';
var isDev = process.env.NODE_ENV === 'dev';
var app = express();
var port = config.port;


app.set('view engine', 'pug');
// 设置模板文件路径
if (isDev){
    
    
	app.set('views', path.resolve(__dirname, 'src/Views'));
}else {
    
    
	app.set('views', path.resolve(__dirname, 'dist/Views'));
}

// app.locals定义的键值对能在模板中直接访问
app.locals.env = process.env.NODE_ENV || 'dev';
app.locals.reload = true;

app.use(cookieParser());
app.use(bodyParser.urlencoded({
    
    extended: false}));


if (isDev) {
    
    
    // app.locals.pretty = true;
	// 开发环境,静态文件使用热插拔
	var webpack = require('webpack');
	var webpackDevMiddleware = require('webpack-dev-middleware');
	var webpackHotMiddleware = require('webpack-hot-middleware');
	var webpackDevConfig = require('./build/webpack.dev.config.js');

	var compiler = webpack(webpackDevConfig);
	// 热插拔
	app.use(webpackDevMiddleware(compiler, {
    
    
		publicPath: webpackDevConfig.output.publicPath,
		noInfo: true,
		stats: 'errors-only'
	}))
	app.use(webpackHotMiddleware(compiler, {
    
    
		heartbeat: 1000,
		noInfo: true,
	}));

	// 不能热插拔的往下执行
	var reload = require('reload');
	var http = require('http');
	var server = http.createServer(app);
	// reload(server, app);
	reload(app);
	server.listen(port, () => {
    
    
		console.log('App【dev】 is now running on port ' + port + '!');
	});

	// 静态目录设置必须有,开发环境读取的vendor.js不是内存文件;
    // 静态目录设置必须放在reload后面,避免页面引入reload.js报错
    app.use(express.static(path.join(config.root, 'src')));
    app.use('/', require(path.join(config.configRoot,'/routes')));
	
}else {
    
    
	// 线上环境不需要监听,只需开启node服务即可
	// 设置node的静态文件目录
	app.use(express.static(path.join(config.root, 'dist')));
    app.use('/',require(path.join(config.configRoot,'/routes')));
    // app.listen(process.env.PORT, () => {
    
    
    app.listen(port, () => {
    
    
		console.log('App【production】 is now running on port ' + port + '!');
    })
}

// 捕捉 404错误 传给 error路由
app.use('*', auth, (req, res, next) => {
    
    
	let err = new Error('Not Found');
	err.status = 404;
	next(err);
});

// 捕获 error,跳转至error页面
app.use((err, req, res, next) => {
    
    
	const sc = err.status || 500;
	if(err.status == 405){
    
    
		res.redirect(config.cndesignOrigin + '/Home/GuideAuthentication');
		return;
	}
	res.status(sc);
	// 此处需写入日志
	log4js.error('\r\n Status: '+ sc + "\r\n Message: " + err.message + "\r\n Href: " + localOptions.baseUrl + req.originalUrl + "\r\n User-agent: " + req.headers['user-agent']);

	res.render('Error/404', {
    
    
		error: err,
		status: sc,
		message: err.message,
		userInfo: req.userInfo_ || {
    
     hasLogin: false }
	});
});

注意Error Handle的挂载的顺序,一般挂载到app.use()下,且放到最后。
因为Error Handle的参数为4个,第一个参数err通过路由中的next(err)抛出,这样所有的路由都可以随时抛出error,让Error Handle来捕获。
来看一下目录结构:

App
├─ .babelrc                         // babel的配置
├─ ReadMe                           
├─ app.js                           // 启动文件
├─ build                            // webpack的配置文件
│    ├─ entrys.js                   // webpack打包js和css的入口文件
│    ├─ localOptions.js             // 前端开发者本地配置文件,本地ip等站点配置
│    ├─ postcss.config.js           // postcss的配置文件
│    ├─ webpack.dev.config.js       // 开发环境的webpack打包配置
│    ├─ webpack.dll.config.js       // webpack.DllReferencePlugin插件的配置文件
│    └─ webpack.prod.config.js      // 生产环境的webpack打包配置
├─ config                           // Model层文件:包括node服务器的配置、路由和代理接口
│    ├─ common.js                   // 中间层逻辑处理的公用方法
│    ├─ config.js                   // node服务器的配置
│    └─ routes                      // 路由和代理接口配置
│           ├─ default.js
│           ├─ designers.js
│           ├─ home.js
│           └─ index.js             // 路由和接口配置的入口文件
├─ package.json
└─ src                              // View层文件
       ├─ Components                // 公用组件
       │    ├─ base
       │    ├─ home
       │    ├─ index
       │    ├─ message
       │    ├─ modals
       │    ├─ page
       ├─ Views                     // 页面
       │    ├─ Default
       │    ├─ Error
       │    ├─ Home
       │    ├─ Include
       │    ├─ Messages
       │    └─ Shared
       └─ assets                    // 静态文件目录
              ├─ Jcrop
              ├─ es5-shim-master
              ├─ images
              ├─ jquery-1.10.2.min.js
              ├─ jquery-ui-1.8.24.min.js
              └─ layui

参考博客:

Node中间层实践(二)——搭建项目框架 https://juejin.cn/post/6844904191605866510

猜你喜欢

转载自blog.csdn.net/qq_26780317/article/details/125809741