expviewer
v1.1.0
Published
A view engineer for express application that use a litle php like syntax to describe view with some interesting features
Downloads
3
Readme
expviewer
Expviewer is a view engineer for express application that use a litle php like syntax to describe view with some interesting features
installation
npm install expviewer
first view
A sample preview in vscode
core description
The view basically use a classic html syntax but enable to use two tags to embed a javascript code that will be executed in a nodejs context . Those are:
<?exp /* block code */ ?>
to describe a script that will run in the context an eventually write something inside the final generated response<?e= /* inline expression */ ?>
for an expression that result will append inside the finale response
basic documentation
The embedded script is executed in a nodejs context, so we can use all the basic javascript syntax an functionality inside it, but we can also use the nodejs's require api to require node modules, js an json files inside the embedded script in your views.
Additionally to the basic javascript api, there are some build-in constants and functions that you can use in your exp script , they are :
__view: string
: a string containing the current view's absolute path__filename: string
: the absolute path to the script that required the expviewer module- app.js
const exp = require("expviewer") // ... app.engine("exp", exp) app.set("view enginer", "exp") // ... app.get("/test", (req, res)=>{ res.render("view") })
- view.exp
<span> <?e= __filename ?> </span>
the result will be
<span><!-- path/to/app.js --> </span>
__dirname: string
: the folder in which the requirer of expviewer is located__module: string
: the relative path from execution context to the requirer file , useful to require a local script or json inside the view- paths description
src >app.js ... models index.js ...
- require the models/index.js from view.exp
<?exp const models = require(__module+"../models") // the requirer here is app.js ?>
include: (view: string)=>void
: a function to include view inside other view; inclusions are made during the compilation so, the use of variables as parameters is currently not possible.
<?exp
let view = "includ"
include(view) // this will throw a ReferenceError
include("inc"+"clude"+2) // this will include the related "include2.exp" view
?>
print: (value: string|any)=>void
: a build in function used to write something inside the response that will be generatedprintln: (value: string|any)=>void
: do the same job thanprint
but with a line break ( just a\n
not<br />
)write: (value: string|any)=>void
: alias forprint
writeHtml: (value: string|any)=>void
: alias forprint
which escape html specials characters before printing<pre> <?exp writeHtml(fs.readFileSync(__filename, "utf8")) ?> </pre>
writeJs: (value: string|any)=>void
: alias forprint
that format string to prevent error in javascript context before printing<script> let code = "<?exp writeJs(fs.readFileSync(__filename, "utf8")) ?>" </script>
escapeHtml: (value: string)=> string
: escape html's special character and return the resultescapeJs: (value: string)=> string
: escape string to avoid error in javascript context
using the render option, you can add or override some globals variables initially declared in the execution context
- route.js
const products = require("../products") app.get("/products", (req, res)=>{ // ... res.render("products", { //override __filename and __dirname __filename, __dirname, title: " our products", products }) })
- products.exp
<!-- ... --> <head> <title><?e= title ?</title> </head> <body> <!-- ... --> <?exp products.forEach(prod=>{ ?> <!-- show product some how --> <?exp }) ?> <script> // debug product console.log(<?e= JSON.stringify(products) ?>) </script> </body>
Limitations
Because the view is read an evaluated synchronously an from one to end and exit directly when the last line is evaluated, it is not actually possible to run an asynchronous code in the exp script (with usage of callback functions) but it is possible to use the await
keyword directly in the main scope (no need to be in an async
function, but just in the main scope if you want to use await in a function , this still need the function to be an async function); considering this, you could change your functions with callback to promise then await when required in the main scope
<?exp
const util = require("util")
const fs = require("fs")
const readfile = util.promisify(fs.readFile)
// or
function readFile2(file, encoding = "utf8"){
return new Promise((resolve, reject)=>{
fs.readFile(file, encoding, (err, val)=>{
if(err){
reject(err)
break
}
resolve(val)
})
})
}
print(await readFile(__filename, "utf8"))
print(await readFile2(__filename))
?>
But because of using await
, if the treatment take to mush time, this will take effect on your server's response time but if you well thing your script, this could be no problem. You must eventually do some work ahead and parse the result to the render options
app.get("/code", (req, res)=>{
fs.readFile("file", "utf8", code=>{
res.render("code", {code})
})
})
Moreover, error tracking and translating to their original positions is included, but syntax errors may not be at their right position, so in general you will have to be careful with closing exp tags and other syntax errors. you can refer to your editor's syntax highlighting to see syntax errors if you have installed the corresponding extension (for vscode
or Sublime Text
)
plus
There is a vscode syntaxe support extension ( Exp Support ) and a Sublime Text syntaxe support package ( Exp-language-support ) that will highlight your code ( but they just offert code highlight for the moment )
Any contribution with th aim of correcting any errors, improving or add features would be welcome, as well as your feedback on errors and inconveniences encountered with expviewer.