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

启动项目

通过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. Window Azure ServiceBus Messaging消息队列技术系列2-编程SDK入门

    各位,上一篇基本概念和架构中,我们介绍了Window Azure ServiceBus的消息队列技术的概览.接下来,我们进入编程模式和详细功能介绍模式,一点一点把ServiceBus技术研究出来. 本 ...

  2. 分布式入门之2:Quorum机制

    1.  全写读1(write all, read one) 全写读1是最直观的副本控制规则.写时,只有全部副本写成功,才算是写成功.这样,读取时只需要从其中一个副本上读数据,就能保证正确性. 这种规则 ...

  3. 自定义子tabBar

    基本设置 设置APPIcon(直接拖图片) 设置启动图片 将launch Screen File里的LaunchScreen.xib给删掉 点击launch image source框内的Use As ...

  4. SVN强制退出,出现被锁的情况解决方法

    1. 打开终端 输入cd Desktop enter之后 输入ls enter键 2. 输入cd  文件名(比如IOS)enter键 3. 输入LS enter 4. find . | grep &q ...

  5. regeneratorRuntime未定义

    babel-preset-stage-2 { "presets": ["es2015", "stage-2"], "plugins ...

  6. jquery autocomplete

    <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="http: ...

  7. c++源文件后缀名

    C中: 头文件后缀名: .h 源文件后缀名: .c C++中: 头文件后缀名: .h,   .hpp,   .hxx 源文件后缀名:.cpp,   .cc,   .cxx,   .C   .c++ 现 ...

  8. ThinkPhp的搭建

    一般而言,环境的搭建都是很复杂的,但是说句实话,php的环境是我见过最简单的,首先下载一个XAMPP集成软件包(这种软件包还有好多,但是我还是喜欢这个啊),然后直接安装,一路NEXT下午就ok了. 这 ...

  9. stm8的IIC库的使用

    一.前言 stm8是一款低功耗的MCU芯片,它具备stm32库函数和资源丰富的优势.也同时具有价格便宜,低功耗的特点.在一些项目中,能起到很好的作用.下面我介绍一下stm8的IIC硬件库函数驱动代码及 ...

  10. 向STM32 CUBE MX 生成的工程里移植stemwin

    我参考这个文章做的: http://bbs.armfly.com/read.php?tid=1678 这次添加的是没有os的版本 另外跟用不用hal库没关系 1. keil自带了emwin 2. 用c ...