集成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)软件现状及未来发展趋势,侧重分析全球及中国市场的主要企业,同时对比北美、欧洲、中国、日本、东南亚和印度等地区的现状及未来发展趋势
|
29天前
|
人工智能 运维 安全
聚焦API安全未来,F5打造无缝集成的解决方案
聚焦API安全未来,F5打造无缝集成的解决方案
75 26
|
3月前
|
人工智能 并行计算 语音技术
fasterWhisper和MoneyPrinterPlus无缝集成
fasterWhisper是一款优秀的语音识别工具,现在它可以和MoneyPrinterPlus无缝集成了。
fasterWhisper和MoneyPrinterPlus无缝集成
|
3月前
|
数据采集 存储 算法
ScrapySharp框架:小红书视频数据采集的API集成与应用
ScrapySharp框架:小红书视频数据采集的API集成与应用
|
5月前
|
监控 数据可视化 测试技术
集成阿里云 RPA 与现有系统
随着企业对自动化和数字化转型的需求不断增长,阿里云 RPA(机器人流程自动化)技术成为了提升业务效率和减少人工操作的重要工具。本文将介绍如何集成阿里云 RPA 与现有系统,以实现更高效的业务流程自动化。
|
5月前
|
资源调度 数据可视化 前端开发
基于mathlive从零将公式编辑器集成到可视化搭建平台
基于mathlive从零将公式编辑器集成到可视化搭建平台
173 0
|
数据可视化 物联网 数据挖掘
应用开发组件功能介绍(一)
应用开发组件功能介绍(一)
263 0
|
消息中间件 XML 存储
集成的方式
系统集成-功能集成
102 0
|
消息中间件 存储 架构师
「集成架构」理解企业应用集成
「集成架构」理解企业应用集成
|
机器学习/深度学习 数据挖掘 开发者
集成| 学习笔记
快速学习集成。
122 0
集成| 学习笔记