A fast and dynamic view engine similar to handlebars.
npm install regve!npm
!Libraries.io dependency status for latest release
!GitHub top language
!NPM

A fast and dynamic view engine similar to handlebars.
This module is focused on being a fast, and easy to use view engine for nodejs.
Running most things in regex allows for a lightweight, fast, and dynamic html template engine.
This view engine avoids throwing errors on undefined values.
The engine instead, simply hides undefined (or falsy) values.
This means, you don't get that annoying crash when you simply don't what to show a value,
instead the engine assumes you want to use the value only if it exists.
It can handle nested objects without crashing even if the parent (or grandparent) object is undefined.
This module also auto closes html tags (apart from those that should not close), and removes html comments unless they start with ! or @, or they include copyright, (c), license, or license.
The view engine runs mainly through regex functions, to try and gain improved speed and performance.
Additionally, regex has the benefit of recognizing patters, which allows for an easy dynamic template engine.
The syntax of this view engine is similar to handlebars, so getting started should be easy.
This is to start you off with a pattern that you may be familiar with already.
Although, this is not completely the same as handlebars, and .hbs files will complain about errors, which do not exist in this template engine.
In this template engine, those errors do not exist, because there handled dynamically and common mistakes are recognized and corrected by the engine.
To help with crash resistance, the file is read, not run.
This view engine is running on javascript regex functions, so a file is simply read as a string.
This view engine has some (optional) basic markdown like features, by using regex to replace markdown with html.
You can add variables and use if and each statements.
You can also import other views into the current view.
You can choose any html tag name, and have it automatically moved to a different location.
The if statements support & (and) | (or) operators, as well as the ! (not) operator.
If statements also support < = > and you can check if a var is equal to a 'string'.
There are also some shortened methods for doing common tasks in a simpler way.
VSCode Extention For .regve Syntax Highlighting
- Extended Markdown Support
- Added Components
``shell script`
npm install @aspiesoft/regve
`js
// express
const express = require('express');
const regve = require('@aspiesoft/regve');
const app = express();
app.engine('html', regve({
/ global options /
opts: {default: 'some default options for res.render'}
}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.use(function(req, res, next){
res.render('index', {title: 'example', content: "
// render from string
const regve = require('@aspiesoft/regve');
regve({/ global options /});
let html = '#Hello, {{name}}!';
html = regve.render(html, {name: 'World'});
console.log(html);
`
`js`
regve({template: 'layout'});
`js`
// if your Not using express, you can still define the the views path and file type in another way
path = require('path');
regve({
dir: path.join(__dirname, 'views'),
type: 'html'
});
`js`
// to disable everything, and send raw html, just set the raw option to true
// note: cache will still run if set
app.engine('html', regve({raw: true}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
`html
{{title}}
{{title.default}}
{{title.1}}
{{{content}}}
{{#if title}}
{{#if !content}}
no content
{{else}}
{{{content}}}
{{/if}}
{{#if title1}}
{{#if name & url}}
{{name}}
{{else name | url}}
{{name}} {{url}}
{{/if}}
{{{myContent | myBackupContent}}}
{{#each items|itemsDefault as item}}
{{item}}
{{/each}}
{{#if item = 'item1'}}
this is the first item
{{else item = defaultItem}}
this is {{defaultItem}}
{{else !item}}
there is no item
{{/if}}
{{#if item != 'item1'}}
this is Not the first item
{{/if}}
{{#if '1' < '2'}}
true
{{/if}}
{{#if '1' > '2'}}
false
{{/if}}
{{#if '1' <= '1'}}
true
{{/if}}
{{#if '1' < '1'}}
false
{{/if}}
{{#if '2' >= '1'}}
true
{{/if}}
{{#if '2' > '2'}}
false
{{/if}}
{{test | 'default'}}
{{"test"}}
{{#each list as item of index}}
{{index}} = {{item}}
{{/each}}
{{#each list as item of index from object}}
{{object}}
{{index}} = {{item}}
{{/each}}
{{#each list from object of index as item}}
{{object}}:
{{index}} = {{item}}
{{/each}}
{{#each list as item of index}}
{{item.id}} = {{item.name}}
{{/each}}
{{#each list as item}}
{{#if item}}
{{item.name}}
{{/if}}
{{/each}}
{{#each menus as menu of type}}
{{#each list1&list2 as item of index from list}}
{{list}}:
{{index}} = {{item}}
{{#if list = 'list1'}}
this is the first list
{{/if}}
{{/each}}
{{$myVar = 'a new var'}}
{{$myVar2 = menu|menus.0}}
regve.render('index', {$: {myVar: 'a new var default'});
{{$myVar}}
{{$myVar2}}
{{{#import header}}}
{{{#import page/header}}}
{{{#import some/file/path}}}
{{{#module components/header var1:a var2: b str: "A String with spaces \"and\" escaped quotes" obj[ key:value item1: a item2: b item3: c ] }}}
This module has content
{{{/module}}}
{{{#insert components/header desc: "a simple module without a body" body: "I can also define the body with a var if I want" test 'this \'test\' string uses single quotes'}}}
{{#no-markdown}}
markdown will not run in here
{{/no-markdown}}
{{#no-html}}
html should not run here
Do Not rely on this for html security
The purpose of this, is so an admin can display html without running it
{{/no-html}}
{{#delete}}
This text will be removed before rendering
Do Not rely on this for security
The purpose of this, is for the engine to remove the right content from if else statements in bulk
{{/delete}}
--- =
https://example.com = https://example.com
example = example
p tag p tag =
pre tag also supported with 3 but this readme is written in markdown, so I can not display it.
italic
bold
bold italic
__underlined__
~~strike through~~
``
`js`
//you can add any tag name. custom tags also work
//note: style tag also includes stylesheets.
app.engine('html', regve({extract: ['script', 'style', 'link', 'meta']}));
`html
some other text
{{-script}}
some other text
`
`js
// this can help reduce the number of calls to fs.reaFile()
// note: the cache is also reset on server restart
// note: the cache value is case sensitive
app.engine('html', regve({cache: '2h'})); // 2 hours
// or if you have a small number of views that never change
app.engine('html', regve({cache: '1Y'})); // 1 Year
// or for a daily cache
app.engine('html', regve({cache: '1D'})); // 1 Day
// the cache only runs on production. to run the cache in development, set the cacheDev option
app.engine('html', regve({cache: '2m', cacheDev: true})); // 2 minutes (also runs in development)
`
`js
// in express, you can set a callback function, just before, or just after res.render() runs
// the data is the file data before or after rendered
// you can also return the data, with some modifications, to override the original data (must be type string)
// returning nothing will leave the result alone
// data will be returned as a buffer, so you may need to use data.toString() to modify it
regve({onBeforeRender: function(data){
// this will run before res.render() runs
return data;
}});
regve({onAfterRender: function(data){
// this will run after res.render() runs
return data;
}});
// you can also run these functions by setting options
res.render('index', {onBeforeRender: function(data){
// this will run before res.render() runs
return data;
}});
res.render('index', {onAfterRender: function(data){
// this will run after res.render() runs
return data;
}});
`
`js
// to increase performance, you can globally skip some of the unused parts of the view engine
// you can also add these to res.render({/ options /});
app.engine('regve', regve({
noImports: true,
noEach: true,
noMarkdown: true
}));
// by default, the view engine will remove any unused vars
// you can disable this feature by setting the keepInvalidVars option
app.engine('html', regve({keepInvalidVars: true}));
`
`js
let hasContent = true || false; // default = false
regve.addFunction('name', function(attrs, content, options){
// attrs is an array of items added after the tag name, separated by spaces
// example: {{#name attr1 attr2 attr3}}
// content only exists if hasContent is true
// if hasContent is true, than you will need to close the tag with {{/name}}
// example: {{#name attrs}} content {{/name}}
// options are the vars you set when adding the template
// example: res.render('index', {/ options /});
// when your done, you need to return the new content
// if you return nothing, the content is simply removed
return content;
}, hasContent);
`
`js`
// this module automatically closes any open tags, but it defines the tags that should not close
// example: should be closed with , but should Not be closed with
// if you notice any tags that should Not close were missed, you can add them with this function
regve.defineSingleTagType('input');
regve.defineSingleTagType('img');
regve.defineSingleTagType('br');
`js
// lazy loading a page as the user scrolls down, is one of the more advanced options this view engine has to offer
// this option is disabled by default, and can be enabled per page render
// express example
const express = require('express');
const regve = require('regve');
const app = express();
// you may also need to set up a module to get post body, (or use optional get method)
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json({type: ['json']}));
app.engine('html', regve({/ global options /}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.post(function(req, res){
// compatible with nonce script key (set with {{nonce}}) (even if random per click, will send original key in ajax call)
// the nonce key (if set) is pulled from its own script tag to a temp 'let' variable when running an ajax call, to preserve the way google hides the key in console 'elements' on a script tag
res.render('index', {lazyLoad: {tag: 'body', method: 'post', data: req.body.lazyLoadData}});
});
app.get(function(req, res){
// method 'post' will use app.post when sending ajax request to server for next piece of the page
// method 'get' is optional
res.render('index', {lazyLoad: {tag: 'body', method: 'post'}});
});
app.get(function(req, res){
// you can also set the 'lazyLoad.scrollElm' option and append to a different tag than you scrolled to
// this is useful if you want to have a footer scroll with the content, and stay at the bottom when new content is added
// 'scrollElm' can be a class, id, or tag name
res.render('index', {lazyLoad: {tag: 'main', scrollElm: 'body'}});
});
app.get(function(req, res){
// by default, the lazyLoad option will run before any variables are added or functions are run, allowing unused parts of the lazy loaded template to be removed before rendering
// you can disable this if needed, by setting the 'afterVars' option to true
// setting this can be useful if you have a variable that adds the {{#lazyload}} tag dynamically
res.render('index', {lazyLoad: {afterVars: true}});
});
// if you only have specific vars that need to load early, you can set the 'earlyVars' option
// note: 'earlyVars' will only run on basic html var objects. This will skip attributes and escaped vars
res.render('index', {lazyLoad: {earlyVars: ['myContent', 'myScripts', 'myStyles.mainStyle']}});
// data parameter is required for the method that ajax requests to, so it can get the next piece of the page
`
`html
Lazy Load Event Listener
`js
// client side javascript, there is a custom event listener you can use
// this event listener is triggered every time a new page (new content) is lazy loaded
document.addEventListener('onPageLazyLoad', function(e){
// getPage() returns the numbered section loaded, based on separation between {{#lazyload}} tag occurrences
console.log('page', e.detail.getPage());
});
`Auto Ad Insert
`js
// you can easily and automatically place your ads into your website
// this method will place ads by page distance, running on client side, and updating with scrolling for lazy load compatibility
// note: autoAdInsert 'tag' and 'scrollElm' are similar to lazyLoad 'tag' and 'scrollElm'
res.render('index', {autoAdInsert: {tag: 'body', scrollElm: 'window', distance: '120%', topPadding: 1, content: 'My Ad
'}});// autoAdInsert 'distance' can be a percentage of the window height, or an absolute number
res.render('index', {autoAdInsert: {distance: '20%'}});
res.render('index', {autoAdInsert: {distance: 320}});
// you can embed html
res.render('index', {autoAdInsert: {content: ''}});
// or run a script on insert
let onAdInsertScript =
;
res.render('index', {autoAdInsert: {onInsert: onAdInsertScript}});
// you can also add a client side event listener
document.addEventListener('onAdInsert', e => {
e.detail.insertAd('');
});// autoAdInsert 'topPadding' is used to decide how far down the page, before the first ad shows
// a 'topPadding' greater than 1 will try to wait for a specific scroll height before inserting the first ad
res.render('index', {autoAdInsert: {topPadding: 10}});
// a 'topPadding' of 0 will put the first ad at the top of the page
res.render('index', {autoAdInsert: {topPadding: 0}});
// when ads are placed, they go between each child element inside the 'tag' option you specify
// by default, the ads avoid going inside the child elements
// you can also scan the child elements content by setting the 'includeInnerChildren' option to true
res.render('index', {autoAdInsert: {includeInnerChildren: true}});
``