Pug/Jade 中动态包含的解决方法



我知道 Pug 不支持模板中的动态包含或扩展。即

extend path/to/template 

有效但无效

extend #{dynamic_path_to_template}

是否有一种解决方法(无论多么复杂(将允许在运行时修改视图使用的模板的相同目标

上下文:我的用例是我正在开发一个 npm 模块,用于扩展其他视图的模板位于模块内部。 模块发布并安装后,将定义路径(即 node_modules/my_module/path/to/template(,但在开发阶段,我只需要能够"npm 链接"到模块并让模板工作。 我也不希望对链接进行硬编码,以便我可以发布与测试相同的代码。

我也遇到了这个问题,在寻找解决方案时发现了这个问题。我的解决方案类似于Nikolay Schambergs Answer,但我认为我应该分享它。

我创建了一个函数,该函数通过为其提供路径并将其传递给选项对象来呈现模板。也许这对您的情况也有帮助

const includeFunc = (pathToPug, options = {}) => {
return pug.renderFile(pathToPug, options); //render the pug file
}
const html = pug.renderFile('template.pug', {include: includeFunc});

然后在模板中按如下方式使用它:

body
h1 Hello World
|!{include(dynamicPugFilePathFromVariable)}

目前没有办法做到这一点,但您可以在没有动态扩展的情况下制定您的应用程序架构。

可能的解决方案#1

  1. 制作一个有条件地包含多个布局的 layout.jade:

    layout.jade:
    if conditionalVariable
    include firstLayout.jade
    else
    include otherLayout
    
  2. 在您看来,扩展layout.jade,并在控制器中定义conditionalVariable(true/false(:

    view.jade:
    extends layout
    block content
    p here goes my content!
    

可能的解决方案#2

  1. 将配置传递到布局

    - var lang = req.getLocale();
    doctype html
    block modifyLayout
    
  2. 将项目拆分为多个入口,每个入口扩展布局并传递其不同的配置,并在不同的块中包含不同的东西

    extends ../layout
    block modifyLayout
    - var lang = "en" //force language to be en in this page.
    block body
    include my-page-body
    

可能的解决方案#3

使用像 Terraform 这样的东西,它使用 Pug 作为其渲染引擎,但它使您能够使用这样的动态部分

!= partial(dynamicFileFromVariable)

为了执行动态包含,您必须使用未转义字符串插值,在路由中的主 .pug 文件之前插入预编译的 pug 内容。换句话说,它的工作原理如下:

1(一些.pug文件被预编译成HTML 2(HTML被输入到另一个.pug文件编译过程中

下面是一个如何做到这一点的示例

在您的路由器文件(路由.js或其他任何内容(中

var pug = require('pug')
var html = []
var files = ['file1','file2'] // file names in your views folders
let dir = path.resolve(path.dirname(require.main.filename) + `/app/server/views/`)
//dir is the folder with your templates
app.get('/some-route', (req,res) => {
for (let n = 0; n < files.length; n++) {
let file = path.resolve(dir + '/' + files[n] + `.pug`)
fs.access(file, fs.constants.F_OK, (err) => {
if (!err) {
html.push(pug.renderFile(file, data))
if (n === files.length - 1) {
res.render('dashboard', {html})
}
}
else {
res.status(500).json({code:500,status:"error", error:"system-error"})
}
})
}
})

在您想要的 .pug 文件中:

for item in html
.
!{item}

上面的例子特定于我自己的用例,但它应该很容易适应它。

它有效!

首先,设置 res.locals 中间件。

中间件/设置本地.js

const pug = require('pug')
const path = require('path')
module.exports = function(req, res, next) {
res.locals.include = (pathToPug, options = {}) => { // used for imitate includ pug function
return pug.renderFile(pathToPug, options); //render the pug file
}
res.locals.__PATH__ = path.join(__dirname, '../')
next()
}

服务器/索引.js

app.use(require('../middlewares/setResLocals'))

文件.哈巴狗

|!{include(`${__PATH__}/${something}`)}

我知道,这回答有点晚了。但是我通过哈巴狗文档中的这些信息找到了适合我目的的可能性:

如果路径是绝对路径(例如,include /root.pug(,则由 前缀options.basedir。否则,路径将相对于 正在编译的当前文件。

因此,我按相对路径提供大部分哈巴狗模块,并且我要动态交换的内容组织在同名但位于不同文件夹(想想主题(中的哈巴狗文件中,并按绝对路径包含它们。然后我更改basedir选项以动态选择一组哈巴狗文件(例如选择主题(。

愿这也能帮助他人。

最新更新