ejs-locals-vadorequest
v2.0.2
Published
Express 3.x locals for layout, partial and blocks.
Downloads
33
Readme
ejs-locals
Table of contents
- Status: What the current status of the library is?
- About: What the library is made for?
- Features summary: What features are available that aren't in the original
ejs-locals
? - Installation: How to install the library?
- Proper setup: How to properly setup absolute path finding?
- Usage: How to use the lib? With examples.
- Features: Deep explanation of the features.
- Debug: Tips and explanation about how to debug.
- Specific attributes: Specific attributes used by the library that you should be aware about.
- Template support: Node.js template engine supported.
- Tests: How to run the tests?
- Backwards compatibility: A small talk about backward compatibility.
Include
orpartial
?: Why usinginclude
is bad and will give you headaches.- Contributing
- Roadmap
- Credits
- License
Status
This is my own library that replaces ejs-locals
from https://github.com/RandomEtc/ejs-locals.
The original lib is unmaintained so I have made some improvements, mostly based on what I need since I don't understand exactly how everything works there.
Anyway, if you want small edit/features I should be able to do it, just open an issue.
Or better: Make a PR. (see Contributing.md)
About
Express 3.x layout
, partial
and block
template functions for the EJS template engine.
Previously also offered include
but you should use EJS 0.8.x's own method for that now. And you shouldn't the use of include
and partial
because of bugs, just use partial
, read more at Include
or partial
?
Note: This library is backward compatible with the original ejs-locals
. You can just change it in your program and everything should work just fine.
Summary of the features added to the original ejs-locals
- Absolute paths based on Express views or custom configuration.
- When a
partial
call fails, show the stacks of tried paths so you can figure out what's wrong. - When a
partial
call success, show the loaded partial and every single tried paths so you can makes sure it loads the right one. (not possible to disable this yet) - Optional argument for
script
andstylesheet
helpers to generate html properties with default values.
Features are explained below, if you believe it lacks of documentation please open an issue.
Installation
$ npm install ejs-locals-vadorequest --save
(--save
automatically writes to your package.json
file, tell your friends)
Proper setup
If you want to use a smart and reusable absolute path
, here is how it should be done.
Using Express.js
This is the smarter solution. Just set the following when setting your express
application: app.set('views', __dirname + '/views')
even if I guess that's already done!
Every use of absolute path (I.e: partial('/partials/absolute')
will take the views
folder as root.
Without Express.js
If you're not using Express, then you could set when you're rendering a view the following: res.render('index', { _basePath: __dirname });
,
it would be shared across every partial loaded by the view and you would not need to precise the _basePath
while calling partial()
.
Of course this can be a pain in the ass if you need to change every call to res.render
, I myself don't,
I prefer to use the Express configuration and when I can't I have a bunch of default values bound in every view dynamically, so I don't even have to think about it.
Usage
Run node app.js
from examples
folder and open localhost:3000
to see a working example.
Given a template, views/index.ejs
:
<% layout('layouts/boilerplate') -%>
<% script('/foo.js') -%>
<% stylesheet('/foo.css') -%>
<h1>Partials, include and local variables</h1>
<b>I am the <%= what %> template</b>
<!-- Using include will make any use of the partial function bug using relative paths. Much better to use partial actually. -->
<% include partials/included %>
<%- partial('partials/relative', {text: "Loaded using: <code>partial('partials/relative.ejs')</code>"}) %>
<%- partial('/partials/absolute.ejs', {text: "Loaded using: <code>partial('/partials/absolute.ejs')</code>. Used <b>Express</b> configuration to find the view."}) %>
<%- partial('/partials/absolute', {text: "Loaded using: <code>partial('/partials/absolute')</code>. Used <b>Express</b> configuration to find the view."}) %>
<%- partial('/views/partials/absolute.ejs', {text: "Loaded using: <code>partial('/views/partials/absolute.ejs', {_basePath: base})</code>. Used <b><code>_basePath</code></b> value to find the view.", _basePath: base}) %>
<hr/>
<h1>Partials with variables</h1>
<p>Here are some muppets we know about:
<ul>
<%- partial('partials/muppet', muppets) %>
</ul>
</p>
<%- partial('partials/extra') %>
<hr/>
<h1>Templates</h1>
<%- partial('templates/box', {box_title: 'My box!', box_content: '<div><b>Box content!</b></div>'})%>
<hr/>
<h1>Blocks, JS and CSS</h1>
<% block('header', "<p>I'm in the header.</p>") %>
<% block('footer', "<p>I'm in the footer.</p>") %>
<p class="better-than-dead">I'm red if foo.css was loaded.</p>
And a layout, views/layouts/boilerplate.ejs
:
<!DOCTYPE html>
<html>
<head>
<title>It's <%=who%></title>
<%-scripts%>
<%-stylesheets%>
</head>
<body>
<header>
<%-blocks.header%>
</header>
<section>
<%-body -%>
</section>
<footer>
<%-blocks.footer%>
</footer>
</body>
</html>
When rendered by an Express 3.0 app, app.js
:
var express = require('express')
, ejsLocals = require('../')
, app = express()
, path = require('path');
// use ejs-locals for all ejs templates:
app.engine('ejs', ejsLocals);
// Path resolving will be using this setting to resolve paths during fallback.
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs'); // so you can render('index')
// render 'index' into 'boilerplate':
app.get('/',function(req, res, next){
// The fact that we send _basePath from here, it will be bound automatically to each call to `partial`, not useful to specify it again. But possible to override it to set a custom _basePath for a specific call.
res.render('index', { what: 'best', who: 'me', muppets: [ 'Kermit', 'Fozzie', 'Gonzo' ], base: __dirname });
});
/**
* Make the /example/public folder public from the browser.
*/
app.use(express.static(path.join(__dirname, 'public')));
/**
* Start the application on a specific port.
*/
app.listen(3000);
You get the following result: (See Picture)
Features
layout(view)
When called anywhere inside a template, requests that the output of the current template be passed to the given view as the body
local. Use this to specify layouts from within your template, which is recommended with Express 3.0, since the app-level layout functionality has been removed.
partial(name, optionsOrCollection)
When called anywhere inside an EJS file, adds the given view to that template using the current given optionsOrCollection
.
The usual way to use this is to pass an Array/Object as the collection argument.
The given view is then executed for each item in the Array. The item is passed into the view as a local with a name generated from the view's filename.
For example, if you do <%-partial('thing', things)%>
then each item in the things
Array is passed to thing.ejs
with the name thing
.
If you rename the template/partial, the local name of each item will correspond to the template name.
If you do <%-partial('thing', {things: things, foo: {bar: 'bar')%>
then you will have access to things
and foo
from the template/partial, and foo
would contain a bar
key.
That's what is recommended to do most of the time, the first way is more a helper for loops.
Note that you can precise the view engine at the end of the filename, or not, as you want. Both ways will work, unlike in the official lib. (i.e: <%- partial('partials/relative.ejs') %>
)
Load partial with absolute path
The path will be relative to your express app configuration: app.set('views', __dirname + '/views');
, if it is not set then it will have for default:
process.cwd() + '/views'
, so basically the folder views
from where the application is started, better to use express!
To use the absolute way you will need to make it start by a dash (/
).
In any case you can force the base path by doing the following: partial('/partials/absolute', {_basePath: your_base_path})
.
Using the _basePath
attribute you will force the base path, so if for some reason the lookup system that loads a view mess up you are able to force the path this way.
Resolve absolute file order
There is a specific order while trying to resolve a path using the partial
function. Here is the description taking as example the following partial('/partials/absolute')
from the file c:\wamp\www\ejs-locals\example\index.ejs
:
c:\wamp\www\ejs-locals\example\partials\absolute.ejs
(not tested) (would be tested only if_basePath
is bind to the view (inlocals._basePath
), or when calling thepartial
function like:partial('/partials/absolute', {_basePath: your_base_path)
)c:\wamp\www\ejs-locals\example\views\partials\absolute.ejs
(succeed)c:\partials\_absolute.ejs
(not tested) fallback relativec:\partials\absolute.ejs
(not tested) fallback relativec:\partials\absolute\index.ejs
(not tested) fallback relative
As you can see, the fallback here isn't really useful. I actually don't know if I should improve it or not, and I don't know how to. It's kinda hard to fallback from absolute to relative and I'm afraid the program would be wrong most of the time actually.
So, probably better this way, or completely remove fallback from absolute to relative paths. Feel free to guide me here.
Load partial with relative path
Nothing complicated here, just to <%- partial('partials/relative') %>
Resolve relative file order
There is a specific order while trying to resolve a path using the partial
function. Here is the description taking as example the following partial('partials/relative')
from the file c:\wamp\www\ejs-locals\example\index.ejs
:
c:\wamp\www\ejs-locals\example\views\partials\_relative.ejs
(failed)c:\wamp\www\ejs-locals\example\views\partials\relative.ejs
(succeed)c:\wamp\www\ejs-locals\example\views\partials\relative/index.ejs
(not tested) (a file was found already)
block(name, html)
When called anywhere inside an EJS file, adds the given html to the named block. In the layout you can then do `<%-block('foo')%> to render all the html for that block.
Since this relies on javascript strings, and bypasses EJS's default escaping, you should be very careful if you use this function with user-submitted data.
script(src, parameters)
A convenience function for block('scripts', '<script src="src.js"></script>')
with optional type.
When called anywhere inside a template, adds a script tag with the given src/type to the scripts block.
In the layout you can then do `<%-scripts%> to output the scripts from all the child templates.
The second parameters can also be an object.
<% script('/foo.js') -%>
will generate <script src="/foo.js" type="text/javascript"></script>
<% script('/foo.js', {type: 'text/javascript', id: 'script-foo'}) -%>
will generate <script src="/foo.js" type="text/javascript" id="script-foo"></script>
stylesheet(href, parameters)
A convenience function for block('stylesheets', '<link rel="stylesheet" href="href.css" />')
with optional media type.
When called anywhere inside a template, adds a link tag for the stylesheet with the given href/media to the stylesheets block.
In the layout you can then do `<%-stylesheets%> to output the links from all the child templates.
The second parameters can also be an object.
<% stylesheet('/foo.css') -%>
will generate <link rel="stylesheet" href="/foo.css">
<% stylesheet('/foo.css', 'print') -%>
will generate <link rel="stylesheet" href="/foo.css" media="print">
<% stylesheet('/foo.css', {type: 'text/css', id: 'stylesheet-foo'}) -%>
will generate <link rel="stylesheet" href="/foo.css" type="text/css" id="stylesheet-foo">
Debug support
In order to help developers using this library I have made a couple of changes:
- Every successful partial found is written in the server console as
log
. If I can understand that it could be boring due to a lot of views loaded, I prefer doing so for the moment so we are able to see if the file loaded is the one we want to, especially now that I don't trust the lookup system 100%. Feel free to make a PR with some kind of settings to disable it, I didn't get any idea other than checking theenvironment
but I would like to have log in production too, I don't think that's the best way. We need something independent, not related to the env. - When a file to load fails to be found, all paths tested are now displayed in the server console as
error
.
Specific attributes
This list is probably not complete, I didn't run into every case but I will detail here all the specific attributes that you should not use.
- While rendering a view:
- locals._layoutFile: Used to set the layout to use. Set to false to disable.
- locals.body: Contains the content of a view when used in a layout. If you override this, you're gonna regret it. https://github.com/RandomEtc/ejs-locals/issues/22
- While loading a partial
partial(view, options)
- options.cache: I'm not sure what it is, seems that we can enable/disable the cache on a specific partial. I read somewhere that it was enabled in production. Anyway, I would recommend to avoid using this key, excepted if you understand what it does.
Template Support
ejs
(actually hard coded right now, but feel free to fork and help!)
Running Tests
To run the test suite first invoke the following command within the repo, installing the development dependencies:
$ npm install -d
then run the tests:
$ npm test
Backwards Compatibility
Express 2.0 had similar functionality built in, using { layout: 'view' }
as an argument to res.render
but this has been removed in Express 3.0. If you want the old behavior you should do:
app.locals({
_layoutFile: true
})
And/or pass _layoutFile: true
in the options when you call res.render(...)
.
Using include
over partial
?
Previous versions of this library had an include
function. This is now supported directly by EJS, albeit with a different syntax. For ejs-locals
1.0+ simply do:
<% include path/view %>
When called anywhere inside a template, this adds the given view to that template using the current options and locals. This is built-in to EJS 0.8+.
I warn you here, know that every file loaded through include
will not be able to load files using the partial()
function with relative path,
it is just broken (path resolve fails). Since include
belongs to EJS and partials
belongs to ejs-locals
they are NOT friendly.
If you want to test it, there are tests in my example
, just read them and figure it out by yourself.
Anyway include
isn't as useful as partial
so I won't bother anymore.
Contributing
See CONTRIBUTING.md.
Roadmap
See ROADMAP.md.
Credits
This library is a fork from ejs-locals which is unmaintained.
License
See LICENSE.md.