轻量级 Express 服务器:用 Pug 模板引擎实现动态参数传递

前言

之前公司的后台项目有个需求,要在后端生成使用 canvas 元素绘制了一些内容的 html 页面,并统一转换成 pdf 文件再发送给前端供用户下载。这就要用到服务端渲染(SSR,即 server side render),之前我介绍过如何使用 nuxt2 生成基于 vue 的 ssr 项目,若专门为这点小需求去使用 nuxt,无疑是大材小用了。

我决定直接通过 express 搭建个服务器来实现,在过程中遇到个问题------html 中的 canvas 绘制的内容是动态的,如何把在服务器获取到的参数传递到 html 页面中呢?本文就来介绍怎样通过 pug 模板引擎实现在 express 搭建的服务器中向视图模板传递参数。

express 搭建服务器

我们创建项目 express-pug 来进行演示,使用 pnpm 作为项目的包管理器。然后执行 pnpm initpnpm add express 安装上 express。

启用 esm

新建 server.js 作为服务器文件,在里面引入 express 并搭建服务器:

javascript 复制代码
// server.js
import express from 'express'
const app = express()
app.listen(4396, () => {
  console.log('服务器开启')
})

请注意,我没有使用 CommonJS 语法 const express = require('express') 来引入 express,而是使用了 EcmaScript modules(esm)的导入语法。这需要在 package.json 中配置 "type" 属性为 "module"

告诉 node 在执行时将 js 都解释为 es 模块。如此,在 express 的源码中虽然使用的是 CommonJS 的导出语法 module.exports

javascript 复制代码
/*!
 * express
 * Copyright(c) 2009-2013 TJ Holowaychuk
 * Copyright(c) 2013 Roman Shtylman
 * Copyright(c) 2014-2015 Douglas Christopher Wilson
 * MIT Licensed
 */

'use strict';

module.exports = require('./lib/express');

但是在我们项目的 server.js 中导入时, module.exports 对象会作为默认导出提供。

配置脚本命令

在项目的 package.json 中,给 "scripts" 添加上 "dev": "node server"

json 复制代码
{
  "name": "express-pug",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "node server"
  },
  "dependencies": {
    "express": "^4.21.2"
  }
}

就可以在命令行执行 pnpm dev 启动服务器了:

添加中间件

在 server.js 中使用 app.get() 添加中间件:

javascript 复制代码
// server.js 省略部分代码
const app = express()
app.get('/', (req, res) => {
  // 在这里生成视图模板并发送给客户端
})

在浏览器地址栏输入 localhost:4396/ 后,请求就会被该中间件拦截。我们就在这个中间件内,编译生成视图模板并作为响应返回给客户端。这部分的处理,需要用到 pug 模板引擎。

使用 pug

express 良好地集成了 pug,在 express 中使用 pug,只需要简单的 3 步:

安装 pug

shell 复制代码
pnpm add pug

创建模板文件

在项目中创建 views 目录用来存放模板文件,创建 views\index.pug 作为模板。在 server.js 中通过 app.set('view', './views') 告诉 express 模板文件的存放位置。也可以不明确设置,因为默认的存放目录就是 ./views

在之前创建的中间件里,通过 res.render('index'),将视图模板 index.pug 编译成 html 字符串,返回给浏览器呈现:

javascript 复制代码
// server.js
app.get('/', (req, res) => {
  res.render('index')
})

index.pug

pug 文件拥有自己特殊的语法,如果我们想返回给前端的 html 内容如下:

html 复制代码
<html lang="en">
  <head>
    <title>Document</title>
    <style>
      #my-canvas {
        background-color: antiquewhite;
      }
    </style>
  </head>
  <body>
    <canvas id="my-canvas">当前浏览器不支持canvas</canvas>
    <script>
      const canvas = document.getElementById('my-canvas')
      const ctx = canvas.getContext('2d')
      ctx.fillStyle = '#358DFD'
      ctx.fillRect(10, 10, 50, 50)
    </script>
  </body>
</html>

在 index.pug 中要写成下面这样,相比 html,pug 的语法写起来其实更加简单精炼:

plain 复制代码
//- index.pug
html(lang="en") 
  head
    title Document
    style 
      include index.css
  body 
    canvas(id="my-canvas") 当前浏览器不支持canvas
    script 
      include index.js
  • 其使用缩进的方式标注不同 html 标签之间的包含关系,所以不需要尾标签;
  • 标签的属性写在紧跟着标签后的括号内,如果有多个属性可用空格隔开;
  • 标签后的文本即为标签的内容,标签和内容之间要有空格;
  • include index.css 就是将 index.css 文件的内容以字符的形式加载进 index.pug。index.css 创建于 views 目录下:
css 复制代码
/* views\index.css */
#my-canvas {
  background-color: antiquewhite;
}
  • 同理,include index.js 是将 views\index.js 文件的内容加载进 index.pug:
javascript 复制代码
// views\index.js
const canvas = document.getElementById('my-canvas')
const ctx = canvas.getContext('2d')
ctx.fillStyle = '#358DFD'
ctx.fillRect(10, 10, 50, 50)

指定模板引擎

在 server.js 中通过 app.set('view engine', 'pug')告诉 express 在 res.render() 时,使用 pug 作为视图模板引擎。现在运行 pnpm dev,于浏览器地址栏输入 localhost:4396/,效果如下:

传递参数

原始数据

在后端服务器中向视图模板传参,只需在服务器的中间件回调函数中调用 res.render() 时,把要传递的参数对象作为第 2 个参数传入即可:

javascript 复制代码
// server.js
app.get('/', (req, res) => {
  res.render('index', { msg: '当前浏览器不支持canvas' })
})

index.pug 里就可以通过 #{msg} 使用参数:

plain 复制代码
//- index.pug
canvas(id="my-canvas") #{msg}

如果要传递的参数是在模板的 js 中使用的,比如要控制 canvas 绘制的矩形的颜色:

javascript 复制代码
// server.js
app.get('/', (req, res) => {
  res.render('index', { msg: '当前浏览器不支持canvas', color: '#705697' })
})

在 index.pug 中,只需在 script 后添加一个 .,表示要在 <script> 标签中添加大段文本(本例中就一行代码),然后在其中定义获取到的变量 color,就能在 index.js 中使用了:

plain 复制代码
//- index.pug
script. 
  const color = '#{color}'    
script 
  include index.js
javascript 复制代码
// views\index.js 省略其它代码
ctx.fillStyle = color

重启服务器后,效果如下:

至此,我们已经成功实现在 express 搭建的服务器中,通过 pug 模板引擎,向视图模板传递原始数据的功能了。

项目完整代码可查阅:gitee/ github

对象

如果要传递的参数为对象,则可以先通过 JSON.stringify() 处理成字符串:

javascript 复制代码
// server.js
const data = { name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }
res.render('index', { data: JSON.stringify(data) })

在 index.pug 中还是当作字符串传给 data

plain 复制代码
//- index.pug
script.
  const data = '#{data}'
script 
  include index.js

在 index.js 中就能使用了:

javascript 复制代码
// index.js
console.log(JSON.parse(data.replace(/&quot;/g, '"')))

data.replace(/&quot;/g, '"') 是为了去除 data 中的 &quot;(代表双引号),如果不做任何处理,在 index.js 中打印 dataconsole.log(data) 得到的结果如下:

相关推荐
涵信7 分钟前
第九节:性能优化高频题-首屏加载优化策略
前端·vue.js·性能优化
前端小巷子18 分钟前
CSS单位完全指南
前端·css
Piper蛋窝28 分钟前
Go 1.19 相比 Go 1.18 有哪些值得注意的改动?
后端
码农BookSea34 分钟前
不用Mockito写单元测试?你可能在浪费一半时间
后端·单元测试
SunTecTec1 小时前
Flink Docker Application Mode 命令解析 - 修改命令以启用 Web UI
大数据·前端·docker·flink
软件技术NINI1 小时前
html css js网页制作成品——HTML+CSS甜品店网页设计(4页)附源码
javascript·css·html
涵信1 小时前
第十一节:性能优化高频题-响应式数据深度监听问题
javascript·vue.js·性能优化
codingandsleeping2 小时前
Express入门
javascript·后端·node.js
Vaclee2 小时前
JavaScript-基础语法
开发语言·javascript·ecmascript
ss2732 小时前
基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
spring boot·后端·高考