集成Nunjucks

简介: 集成Nunjucks

集成Nunjucks


集成Nunjucks实际上也是编写一个middleware,这个middleware的作用是给ctx对象绑定一个render(view, model)的方法,这样,后面的Controller就可以调用这个方法来渲染模板了。


我们创建一个templating.js来实现这个middleware:


const nunjucks = require('nunjucks');

function createEnv(path, opts) {
    var
        autoescape = opts.autoescape === undefined ? true : opts.autoescape,
        noCache = opts.noCache || false,
        watch = opts.watch || false,
        throwOnUndefined = opts.throwOnUndefined || false,
        env = new nunjucks.Environment(
            new nunjucks.FileSystemLoader(path || 'views', {
                noCache: noCache,
                watch: watch,
            }), {
                autoescape: autoescape,
                throwOnUndefined: throwOnUndefined
            });
    if (opts.filters) {
        for (var f in opts.filters) {
            env.addFilter(f, opts.filters[f]);
        }
    }
    return env;
}

function templating(path, opts) {
    // 创建Nunjucks的env对象:
    var env = createEnv(path, opts);
    return async (ctx, next) => {
        // 给ctx绑定render函数:
        ctx.render = function (view, model) {
            // 把render后的内容赋值给response.body:
            ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {}));
            // 设置Content-Type:
            ctx.response.type = 'text/html';
        };
        // 继续处理请求:
        await next();
    };
}

module.exports = templating;


注意到createEnv()函数和前面使用Nunjucks时编写的函数是一模一样的。我们主要关心tempating()函数,它会返回一个middleware,在这个middleware中,我们只给ctx“安装”了一个render()函数,其他什么事情也没干,就继续调用下一个middleware。


使用的时候,我们在app.js添加如下代码:


const isProduction = process.env.NODE_ENV === 'production';

app.use(templating('views', {
    noCache: !isProduction,
    watch: !isProduction
}));


这里我们定义了一个常量isProduction,它判断当前环境是否是production环境。如果是,就使用缓存,如果不是,就关闭缓存。在开发环境下,关闭缓存后,我们修改View,可以直接刷新浏览器看到效果,否则,每次修改都必须重启Node程序,会极大地降低开发效率。


Node.js在全局变量process中定义了一个环境变量env.NODE_ENV,为什么要使用该环境变量?因为我们在开发的时候,环境变量应该设置为'development',而部署到服务器时,环境变量应该设置为'production'。在编写代码的时候,要根据当前环境作不同的判断。


注意:生产环境上必须配置环境变量NODE_ENV = 'production',而开发环境不需要配置,实际上NODE_ENV可能是undefined,所以判断的时候,不要用NODE_ENV === 'development'。


类似的,我们在使用上面编写的处理静态文件的middleware时,也可以根据环境变量判断:


if (! isProduction) {
    let staticFiles = require('./static-files');
    app.use(staticFiles('/static/', __dirname + '/static'));
}

这是因为在生产环境下,静态文件是由部署在最前面的反向代理服务器(如Nginx)处理的,Node程序不需要处理静态文件。而在开发环境下,我们希望koa能顺带处理静态文件,否则,就必须手动配置一个反向代理服务器,这样会导致开发环境非常复杂。


编写View


在编写View的时候,非常有必要先编写一个base.html作为骨架,其他模板都继承自base.html,这样,才能大大减少重复工作。


编写HTML不在本教程的讨论范围之内。这里我们参考Bootstrap的官网简单编写了base.html。


运行


一切顺利的话,这个view-koa工程应该可以顺利运行。运行前,我们再检查一下app.js里的middleware的顺序:


第一个middleware是记录URL以及页面执行时间:


app.use(async (ctx, next) => {
    console.log(`Process ctx.request.method{ctx.request.method} {ctx.request.url}...`);
    var
        start = new Date().getTime(),
        execTime;
    await next();
    execTime = new Date().getTime() - start;
    ctx.response.set('X-Response-Time', `${execTime}ms`);
});


第二个middleware处理静态文件:


if (! isProduction) {
    let staticFiles = require('./static-files');
    app.use(staticFiles('/static/', __dirname + '/static'));
}


第三个middleware解析POST请求:


app.use(bodyParser());


第四个middleware负责给ctx加上render()来使用Nunjucks:


app.use(templating('view', {
    noCache: !isProduction,
    watch: !isProduction
}));


最后一个middleware处理URL路由:


app.use(controller());

现在,在VS Code中运行代码,不出意外的话,在浏览器输入localhost:3000/,可以看到首页内容:


image.png

直接在首页登录,如果输入正确的Email和Password,进入登录成功的页面:


image.png

如果输入的Email和Password不正确,进入登录失败的页面:

image.png


怎么判断正确的Email和Password?目前我们在signin.js中是这么判断的:


if (email === 'admin@example.com' && password === '123456') {
    ...
}


当然,真实的网站会根据用户输入的Email和Password去数据库查询并判断登录是否成功,不过这需要涉及到Node.js环境如何操作数据库,我们后面再讨论。


扩展


注意到ctx.render内部渲染模板时,Model对象并不是传入的model变量,而是:


if (email === 'admin@example.com' && password === '123456') {
    ...
}


这个小技巧是为了扩展。


首先,model || {}确保了即使传入undefined,model也会变为默认值{}。Object.assign()会把除第一个参数外的其他参数的所有属性复制到第一个参数中。第二个参数是ctx.state || {},这个目的是为了能把一些公共的变量放入ctx.state并传给View。


例如,某个middleware负责检查用户权限,它可以把当前用户放入ctx.state中:

app.use(async (ctx, next) => {
    var user = tryGetUserFromCookie(ctx.request);
    if (user) {
        ctx.state.user = user;
        await next();
    } else {
        ctx.response.status = 403;
    }
});
相关文章
|
Oracle 关系型数据库
集成平台即服务(iPaaS)软件
本文研究全球及中国市场集成平台即服务(iPaaS)软件现状及未来发展趋势,侧重分析全球及中国市场的主要企业,同时对比北美、欧洲、中国、日本、东南亚和印度等地区的现状及未来发展趋势
|
7天前
|
人工智能 运维 安全
聚焦API安全未来,F5打造无缝集成的解决方案
聚焦API安全未来,F5打造无缝集成的解决方案
55 26
|
2月前
|
人工智能 并行计算 语音技术
fasterWhisper和MoneyPrinterPlus无缝集成
fasterWhisper是一款优秀的语音识别工具,现在它可以和MoneyPrinterPlus无缝集成了。
fasterWhisper和MoneyPrinterPlus无缝集成
|
4月前
|
监控 数据可视化 测试技术
集成阿里云 RPA 与现有系统
随着企业对自动化和数字化转型的需求不断增长,阿里云 RPA(机器人流程自动化)技术成为了提升业务效率和减少人工操作的重要工具。本文将介绍如何集成阿里云 RPA 与现有系统,以实现更高效的业务流程自动化。
|
4月前
|
资源调度 数据可视化 前端开发
基于mathlive从零将公式编辑器集成到可视化搭建平台
基于mathlive从零将公式编辑器集成到可视化搭建平台
153 0
|
消息中间件 XML 存储
集成的方式
系统集成-功能集成
93 0
|
消息中间件 存储 架构师
「集成架构」理解企业应用集成
「集成架构」理解企业应用集成
|
SQL 存储 消息中间件
基于 EventBridge 构建数据库应用集成
本文重点介绍 EventBridge 的新特性:数据库 Sink 事件目标。
243 0
基于 EventBridge  构建数据库应用集成
|
机器学习/深度学习 数据挖掘 开发者
集成| 学习笔记
快速学习集成。
119 0
集成| 学习笔记
|
网络协议 数据库 网络架构
集成IS-IS配置
文章目录 系列文章 实验拓扑 实验要求 实验配置 实验总结 一、 show clns neighbors 二、show clns protocol 三、show clns interface 四、show clns route 五、show isis topology 六、show isis database 要点 七、show isis route 八、show ip protocols 九、show ip route isis
177 0
集成IS-IS配置