ejs: block/template/extend support for ejs
Currently ejs doesn’t have any block/template/extend features.
existing solutions:
https://github.com/seqs/ejs-blocks
neat javascript grammar, however it only support raw strings as block content.
https://github.com/tj/ejs/pull/142 https://github.com/User4martin/ejs/blob/plugin-snippets/docs/plugin-snippet.md
they invents several preprocessor directives like
<%block header%>
,<%/block header%>
<%+ template%>
,<%* snippet name %>
,<%* /snippet %>
, thus not very easy to learn, this is against ejs’s design goals.
this approach:
page implementation (home.ejs):
<!-- define block contents by functions, it should be able to access the same locals data & context -->
<% var head = () => { %>
<%- include('./include.css') %>
<title>Hello EJS Template</title>
<% } -%>
<% var body = () => { %>
<div>
you have an message: <%= message.toLowerCase() %>
</div>
<% } -%>
<!-- a single "include" finally, and its contents are passed by locals -->
<%- include('./layout', {body, head}) %>
template/layout declaration (layout.ejs):
<!-- NOTE: template/layout can be nested -->
<html>
<head>
<% if (!head) { %>
<title>default title</title>
<% } else { %>
<!-- NOTE: this is the only one thing changed for ejs users, ejs "include" function now accept function as its first argument -->
<%- include(head) %>
<% } %>
</head>
<body>
<h1>This is a layout</h1>
<% if (!body) { %>
<small>default content</small>
<% } else { %>
<!-- same above -->
<%- include(body) %>
<% } %>
</body>
</html>
advantages
- pure javascript gramma, with ES6 arrow function, the code looks nice too
- it breaks nothing
- like the original “include”, it can be nested
- functions can have its parameters, so include can handle function-local variables as well as context variables, example: https://github.com/mde/ejs/issues/252#issuecomment-428576331
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 12
- Comments: 17 (2 by maintainers)
One way to use extends/block in existing versions:
page.ejs
base.ejs
Any update to this conversation?
This is why I like ejs
sorry for the late reply, I would be glad to help with the code & pr, as long as @mde @RyanZim and other maintainer agrees on this approach.
@ichiriac agrees with you, I think there should be as little avoids extra syntax as possible
@mde my approach here is to introduce a global output stack, which could be toggled at runtime.
I guess by some feather modification, it could become something like a EventEmitter. there maybe some cool features could come from it, the only problem is, it looks like a big rewrite here – which I’m not so sure, however I’ll be willing to help if you guys can give a specific task 😄 .
Hi,
Meanwhile I’ve made a workaround/hack in order to avoid extending - in my case I just needed the inheritance behavior (and it works with expressjs).
And here the usage from an
views/index.ejs
:And here my layout
views/layouts/default.ejs
:This little snippet not so intrusive and avoids extra dependencies but may break if renderFile executes the cb argument async (as it may should but it doesn’t today)…
I think the simplest thing to do is to introduce on ejs an hook system on compile and then it would provide a way to implement new functions like inhertance or blocks out of the box…
I’ve made a quick & dirty prototype in order to see how the API could be, you can take a look at it here : https://github.com/ichiriac/ejs-decorator - tell me if you’re interested in a PR
Hi @huxia, does this feature is still planned ?
This could definitely work. One thing to keep in mind is that we ultimately want to support async/await for
include
.