| 1 | Embedded JavaScript templates<br/>
|
|---|
| 2 | [](https://snyk.io/test/npm/ejs)
|
|---|
| 3 | =============================
|
|---|
| 4 |
|
|---|
| 5 | ## Security
|
|---|
| 6 |
|
|---|
| 7 | Security professionals, before reporting any security issues, please reference the
|
|---|
| 8 | <a href="https://github.com/mde/ejs/blob/main/SECURITY.md">SECURITY.md</a>
|
|---|
| 9 | in this project, in particular, the following: "EJS is effectively a JavaScript runtime.
|
|---|
| 10 | Its entire job is to execute JavaScript. If you run the EJS render method without
|
|---|
| 11 | checking the inputs yourself, you are responsible for the results."
|
|---|
| 12 |
|
|---|
| 13 | In short, DO NOT submit 'vulnerabilities' that include this snippet of code:
|
|---|
| 14 |
|
|---|
| 15 | ```javascript
|
|---|
| 16 | app.get('/', (req, res) => {
|
|---|
| 17 | res.render('index', req.query);
|
|---|
| 18 | });
|
|---|
| 19 | ```
|
|---|
| 20 |
|
|---|
| 21 | ## Installation
|
|---|
| 22 |
|
|---|
| 23 | ```bash
|
|---|
| 24 | $ npm install ejs
|
|---|
| 25 | ```
|
|---|
| 26 |
|
|---|
| 27 | ## Features
|
|---|
| 28 |
|
|---|
| 29 | * Control flow with `<% %>`
|
|---|
| 30 | * Escaped output with `<%= %>` (escape function configurable)
|
|---|
| 31 | * Unescaped raw output with `<%- %>`
|
|---|
| 32 | * Newline-trim mode ('newline slurping') with `-%>` ending tag
|
|---|
| 33 | * Whitespace-trim mode (slurp all whitespace) for control flow with `<%_ _%>`
|
|---|
| 34 | * Custom delimiters (e.g. `[? ?]` instead of `<% %>`)
|
|---|
| 35 | * Includes
|
|---|
| 36 | * Client-side support
|
|---|
| 37 | * Static caching of intermediate JavaScript
|
|---|
| 38 | * Static caching of templates
|
|---|
| 39 | * Complies with the [Express](http://expressjs.com) view system
|
|---|
| 40 |
|
|---|
| 41 | ## Example
|
|---|
| 42 |
|
|---|
| 43 | ```ejs
|
|---|
| 44 | <% if (user) { %>
|
|---|
| 45 | <h2><%= user.name %></h2>
|
|---|
| 46 | <% } %>
|
|---|
| 47 | ```
|
|---|
| 48 |
|
|---|
| 49 | Try EJS online at: https://ionicabizau.github.io/ejs-playground/.
|
|---|
| 50 |
|
|---|
| 51 | ## Basic usage
|
|---|
| 52 |
|
|---|
| 53 | ```javascript
|
|---|
| 54 | let template = ejs.compile(str, options);
|
|---|
| 55 | template(data);
|
|---|
| 56 | // => Rendered HTML string
|
|---|
| 57 |
|
|---|
| 58 | ejs.render(str, data, options);
|
|---|
| 59 | // => Rendered HTML string
|
|---|
| 60 |
|
|---|
| 61 | ejs.renderFile(filename, data, options, function(err, str){
|
|---|
| 62 | // str => Rendered HTML string
|
|---|
| 63 | });
|
|---|
| 64 | ```
|
|---|
| 65 |
|
|---|
| 66 | It is also possible to use `ejs.render(dataAndOptions);` where you pass
|
|---|
| 67 | everything in a single object. In that case, you'll end up with local variables
|
|---|
| 68 | for all the passed options. However, be aware that your code could break if we
|
|---|
| 69 | add an option with the same name as one of your data object's properties.
|
|---|
| 70 | Therefore, we do not recommend using this shortcut.
|
|---|
| 71 |
|
|---|
| 72 | ### Important
|
|---|
| 73 | You should never give end-users unfettered access to the EJS render method, If you do so you are using EJS in an inherently un-secure way.
|
|---|
| 74 |
|
|---|
| 75 | ### Options
|
|---|
| 76 |
|
|---|
| 77 | - `cache` Compiled functions are cached, requires `filename`
|
|---|
| 78 | - `filename` The name of the file being rendered. Not required if you
|
|---|
| 79 | are using `renderFile()`. Used by `cache` to key caches, and for includes.
|
|---|
| 80 | - `root` Set template root(s) for includes with an absolute path (e.g, /file.ejs).
|
|---|
| 81 | Can be array to try to resolve include from multiple directories.
|
|---|
| 82 | - `views` An array of paths to use when resolving includes with relative paths.
|
|---|
| 83 | - `context` Function execution context
|
|---|
| 84 | - `compileDebug` When `false` no debug instrumentation is compiled
|
|---|
| 85 | - `client` When `true`, compiles a function that can be rendered
|
|---|
| 86 | in the browser without needing to load the EJS Runtime
|
|---|
| 87 | ([ejs.min.js](https://github.com/mde/ejs/releases/latest)).
|
|---|
| 88 | - `delimiter` Character to use for inner delimiter, by default '%'
|
|---|
| 89 | - `openDelimiter` Character to use for opening delimiter, by default '<'
|
|---|
| 90 | - `closeDelimiter` Character to use for closing delimiter, by default '>'
|
|---|
| 91 | - `debug` Outputs generated function body
|
|---|
| 92 | - `strict` When set to `true`, generated function is in strict mode
|
|---|
| 93 | - `_with` Whether or not to use `with() {}` constructs. If `false`
|
|---|
| 94 | then the locals will be stored in the `locals` object. Set to `false` in strict mode.
|
|---|
| 95 | - `destructuredLocals` An array of local variables that are always destructured from
|
|---|
| 96 | the locals object, available even in strict mode.
|
|---|
| 97 | - `localsName` Name to use for the object storing local variables when not using
|
|---|
| 98 | `with` Defaults to `locals`
|
|---|
| 99 | - `rmWhitespace` Remove all safe-to-remove whitespace, including leading
|
|---|
| 100 | and trailing whitespace. It also enables a safer version of `-%>` line
|
|---|
| 101 | slurping for all scriptlet tags (it does not strip new lines of tags in
|
|---|
| 102 | the middle of a line).
|
|---|
| 103 | - `escape` The escaping function used with `<%=` construct. It is
|
|---|
| 104 | used in rendering and is `.toString()`ed in the generation of client functions.
|
|---|
| 105 | (By default escapes XML).
|
|---|
| 106 | - `outputFunctionName` Set to a string (e.g., 'echo' or 'print') for a function to print
|
|---|
| 107 | output inside scriptlet tags.
|
|---|
| 108 | - `async` When `true`, EJS will use an async function for rendering. (Depends
|
|---|
| 109 | on async/await support in the JS runtime.
|
|---|
| 110 | - `includer` Custom function to handle EJS includes, receives `(originalPath, parsedPath)`
|
|---|
| 111 | parameters, where `originalPath` is the path in include as-is and `parsedPath` is the
|
|---|
| 112 | previously resolved path. Should return an object `{ filename, template }`,
|
|---|
| 113 | you may return only one of the properties, where `filename` is the final parsed path and `template`
|
|---|
| 114 | is the included content.
|
|---|
| 115 |
|
|---|
| 116 | This project uses [JSDoc](http://usejsdoc.org/). For the full public API
|
|---|
| 117 | documentation, clone the repository and run `jake doc`. This will run JSDoc
|
|---|
| 118 | with the proper options and output the documentation to `out/`. If you want
|
|---|
| 119 | the both the public & private API docs, run `jake devdoc` instead.
|
|---|
| 120 |
|
|---|
| 121 | ### Tags
|
|---|
| 122 |
|
|---|
| 123 | - `<%` 'Scriptlet' tag, for control-flow, no output
|
|---|
| 124 | - `<%_` 'Whitespace Slurping' Scriptlet tag, strips all whitespace before it
|
|---|
| 125 | - `<%=` Outputs the value into the template (escaped)
|
|---|
| 126 | - `<%-` Outputs the unescaped value into the template
|
|---|
| 127 | - `<%#` Comment tag, no execution, no output
|
|---|
| 128 | - `<%%` Outputs a literal '<%'
|
|---|
| 129 | - `%%>` Outputs a literal '%>'
|
|---|
| 130 | - `%>` Plain ending tag
|
|---|
| 131 | - `-%>` Trim-mode ('newline slurp') tag, trims following newline
|
|---|
| 132 | - `_%>` 'Whitespace Slurping' ending tag, removes all whitespace after it
|
|---|
| 133 |
|
|---|
| 134 | For the full syntax documentation, please see [docs/syntax.md](https://github.com/mde/ejs/blob/master/docs/syntax.md).
|
|---|
| 135 |
|
|---|
| 136 | ### Includes
|
|---|
| 137 |
|
|---|
| 138 | Includes either have to be an absolute path, or, if not, are assumed as
|
|---|
| 139 | relative to the template with the `include` call. For example if you are
|
|---|
| 140 | including `./views/user/show.ejs` from `./views/users.ejs` you would
|
|---|
| 141 | use `<%- include('user/show') %>`.
|
|---|
| 142 |
|
|---|
| 143 | You must specify the `filename` option for the template with the `include`
|
|---|
| 144 | call unless you are using `renderFile()`.
|
|---|
| 145 |
|
|---|
| 146 | You'll likely want to use the raw output tag (`<%-`) with your include to avoid
|
|---|
| 147 | double-escaping the HTML output.
|
|---|
| 148 |
|
|---|
| 149 | ```ejs
|
|---|
| 150 | <ul>
|
|---|
| 151 | <% users.forEach(function(user){ %>
|
|---|
| 152 | <%- include('user/show', {user: user}) %>
|
|---|
| 153 | <% }); %>
|
|---|
| 154 | </ul>
|
|---|
| 155 | ```
|
|---|
| 156 |
|
|---|
| 157 | Includes are inserted at runtime, so you can use variables for the path in the
|
|---|
| 158 | `include` call (for example `<%- include(somePath) %>`). Variables in your
|
|---|
| 159 | top-level data object are available to all your includes, but local variables
|
|---|
| 160 | need to be passed down.
|
|---|
| 161 |
|
|---|
| 162 | NOTE: Include preprocessor directives (`<% include user/show %>`) are
|
|---|
| 163 | not supported in v3.0+.
|
|---|
| 164 |
|
|---|
| 165 | ## Custom delimiters
|
|---|
| 166 |
|
|---|
| 167 | Custom delimiters can be applied on a per-template basis, or globally:
|
|---|
| 168 |
|
|---|
| 169 | ```javascript
|
|---|
| 170 | let ejs = require('ejs'),
|
|---|
| 171 | users = ['geddy', 'neil', 'alex'];
|
|---|
| 172 |
|
|---|
| 173 | // Just one template
|
|---|
| 174 | ejs.render('<p>[?= users.join(" | "); ?]</p>', {users: users}, {delimiter: '?', openDelimiter: '[', closeDelimiter: ']'});
|
|---|
| 175 | // => '<p>geddy | neil | alex</p>'
|
|---|
| 176 |
|
|---|
| 177 | // Or globally
|
|---|
| 178 | ejs.delimiter = '?';
|
|---|
| 179 | ejs.openDelimiter = '[';
|
|---|
| 180 | ejs.closeDelimiter = ']';
|
|---|
| 181 | ejs.render('<p>[?= users.join(" | "); ?]</p>', {users: users});
|
|---|
| 182 | // => '<p>geddy | neil | alex</p>'
|
|---|
| 183 | ```
|
|---|
| 184 |
|
|---|
| 185 | ### Caching
|
|---|
| 186 |
|
|---|
| 187 | EJS ships with a basic in-process cache for caching the intermediate JavaScript
|
|---|
| 188 | functions used to render templates. It's easy to plug in LRU caching using
|
|---|
| 189 | Node's `lru-cache` library:
|
|---|
| 190 |
|
|---|
| 191 | ```javascript
|
|---|
| 192 | let ejs = require('ejs'),
|
|---|
| 193 | LRU = require('lru-cache');
|
|---|
| 194 | ejs.cache = LRU(100); // LRU cache with 100-item limit
|
|---|
| 195 | ```
|
|---|
| 196 |
|
|---|
| 197 | If you want to clear the EJS cache, call `ejs.clearCache`. If you're using the
|
|---|
| 198 | LRU cache and need a different limit, simple reset `ejs.cache` to a new instance
|
|---|
| 199 | of the LRU.
|
|---|
| 200 |
|
|---|
| 201 | ### Custom file loader
|
|---|
| 202 |
|
|---|
| 203 | The default file loader is `fs.readFileSync`, if you want to customize it, you can set ejs.fileLoader.
|
|---|
| 204 |
|
|---|
| 205 | ```javascript
|
|---|
| 206 | let ejs = require('ejs');
|
|---|
| 207 | let myFileLoad = function (filePath) {
|
|---|
| 208 | return 'myFileLoad: ' + fs.readFileSync(filePath);
|
|---|
| 209 | };
|
|---|
| 210 |
|
|---|
| 211 | ejs.fileLoader = myFileLoad;
|
|---|
| 212 | ```
|
|---|
| 213 |
|
|---|
| 214 | With this feature, you can preprocess the template before reading it.
|
|---|
| 215 |
|
|---|
| 216 | ### Layouts
|
|---|
| 217 |
|
|---|
| 218 | EJS does not specifically support blocks, but layouts can be implemented by
|
|---|
| 219 | including headers and footers, like so:
|
|---|
| 220 |
|
|---|
| 221 |
|
|---|
| 222 | ```ejs
|
|---|
| 223 | <%- include('header') -%>
|
|---|
| 224 | <h1>
|
|---|
| 225 | Title
|
|---|
| 226 | </h1>
|
|---|
| 227 | <p>
|
|---|
| 228 | My page
|
|---|
| 229 | </p>
|
|---|
| 230 | <%- include('footer') -%>
|
|---|
| 231 | ```
|
|---|
| 232 |
|
|---|
| 233 | ## Client-side support
|
|---|
| 234 |
|
|---|
| 235 | Go to the [Latest Release](https://github.com/mde/ejs/releases/latest), download
|
|---|
| 236 | `./ejs.js` or `./ejs.min.js`. Alternately, you can compile it yourself by cloning
|
|---|
| 237 | the repository and running `jake build` (or `$(npm bin)/jake build` if jake is
|
|---|
| 238 | not installed globally).
|
|---|
| 239 |
|
|---|
| 240 | Include one of these files on your page, and `ejs` should be available globally.
|
|---|
| 241 |
|
|---|
| 242 | ### Example
|
|---|
| 243 |
|
|---|
| 244 | ```html
|
|---|
| 245 | <div id="output"></div>
|
|---|
| 246 | <script src="ejs.min.js"></script>
|
|---|
| 247 | <script>
|
|---|
| 248 | let people = ['geddy', 'neil', 'alex'],
|
|---|
| 249 | html = ejs.render('<%= people.join(", "); %>', {people: people});
|
|---|
| 250 | // With jQuery:
|
|---|
| 251 | $('#output').html(html);
|
|---|
| 252 | // Vanilla JS:
|
|---|
| 253 | document.getElementById('output').innerHTML = html;
|
|---|
| 254 | </script>
|
|---|
| 255 | ```
|
|---|
| 256 |
|
|---|
| 257 | ### Caveats
|
|---|
| 258 |
|
|---|
| 259 | Most of EJS will work as expected; however, there are a few things to note:
|
|---|
| 260 |
|
|---|
| 261 | 1. Obviously, since you do not have access to the filesystem, `ejs.renderFile()` won't work.
|
|---|
| 262 | 2. For the same reason, `include`s do not work unless you use an `include callback`. Here is an example:
|
|---|
| 263 | ```javascript
|
|---|
| 264 | let str = "Hello <%= include('file', {person: 'John'}); %>",
|
|---|
| 265 | fn = ejs.compile(str, {client: true});
|
|---|
| 266 |
|
|---|
| 267 | fn(data, null, function(path, d){ // include callback
|
|---|
| 268 | // path -> 'file'
|
|---|
| 269 | // d -> {person: 'John'}
|
|---|
| 270 | // Put your code here
|
|---|
| 271 | // Return the contents of file as a string
|
|---|
| 272 | }); // returns rendered string
|
|---|
| 273 | ```
|
|---|
| 274 |
|
|---|
| 275 | See the [examples folder](https://github.com/mde/ejs/tree/master/examples) for more details.
|
|---|
| 276 |
|
|---|
| 277 | ## CLI
|
|---|
| 278 |
|
|---|
| 279 | EJS ships with a full-featured CLI. Options are similar to those used in JavaScript code:
|
|---|
| 280 |
|
|---|
| 281 | - `-o / --output-file FILE` Write the rendered output to FILE rather than stdout.
|
|---|
| 282 | - `-f / --data-file FILE` Must be JSON-formatted. Use parsed input from FILE as data for rendering.
|
|---|
| 283 | - `-i / --data-input STRING` Must be JSON-formatted and URI-encoded. Use parsed input from STRING as data for rendering.
|
|---|
| 284 | - `-m / --delimiter CHARACTER` Use CHARACTER with angle brackets for open/close (defaults to %).
|
|---|
| 285 | - `-p / --open-delimiter CHARACTER` Use CHARACTER instead of left angle bracket to open.
|
|---|
| 286 | - `-c / --close-delimiter CHARACTER` Use CHARACTER instead of right angle bracket to close.
|
|---|
| 287 | - `-s / --strict` When set to `true`, generated function is in strict mode
|
|---|
| 288 | - `-n / --no-with` Use 'locals' object for vars rather than using `with` (implies --strict).
|
|---|
| 289 | - `-l / --locals-name` Name to use for the object storing local variables when not using `with`.
|
|---|
| 290 | - `-w / --rm-whitespace` Remove all safe-to-remove whitespace, including leading and trailing whitespace.
|
|---|
| 291 | - `-d / --debug` Outputs generated function body
|
|---|
| 292 | - `-h / --help` Display this help message.
|
|---|
| 293 | - `-V/v / --version` Display the EJS version.
|
|---|
| 294 |
|
|---|
| 295 | Here are some examples of usage:
|
|---|
| 296 |
|
|---|
| 297 | ```shell
|
|---|
| 298 | $ ejs -p [ -c ] ./template_file.ejs -o ./output.html
|
|---|
| 299 | $ ejs ./test/fixtures/user.ejs name=Lerxst
|
|---|
| 300 | $ ejs -n -l _ ./some_template.ejs -f ./data_file.json
|
|---|
| 301 | ```
|
|---|
| 302 |
|
|---|
| 303 | ### Data input
|
|---|
| 304 |
|
|---|
| 305 | There is a variety of ways to pass the CLI data for rendering.
|
|---|
| 306 |
|
|---|
| 307 | Stdin:
|
|---|
| 308 |
|
|---|
| 309 | ```shell
|
|---|
| 310 | $ ./test/fixtures/user_data.json | ejs ./test/fixtures/user.ejs
|
|---|
| 311 | $ ejs ./test/fixtures/user.ejs < test/fixtures/user_data.json
|
|---|
| 312 | ```
|
|---|
| 313 |
|
|---|
| 314 | A data file:
|
|---|
| 315 |
|
|---|
| 316 | ```shell
|
|---|
| 317 | $ ejs ./test/fixtures/user.ejs -f ./user_data.json
|
|---|
| 318 | ```
|
|---|
| 319 |
|
|---|
| 320 | A command-line option (must be URI-encoded):
|
|---|
| 321 |
|
|---|
| 322 | ```shell
|
|---|
| 323 | ./bin/cli.js -i %7B%22name%22%3A%20%22foo%22%7D ./test/fixtures/user.ejs
|
|---|
| 324 | ```
|
|---|
| 325 |
|
|---|
| 326 | Or, passing values directly at the end of the invocation:
|
|---|
| 327 |
|
|---|
| 328 | ```shell
|
|---|
| 329 | ./bin/cli.js -m $ ./test/fixtures/user.ejs name=foo
|
|---|
| 330 | ```
|
|---|
| 331 |
|
|---|
| 332 | ### Output
|
|---|
| 333 |
|
|---|
| 334 | The CLI by default send output to stdout, but you can use the `-o` or `--output-file`
|
|---|
| 335 | flag to specify a target file to send the output to.
|
|---|
| 336 |
|
|---|
| 337 | ## IDE Integration with Syntax Highlighting
|
|---|
| 338 |
|
|---|
| 339 | VSCode:Javascript EJS by *DigitalBrainstem*
|
|---|
| 340 |
|
|---|
| 341 | ## Related projects
|
|---|
| 342 |
|
|---|
| 343 | There are a number of implementations of EJS:
|
|---|
| 344 |
|
|---|
| 345 | * TJ's implementation, the v1 of this library: https://github.com/tj/ejs
|
|---|
| 346 | * EJS Embedded JavaScript Framework on Google Code: https://code.google.com/p/embeddedjavascript/
|
|---|
| 347 | * Sam Stephenson's Ruby implementation: https://rubygems.org/gems/ejs
|
|---|
| 348 | * Erubis, an ERB implementation which also runs JavaScript: http://www.kuwata-lab.com/erubis/users-guide.04.html#lang-javascript
|
|---|
| 349 | * DigitalBrainstem EJS Language support: https://github.com/Digitalbrainstem/ejs-grammar
|
|---|
| 350 |
|
|---|
| 351 | ## License
|
|---|
| 352 |
|
|---|
| 353 | Licensed under the Apache License, Version 2.0
|
|---|
| 354 | (<http://www.apache.org/licenses/LICENSE-2.0>)
|
|---|
| 355 |
|
|---|
| 356 | - - -
|
|---|
| 357 | EJS Embedded JavaScript templates copyright 2112
|
|---|
| 358 | mde@fleegix.org.
|
|---|