当前位置: 首页 > 后端技术 > Node.js

Node中间层实践(二)——搭建项目框架

时间:2023-04-04 00:33:56 Node.js

版权声明:更多文章请访问我的个人网站KeyonY,转载请注明出处。项目地址:https://github.com/KeyonY/NodeMiddle脚手架?用过angular2和vue2的同学都知道,官方推荐的安装方式是通过专用的angular-cli和vue-cli快速搭建一个webpack编译打包的项目框架。受到这两个工具的启发,在项目之初开发了一个基于webpack的项目框架:使用express来承载webpack-dev-middleware和webpack-hot-middleware,用于热加载内置dev(开发环境)和production(生产环境)两种启动方式,技术选择,节点开发框架express和koa,二选一。Express更接近于WebFramework的概念;express功能极简,是一个完全由路由和中间件组成的web开发框架:本质上,一个Express应用就是在调用各种中间件;koa使用co作为底层运行框架,使用它完全忘记什么时候使用回调函数或回调壳;express历史较长,装机量大,文档齐全,第三方中间件较多;我选择了express作为节点开发框架。模板引擎对jade比较熟悉,因为我用node写过一个restFul网站(详见我的博客-NodeJS开发个人博客网站),所以这次直接选择了pug作为服务端模板引擎。pug是一个比较灵活的服务端模板,express配置起来也很简单,配置在根目录下的app.js文件中//设置模板引擎的类型app.set('viewengine','pug');//设置模板文件路径app.set('views',path.resolve(__dirname,'src/Views'));这样,在express渲染的时候使用res.render('Home/index',{}),指定对应的页面模板路径即可,第二个参数是pug页面要使用的数据内容,在json中格式。中间层和后端的异步通信其实就是一个ajax库,所以我选择了axios这个vue2官方推荐的ajax库,内置了axios.all(),可以在中间层代理多个后端请求并将它们一起返回,这很容易实现Bigpipe。因为模块化是网站的首页,需要考虑SEO,不能用前端框架,所以另一种思路是用webpack+es6/AMD来实现模块化。因此,使用webpack作为packer+View层的模块化,从前端层面实现了模块化和组件化。es6用于Contorl层的模块化,实现节点中间层的模块化。环境配置(启动文件)app.js是项目的启动文件,是express的配置文件,也是运行开发环境/生产环境的配置文件。通过node启动时配置的命令参数,app.js接收参数,然后运行相应的环境。我们需要安装cross-env插件npmi--save-devcross-env在package.json的脚本中配置:.."scripts":{"start":"cross-envNODE_ENV=productionnodeapp.js","dev":"cross-envNODE_ENV=devsupervisor-wapp.jsapp","build":"webpack--configbuild/webpack.prod.config.js"}...中这样就可以通过process.env.NODE_ENV获取节点启动的环境参数。这里我配置了开发环境(dev)和生产环境(production)开发环境:不压缩代码,打开devtool生成source-map,方便调试代码;生产环境:使用webpack进行打包、压缩、混淆等操作,最终将完成的代码(应用)输出到dist目录,然后启动node服务器运行应用;上述代码还使用了supervisor插件,它监听节点配置文件(app.js)的变化,自动重启节点。npmi--save-devsupervisor在前端层使用webpack-dev-middleware和webpack-hot-middleware来实现热加载。这样就实现了从中间层到前端的热加载。node中间层配置在根目录下新建config文件夹,提取一些常用的配置/参数和方法,写入config/config.js和config/common.js中。例如中间层启动的端口号、应用的根目录(path.resolve(__dirname,'../'))、后端服务器的IP、前端的描述和关键字等参数SEO都放在config.js中,通过AMD规范在所有使用的文件中统一引入,方便修改。app.jsvarexpress=require('express');varcookieParser=require('cookie-parser');varpath=require('path');varlocalOptions=require('./build/localOptions');varconfig=require('./config/config');varbodyParser=require('body-parser');varauth=require('./middleware/auth');varlog4js=require('./config/log4js');process.env.NODE_ENV=process.env.NODE_ENV?process.env.NODE_ENV:'production';varisDev=process.env.NODE_ENV==='dev';varapp=express();varport=config.port;app.set('viewengine','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中直接访问=过程。环境节点环境||'dev';app.locals.reload=true;app.use(cookieParser());app.use(bodyParser.urlencoded({extended:false}));if(isDev){//app.locals.pretty=真的;//开发环境,静态文件使用热插拔varwebpack=require('webpack');变种webpackDevMiddleware=require('webpack-dev-middleware');varwebpackHotMiddleware=require('webpack-hot-middleware');varwebpackDevConfig=require('./build/webpack.dev.config.js');varcompiler=webpack(webpackDevConfig);//热插拔app.use(webpackDevMiddleware(compiler,{publicPath:webpackDevConfig.output.publicPath,noInfo:true,stats:'errors-only'}))app.use(webpackHotMiddleware(compiler,{heartbeat:1000,noInfo:真的,}));//不要执行热交换varreload=require('reload');varhttp=require('http');varserver=http.createServer(app);//重新加载(服务器,应用程序);重新加载(应用程序);server.listen(port,()=>{console.log('App【dev】现在运行在端口'+port+'!');});//静态目录设置必须有,开发环境读取的vendor.js不是内存文件;//静态目录设置必须放在reload之后,避免页面引入reload.js错误app.use(express.static(path.join(config.root,'src')));app.use('/',require(path.join(config.configRoot,'/路线')));}else{//线上环境不用监听,启动节点服务即可//设置节点的静态文件目录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】现在运行在端口'+port+'!');})}//捕获404错误并将它们传递给错误路由app.use('*',auth,(req,res,next)=>{leterr=newError('NotFound');err.status=404;next(err);});//捕获错误,跳转到错误页面app.use((err,req,res,next)=>{constsc=err.status||500;if(err.status==405){res.redirect(config.cndesignOrigin+'/Home/GuideAuthentication');return;}res.status(sc);//log4js.error('\r\nStatus:'+sc+"\r\nMessage:"+err.message需要写在这里+"\r\nHref:"+localOptions.baseUrl+req.originalUrl+"\r\nUser-agent:"+req.headers['用户代理']);res.render('Error/404',{呃错误:错误,状态:sc,消息:err.message,用户信息:req.userInfo_||{hasLogin:false}});});注意ErrorHandle挂载的顺序,一般挂载到app.use()下,放在最后,因为ErrorHandle有4个参数,第一个参数err可以被next(err)中的抛出route,这样所有的routes都可以随时抛出错误,让ErrorHandle捕获。看看目录结构: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层file:包括节点服务器配置、路由和代理接口│├─common.js//中间层逻辑处理的公共方法│├─config.js//节点服务器配置│└─routes//路由和代理接口配置│├─default.js│├─designers.js│├─home.js│└─index.js//路由和接口配置的入口文件├─package.json└─src//视图层文件├─Components//公共组件│├─base│├─home│├─index│├─message│├─modals│├─page├─Views//page│├─Default│├─Error│├─Home│├─包括│├─Messages│└─Shared└─assets//静态文件目录├─Jcrop├─es5-shim-master├─images├─jquery-1.10.2.min.js├─jquery-ui-1.8.24.min.js└─layui欢迎继续关注本博的更新Node中间层实践(一)——基于NodeJS的全栈开发Node中间层实践(二)——搭建项目框架Node中间层实践(3)——webpack配置Node中间层实践(四)——模板引擎pugNode中间层实践(五)——express-中间层的逻辑处理