资讯专栏INFORMATION COLUMN

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

DrizzleX / 3337人阅读

摘要:项目地址脚手架使用过,的同学都清楚,官方推荐的安装方式是通过专用的来快速搭建一个由编译打包的项目框架。用在层的模块化,在中间层实现了模块化。这样,从中间层到前端都实现了热加载。

版权声明:更多文章请访问我的个人站Keyon Y,转载请注明出处。

项目地址:https://github.com/KeyonY/NodeMiddle

脚手架?

使用过angular2,vue2的同学都清楚,官方推荐的安装方式是通过专用的angular-cli、vue-cli来快速搭建一个由webpack编译、打包的项目框架。

受这两个工具的启发,我在项目之初开发一个基于webpack的项目框架:

使用express搭载webpack-dev-middleware和webpack-hot-middleware进行热加载

内置dev(开发环境)和 production(生产环境)两种启动方式

技术选型 node开发框架

express和koa二选一。

express的更贴近Web Framework这一概念;

express功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件;

koa使用co作为底层运行框架,使用它完全忘记了什么时候回调函数或者callbackshell;

express历史更久,装机量大,文档完整,第三方的中间件也很多;

我选择了express作为node开发框架。

模板引擎

由于之前用node写过restFul的网站(详见我的博客-NodeJS开发个人博客网站),比较熟悉jade,所以这次直接选择了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格式。

中间层与后端的异步通信

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

模块化

因为是网站前台页面,需要考虑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的scripts中配置:

...
"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,实现了热加载。

这样,从中间层到前端都实现了热加载。

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("
 Status: "+ sc + "
 Message: " + err.message + "
 Href: " + localOptions.baseUrl + req.originalUrl + "
 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中间层实践(一)——基于NodeJS的全栈式开发
Node中间层实践(二)——搭建项目框架
Node中间层实践(三)——webpack配置
Node中间层实践(四)——模板引擎pug
Node中间层实践(五)——express-中间层的逻辑处理

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92710.html

相关文章

  • 如何打造一个令人愉悦的前端开发环境(三)

    摘要:的最后一个大招就是替换一些传统的服务端语言,例如,,等,在业务层上面使用来开发服务端完全不成问题。更多的的使用细节和技巧建议关注美团博客大搜车论坛下一篇我们开启如何结合和搭建一个开发环境和项目目录 往期回顾 前面2期都讲得是浏览器端的东西比较多,包括Webpack,虽然是Node处理的,但是还是浏览器端用的多,对于现在的前端开发来说,不懂一点服务端的东西,简直没办法活,一般的招聘要求都...

    cgh1999520 评论0 收藏0
  • Node间层实践(一)——基于NodeJS的全栈式开发

    摘要:总结我觉得,以后基于的全栈式开发的模式将会越来越流行,这也会引领前端步入工程化时代。欢迎继续关注本博的更新中间层实践一基于的全栈式开发中间层实践二搭建项目框架中间层实践三配置中间层实践四模板引擎中间层实践五中间层的逻辑处理 版权声明:更多文章请访问我的个人站Keyon Y,转载请注明出处。 前言 近期公司有个新项目,由于后端人手不足,我果断的提议用node中间层的方案,得到了老大的支持...

    warkiz 评论0 收藏0
  • Node间层实践(三)——webpack配置

    摘要:的意思是,如果碰到不能的情况,就整页刷新首页路由开发环境中使用了,需要将每一个的配置中写上欢迎继续关注本博的更新中间层实践一基于的全栈式开发中间层实践二搭建项目框架中间层实践三配置中间层实践四模板引擎中间层实践五中间层的逻辑处理 版权声明:更多文章请访问我的个人站Keyon Y,转载请注明出处。 这里没什么可说的,webpack的配置和插件实在太多了,用的时候查文档就行了。 项目地...

    kelvinlee 评论0 收藏0
  • 构建前端项目

    摘要:解决思路服务器端渲染服务器端和前端公用同一个应用,然后通过构建工具及配置,确定哪些组件需要再服务器端渲染,那些组件需要再客户端渲染。服务器端渲染,由框架与构建工具配合,并依据一定的项目结构和编码方式,共同运行。 分离 为什么需要 前后端分离、web服务器与static服务器分离: 前端与后端耦合 (需求) 自动化、工程化的构建前端的代码 (基础条件) 模块化、组件化,项目共享代码 (...

    mindwind 评论0 收藏0

发表评论

0条评论

DrizzleX

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<