Nodejs Express 系列之二:Express 骨架 Skeleton

前言

本文是笔者所总结的有关 Nodejs Express 系列之一,本文将从实战的角度讲解如何快速的搭建一个 Express 的开发骨架;

本文为作者原创作品,转载请注明出处;

生成项目骨架

手动的方式

可以通过手动安装 express 包的方式来构建 Express 项目,

  1. 创建项目路径

    1
    2
    $ mkdir myapp
    $ cd myapp
  2. 创建 npm 管理 Node.js 的包依赖,

    1
    $ npm init

    有关 npm 的详细介绍参考笔者的另一篇文章 NPM

  3. 使用 npm 安装 Express 依赖包,两种方式,
    永久的将 express 作为 dependencies 安装到 myapp 中,

    1
    $ npm install express --save

    临时的将 express 安装到 myapp 中,不将其添加到 dependencies 当中,

    1
    $ npm install express --no-save

通过上述的方式,我们便构建了使用 npm 来管理的 myapp 工程,并且引入了 express;这种方式笨拙但灵活,可以按照你的意志来搭建 Express 工程的骨架;

使用 Express Application Generator

手动的方式过于的笨拙,方方面面都需要自己搭建,且容易出错或者遗漏什么;通过 Express Application Generator 可以快速的构建其你本地的 Express 开发环境,

  1. 全局安装 express-generator

    1
    $ npm install express-generator -g
  2. 显示帮助

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ express -h

    Usage: express [options] [dir]

    Options:

    -h, --help output usage information
    --version output the version number
    -e, --ejs add ejs engine support
    --hbs add handlebars engine support
    --pug add pug engine support
    -H, --hogan add hogan.js engine support
    -v, --view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
    --git add .gitignore
    -f, --force force on non-empty directory
  3. 使用 ejs 模板引擎来创建 myapp 工程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $ express --view=ejs myapp

    create : myapp
    create : myapp/package.json
    create : myapp/app.js
    create : myapp/public
    create : myapp/views
    create : myapp/views/index.ejs
    create : myapp/views/error.ejs
    create : myapp/routes
    create : myapp/routes/index.js
    create : myapp/routes/users.js
    create : myapp/bin
    create : myapp/bin/www
    create : myapp/public/javascripts
    create : myapp/public/images
    create : myapp/public/stylesheets
    create : myapp/public/stylesheets/style.css

    install dependencies:
    $ cd myapp && npm install

    run the app:
    $ DEBUG=myapp:* npm start
  4. 安装项目依赖

    1
    2
    $ cd myapp
    $ npm install
  5. 在 Linux 或者 Mac 上启动,

    1
    2
    3
    4
    5
    6
    7
    8
    $ DEBUG=myapp:* npm start
    > myapp@0.0.0 start /Users/mac/tmp/myapp
    > node ./bin/www

    myapp:server Listening on port 3000 +0ms
    GET / 200 13.937 ms - 207
    GET /stylesheets/style.css 200 4.443 ms - 111
    GET /favicon.ico 404 2.310 ms - 896
  6. 通过 http://localhost:3000/ 访问 myapp

  7. 目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    .
    ├── app.js
    ├── bin
    │ └── www
    ├── package.json
    ├── public
    │ ├── images
    │ ├── javascripts
    │ └── stylesheets
    │ └── style.css
    ├── routes
    │ ├── index.js
    │ └── users.js
    └── views
    ├── error.pug
    ├── index.pug
    └── layout.pug

    7 directories, 9 files

项目骨架分析

导入项目骨架

我们可以将项目骨架导入自己所熟悉的 Node.js 开发工具中,笔者使用的是 IntelliJ IDEA,下面介绍如何将由 express-generator 所生成的 myapp 工程导入,

  1. 选择 File -> Open…,然后选择 myapp 工程目录即可
    import skeleton into idea.png
  2. 工程导入以后,它会被自动的识别为 Node.js 工程;
    skeleton into idea.png

项目骨架分析

  1. package.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {
    "name": "myapp",
    "version": "0.0.0",
    "private": true,
    "scripts": {
    "start": "node ./bin/www"
    },
    "dependencies": {
    "body-parser": "~1.18.2",
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "ejs": "~2.5.7",
    "express": "~4.15.5",
    "morgan": "~1.9.0",
    "serve-favicon": "~2.4.5"
    }
    }

    可以看到,入口方法在 ./bin/www 中

  2. ./bin/www

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #!/usr/bin/env node

    /**
    - Module dependencies.
    */

    var app = require('../app');
    var debug = require('debug')('myapp:server');
    var http = require('http');

    /**
    - Get port from environment and store in Express.
    */

    var port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);

    /**
    - Create HTTP server.
    */

    var server = http.createServer(app);

    /**
    - Listen on provided port, on all network interfaces.
    */

    server.listen(port);
    server.on('error', onError);
    server.on('listening', onListening);

    /**
    - Normalize a port into a number, string, or false.
    */
    ......

    入口模块中主要执行了下面几件事情

    1. 导入 app 模块,代码第 7 行,注意,这里省略了 .js 后缀;
    2. 将 app 作为参数创建 server 实例,代码第 22 行;
    3. 启动 server 在 3000 端口上的监听,代码第 28 行;
  3. app.js,这是 Express 骨架中最为核心的部分了,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    var express = require('express');
    var path = require('path');
    var favicon = require('serve-favicon');
    var logger = require('morgan');
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');

    var index = require('./routes/index');
    var users = require('./routes/users');

    var app = express();

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

    // uncomment after placing your favicon in /public
    //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
    app.use(logger('dev'));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));

    app.use('/', index);
    app.use('/users', users);

    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
    });

    // 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');
    });

    module.exports = app;

    归纳起来注意以下几点,

    1. 导入第三方模块,cookie-parserbody-parser
    2. 导入自定义模块,这里初始化定义了两个模块,indexusers;这里要注意的是,如果将来有更多的自定义模块的时候,必须在这里导入才能够生效
    3. 初始化 app,并最终将该 app 实例作为模块对象导出;
    4. 在 app 上初始化 middleware 和相应的 routers,这部分逻辑参考代码 19 - 44 行;
  4. views/ 存放的是 ejs 模板信息
  5. public/ 存放的是前端静态资源,包括 css、js 等;

附录

升级 Express Application Generator

笔者当前本地使用的 Express Application Generator 版本是 4.14.1,而最新的 Release 版本是 4.15.5,那么如何升级到最新版本呢?

1
$ sudo npm install -g express-generator

这样,express-generator 的版本就自动升级为最新的版本了,

1
2
$ express --version
4.15.5

备注,如果你本地的 express-generator 是 3.x,要升级到 4.x 会更麻烦,首先要删除旧的 3.x 版本,然后再执行上述命令的安装;

https://stackoverflow.com/questions/23298856/how-to-update-express-to-version-4

升级 Express 模块

参考 https://www.npmjs.com/package/npm-check-updates

References