这一次整理的内容是项目主文件和如何启动项目。

启动项目

通过nodejs官网的例子https://nodejs.org/docs/latest-v4.x/doc/api/synopsis.html我们可以知道,在项目目录下打开终端命令行,并且输入如下命令即可启动服务:

node app.js

其中app.js是项目的主文件。

那是因为这个主文件里面有创建服务和监听端口的语句:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000; const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
}); server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});

而我们现在使用的是express框架,它的写法有些不一样。express4.0之后的版本,项目目录下会有bin/这个目录,这个目录专门用于自定义启动脚本,这样就把与启动服务的代码和主文件分离了,而且你可以定义多个启动脚本,而不用去修改app.js这个主文件。

我们来看看bin/www这个文件是什么内容:

#!/usr/bin/env node

var app = require('../app');
app.set('port', PORT || 3000); var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ', app.get('port'), " with pid ", process.pid);
});

然后我们逐行解释一下:

#!/usr/bin/env node
/*这一句是写给类unix系统看的
*如果用户没有将nodejs装在默认的/usr/bin路径里
*当系统看到这一行的时候,首先会到env设置里查找nodejs的安装路径
*再调用对应路径下的解释器程序完成操作
*/
var app = require('../app');
//引入app主应用
app.set('port', PORT || 3000);
//设置端口为环境变量.env文件里的PORT,如果.env里没有,就默认3000
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ', app.get('port'), " with pid ", process.pid);
});
/*app.listen(path,[callback])的写法是启动一个socket连接,然后在给定的端口上监听连接
*app.get(name)的写法是获取app设置,设置的时候通过app.set('port', 'my port');来设置。
*/

package.json

package.json文件描述了一个NPM包的所有相关信息,包括作者、简介、包依赖、构建等信息。格式必须是严格的json格式。

{
"name": "xia",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "./node_modules/.bin/gulp develop --gulpfile gulp_dev.js",
"ci": "./node_modules/.bin/gulp test --gulpfile gulp_test.js",
"assets": "./node_modules/.bin/gulp build --gulpfile gulp_build.js",
"assets_dev": "./node_modules/.bin/gulp build --dev --gulpfile gulp_build.js",
"watch": "./node_modules/.bin/gulp watch --gulpfile gulp_build.js"
},
"dependencies": {
"async": "2.0.1",
"body-parser": "1.13.3",
"connect-multiparty": "2.0.0",
"connect-redis": "3.0.2",
"cookie": "0.2.3",
"cookie-parser": "1.3.3",
"crypto": "0.0.3",
"dotenv": "1.2.0",
"excel-export": "0.5.1",
"express": "4.13.3",
"express-session": "1.13.0",
"formidable": "1.0.16",
"glob": "5.0.15",
"jsonfile": "2.2.2",
"log4js": "0.6.35",
"morgan": "1.6.1",
"raven": "0.8.1",
"request-promise": "1.0.2",
"run-sequence": "1.1.3",
"serve-favicon": "2.3.0",
"sha1": "1.1.1",
"swig": "1.4.2",
"write-file-stdout": "0.0.2"
},
"devDependencies": {
"gulp-nodemon": "2.0.2",
"gulp": "3.9.0",
"gulp-bower": "0.0.10",
"gulp-clean": "0.3.1",
"gulp-cssmin": "0.1.7",
"gulp-eslint": "1.0.0",
"gulp-if": "1.2.5",
"gulp-uglify": "1.5.3",
"gulp-rev-all-fixed": "0.8.24",
"gulp-livereload": "3.8.0",
"gulp-plumber": "1.0.0",
"gulp-replace": "0.5.4",
"gulp-rev-all": "0.8.21",
"gulp-sass": "2.0.4",
"compass-mixins": "0.12.7",
"node-sass": "3.4.2",
"yargs": "3.25.0"
}
}

其中name和version是最重要的两个字段,也是发布到npm平台标示,必须有。

其中private设置为true,这个包将不会发布到npm。

scripts可以设置一些自定义的脚本,我们项目的启动服务,处理静态文件的命令就定义在这里。

dependencies指定依赖的包,如果是开发中需要的包,可以指定在devDependencies,建议严格匹配包的版本。

scripts中的脚本的写法前面都加上了./node_modules/.bin/是因为这里后面命令都是gulp构建工具的命令,而gulp包在devDependencies里,所以加上这个前缀。

而后面的gulp build --gulpfile gulp_build.js这样的写法是gulp构建工具执行任务时的命令。

app.js

app.js就是node项目主文件。

var express = require('express');
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var glob = require('glob');
var path = require('path');
var bodyParser = require('body-parser'); var swig = require('swig');
var staticTag = require('./swig/static');
var morgan = require("morgan"); var app = express();
var client; app.locals.ENV = NODE_ENV;
app.locals.ENV_DEV = (NODE_ENV === 'dev'); // view engine setup
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('view cache', false);
app.set('views', path.join(__dirname, 'views'));
swig.setDefaults({cache: false});
swig.setDefaults({loader: swig.loaders.fs(__dirname + '/views')}); staticTag.init(swig); app.use(session({
cookie: {
maxAge: 2502000 * 1000
},
name: 'lbn_sid',
secret: 'what are you thinking?',
store: new redisStore({
ttl: 2502000,
url: REDIS_URL
}),
saveUninitialized: false,
resave: false
}));
// app.use(morgan('combined'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true,
limit: '10mb'
})); app.use('/' + global.STATIC_URL, express.static(path.join(__dirname, STATIC_DIR))); var controllers = glob.sync('./controllers/*.js');
controllers.forEach(function (controller) {
require(controller)(app);
}); app.use(function (err, req, res, next) {
res.locals = {env: NODE_ENV};
// treat as 404
if (err.message
&& (~err.message.indexOf('not found')
|| (~err.message.indexOf('Cast to ObjectId failed')))) {
return next();
}
res.status(500).render('500', { error: err.stack });
}); app.use(function (req, res, next) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not found'
});
}); module.exports = app;

我们来看看里面都是什么东西:

var express = require('express'); //引入express框架
var session = require('express-session'); //设置session的中间件
var redisStore = require('connect-redis')(session); //实现redis存储session
var glob = require('glob'); //使用类似shell的模式语法匹配文件路径
var path = require('path'); //path模块用于处理和转换文件路径
var bodyParser = require('body-parser'); //解析请求的body的中间件 var swig = require('swig'); //swig模板引擎
var staticTag = require('./swig/static'); //swig模板相关设置
var morgan = require("morgan"); //控制台日志 var app = express(); //创建一个express应用 app.locals.ENV = NODE_ENV; //将环境变量NODE_ENV存在app.locals里
app.locals.ENV_DEV = (NODE_ENV === 'dev'); //是否是dev环境 // view engine setup
app.engine('html', swig.renderFile); //使用swig渲染html文件
app.set('view engine', 'html'); //设置默认页面扩展名
app.set('view cache', false); //设置模板编译无缓存
app.set('views', path.join(__dirname, 'views')); //设置项目的页面文件,也就是html文件的位置
swig.setDefaults({cache: false}); //关闭swig模板缓存
swig.setDefaults({loader: swig.loaders.fs(__dirname + '/views')}); //从文件载入模板,请写绝对路径,不要使用相对路径 staticTag.init(swig); //这个init函数是自定义的,对swig模板做了一些自定义设置 app.use(session({ //设置session中间件的写法,session会存在服务端
cookie: {
maxAge: 2502000 * 1000 //设置最大生命周期,过了这个时间后cookie会失效,单位毫秒
},
name: 'lbn_sid', //用来保存session的cookie名称
secret: 'what are you thinking?', //用来对session数据进行加密的字符串.这个属性值为必须指定的属性
store: new redisStore({ //设置session的存储仓库为redis数据库
ttl: 2502000, //redis session生命周期,单位秒
url: REDIS_URL //redis缓存服务地址
}),
saveUninitialized: false, //false选项不会强制存储未初始化的session到redis里,未初始化意味着新的还没有修改的
resave: false //如果是true选项,强制重新存储session到redis里,即使session没有被修改,false意味着如果没有变化就不用重新存
}));
// app.use(morgan('combined')); //morgan控制台日志,会在控制台输出所有http请求日志,combined是标准Apache日志格式
app.use(bodyParser.json()); //bodyParser.json是用来解析请求体的json数据格式
app.use(bodyParser.urlencoded({
extended: true,
limit: '10mb'
}));
/*bodyParser.urlencoded则是用来解析我们通常的form表单提交的数据,
*也就是请求头中包含这样的信息: Content-Type: application/x-www-form-urlencoded
*extended选项为true会使用qs library来解析数据,false会使用querystring来解析
*limit选项限制请求体的大小

*/
app.use('/' + global.STATIC_URL, express.static(path.join(__dirname, STATIC_DIR)));
//为静态资源的请求添加虚拟路径,只有请求静态资源的路径前加了global.STATIC_URL前缀后,才可请求成功
var controllers = glob.sync('./controllers/*.js'); //获取到controllers文件夹下的所有js文件,这些文件里都是路由
controllers.forEach(function (controller) {
require(controller)(app);
});
//将所有路由循环到主文件中使其生效
app.use(function (err, req, res, next) { //当请求出现500错误,渲染500错误页面
res.locals = {env: NODE_ENV};
// treat as 404
if (err.message
&& (~err.message.indexOf('not found')
|| (~err.message.indexOf('Cast to ObjectId failed')))) {
return next();
}
res.status(500).render('500', { error: err.stack });
}); app.use(function (req, res, next) { //当请求出现404错误,渲染404错误页面
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not found'
});
}); module.exports = app; //将app应用导出成模块

这其中session的设置值得注意,session的设置写在了app.use()中,也就是中间件中,中间件也是路由,只是所有的请求都会经过它的处理。这里设置session时有一个cookie的设置,这个cookie就是session的唯一标示,是sessionId,也就是说,第一次访问网站的时候,在请求通过session设置的中间件时,响应头里会设置一个set-cookie来强制浏览器存储一个cookie,也就是在浏览器存下sessionId,然后会在node端新建一个session,这里浏览器存的sessionId和node端的session是对应关系,之后的请求也会经过session设置的中间件,此时的请求头里会自动带上浏览器的所有cookie,当中间件发现已经有sessionId的时候,就不会新建了,只用更新对应的session就可以了。

express+gulp构建项目(二)启动项目和主文件的更多相关文章

  1. 【转载】Visual Studio2017中如何设置解决方案中的某个项目为启动项目

    在C#的应用程序开发过程中,一个完成的解决方案可能包含多个子项目,有时候需要设置某一个子项目为启动项目,在Visual Studio 2017集成开发工具中,设置解决方案中的某个项目为启动项目的操作方 ...

  2. 用gulp构建你的前端项目

    前言 前端技术发展日新月异,随着模块化.组件化的提出,前端变得越来越复杂,静态资源越来越多,那么对静态资源的处理,如压缩,合并,去掉调试信息.. 如果还是人工去处理,效率非常之低且还容易出错,于是自动 ...

  3. Angular企业级开发(6)-使用Gulp构建和打包前端项目

    1.gulp介绍 基于流的前端自动化构建工具,利用gulp可以提高前端开发效率,特别是在前后端分离的项目中.使用gulp能完成以下任务: 压缩html.css和js 编译less或sass等 压缩图片 ...

  4. express+gulp构建项目(一)项目目录结构

    express是基于nodejs平台的web框架,它可以让我们快速开发出web引用.而gulp是一种自动构建工具,非常强大,有了它,能帮我们完成很多繁琐的工作,例如,静态文件的压缩,为静态文件加上哈希 ...

  5. express+gulp构建项目(四)env环境变量

    这里的文件的作用是负责设置env环境变量和日志. index.js try { require('dotenv').load({silent: true}); //dotenv从一个.env文件中读取 ...

  6. express+gulp构建项目(三)gulp任务

    这次来看一看gulp是怎么工作的. tasks/paths.js paths.js文件里存放的是gulp任务中需要导入的文件的路径和导出的路径. /** * gulp.src 地址 * gulp.de ...

  7. express+gulp构建项目(五)swig模板

    这里的文件负责配置swig模板引擎. index.js var jsonHash = require('./json_file'); var staticTag = require("./t ...

  8. eclipse项目中启动项目无法载入类

    在eclipse 项目中,当载入jar包后,加载里面的包,可以找到此类,但是编译运行的时候报错java.lang.ClassNotFoundException: 1,路径名未写正确: 2,配置出错; ...

  9. SpringMVC项目,启动项目怎么总是报找不到log4j.properties文件

    具体操作:右键项目---->properties--->Java Build Path--->source--->Add Folder --->选择log4.proper ...

随机推荐

  1. SQL Server 2008创建oracle链接服务器(心得)

    操作系统是32位的情况下,曾经没费太多时间创建好了到oracle的链接服务器.主要要点就是: 1.安装oracle精简客户端.当时我用的是版本比较低的“oracle9i310-客户端简化版”,安装好了 ...

  2. 《Spark 官方文档》机器学习库(MLlib)指南

    spark-2.0.2 机器学习库(MLlib)指南 MLlib是Spark的机器学习(ML)库.旨在简化机器学习的工程实践工作,并方便扩展到更大规模.MLlib由一些通用的学习算法和工具组成,包括分 ...

  3. PXC(percona xtradb cluster)新加节点避免SST的方法

    环境: node1:192.168.0.100  pxc节点 node2:192.168.0.101  新节点 把新加入的节点先建立为node1的从库,可以使用mysqldump或innobackup ...

  4. js定义对象的几种容易犯的错误

    //js定义对象的几种容易犯的错误function Person() { getName = function (){ console.info(1); }; return this;}//Perso ...

  5. HTML 5 视频

    HTML 5 视频 ======================================================================================= 如今 ...

  6. javascirpt对象运用与JS变量

    abcdefghijklmnopqrstuvwyz String 对象方法 charAt() 方法可返回指定位置的字符.stringObject.charAt(index)(index从0开始)[ht ...

  7. .NET蓝牙开源库:32feet.NET

    在用C#调用蓝牙编程一文中我留个小悬念就是:InTheHand.Net.Personal.dll是怎么来的?这篇文章来解答这个问题,InTheHand.Net.Personal.dll就是来源于今天要 ...

  8. linux内核追踪——find_next_bit函数详详详解

    写在前面 宗旨:把话说清楚,把道理讲透彻. 约定:所有代码均来自Linux内核2.6.24版. 建议:本文介绍得十分详细,但也略显繁琐,读者可以先看“Ⅴ.总结”部分带注释的源码,如果哪里不清楚,再回头 ...

  9. Kanzi编程基础2 - Kanzi节点读取和属性设置

    UI设计师在Kanzi studio把Kanzi的节点做好后,就要编码读取这些节点并根据实际功能去控制刷新它. Kanzi读取节点的api发生过很多次变化,从2.7.2.8到3.0,每次变化都比较大, ...

  10. queen8

    八皇后问题 八皇后问题的数学模型:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上.八皇后问题可 ...