comps
v2.3.4
Published
Components in server side render.
Downloads
65
Readme
comps
A Precompile and data-independent template engine for nodejs.
Install
npm install comps --save
Start up
Using with ejs, compile and render before ejs rendering.
var comps = require('comps')
var ejs = require('ejs')
/**
* Custom method for loading component's template file by id
*/
comps.componentLoader(function (name) {
return fs.readFileSync(__dirname + '/c/' + name + '/' + name + '.tpl')
})
var tpl = comps({
template: '<div>{% component $id="header" /%}</div>'
})
var html = ejs.render(tpl, data)
See example.
Doc
Class Methods
Comps(options)
- Param: options
<String>
, see options - Return:
<String>
Render given template to string directly with options.
create()
Create Comps instance with isolated private variables.
var Comps = require('comps').create()
Comps({
// ...
})
config(name, value)
- Param: name
<String>
- Param: value
Rendering configuration setter. Supporting properties:
- openTag
<String>
Template syntax of open delimiter. Default "{%". - closeTag
<String>
Template syntax of close delimiter.Default: "%}"
tag(name, def)
Param: name
<String>
Tag name, using as{% xxtag /%}
or{% xxtag %}{%/ xxtag %}
Param: def
<Object>
Tag configuration. Supporting properties:scope
<Boolean>
|<Function>
Optional Whether create a child-scope for the tag.paired
<Boolean>
Optional Restrains the type of tag. if true, can't not using tag as self-closing. If false, the tag must be self-closing. Otherwise has not constraint.created
<Function>
Call when tag is created.outer
<Function>
Call when tag is rendered. Must return Array with two items, item1 is the open tag, item2 is the close tag.inner
<Function>
Call when tag's child template is rendered. Must return String.
Context of defined method:
- $scope
<Object>
Scope of current context, properties will be herited to child-scope. - $el
<Object>
AST node of the tag. - $raw
<String>
Tag's raw content. - $name
<String>
Tag name. - $attributes
<Object>
All attributes of the tag. - $walk
<Function>
AST traverse method, using to continue traverse childNodes of the tag. - $render
<Function>
All attributes of the tag.
compile(tpl)
- Param: tpl
<String>
Compiled template as the same of options.template. - Return:
<Function>
Render method.
Pre-render template and return render method that receive options
as params.
bcompile(options)
- Param: options
<Object>
Template render options, see options - Return:
<Function>
Bigpipe factory function that will return bigpipe instance after calling
Pre-render template and return factory function that will be create a bigpipe
instance after calling.
bigpipe(options)
- Param: options
<Object>
Template render options, see options - Return:
<Object>
Bigpipe instance. See Using Bigpipe
Create a bigpipe
instance directly.
componentLoader(loader)
- Param: loader
<Function>
Custom component template file loader method. loader
function will receive id<String>
as param, id is the component id that given by tag's $id attribute.
Loader should return object as result, and result must contains properties:request
, content
.
Note: Only one loader work, it will overwrite last loader.
fileLoader(loader)
- Param: loader
<Function>
Custom including template file loader method. loader
function will receive request<String>
and context<String>
as params. request is $path attribute and context is the current directory path of the request.
Loader should return object as result, and result must contains properties:request
, content
.
Note: Only one loader work, it will overwrite last loader.
componentTransform(transform)
- Param: transform
<Function>
Add call transform function before component tag rendering. this
of transform point to tag instance and receive component id<String>
as param.
Using Pagelet
Configuration:
var str = Comps({
template: '...',
pagelet: 'main.content'
})
Using pagelet in HTML template:
<div class="main">
{% pagelet $id="main" %}
<div class="content">
{% pagelet $id="content" %}
here is content.
{% /pagelet %}
out side.
</div>
{% /pagelet %}
</div>
Render result:
<div data-pageletid="main.content">
here is content.
</div>
It will be wrapped with a pagelet tag default, set $wrap to false
will disable wrapper.
Using Bigpipe
Create bigpipe instance:
var creator = Comps.bcompile({
template: '...'
})
var bp = creator()
Using chunk in template:
<div>header-{{title}}</div>
{% chunk $id="header" $require="title" /%}
<ul>...{{list}}...</ul>
{% chunk $id="list" $require="list" /%}
<div class="footer"></footer>
Listen events and handle data:
bp.on('chunk', function (chunk) {
res.write(template.render(chunk, this.data))
})
bp.on('end', function () {
res.end()
})
// will emit "header" chunk
bp.set('title', 'xxx')
setTimeout(function () {
// will emit "list" chunk
bp.set('list', [..])
})
Using multiple data at once:
bp.set({
title: 'xxx',
list: []
})
Using endChunk() end up dependence waiting of the chunk:
bp.endChunk('header')
bp.endChunk('list')
Using flush() to check and write chunk when set data directly:
bp.data.title = ''
bp.data.list = []
bp.flush()
End bigpipe
manually, it flush remain chunks immediately but ignore waiting dependences:
bp.end()
Reusable Template
Assume a component template ./index.tpl
as below:
<div class="index">
{% pagelet $id="list" %}
<ul class="list">
<li>item</li>
</ul>
{% /pagelet %}
</div>
If you need do client-side render and reuse the template in some case, you can use comps-loader .
Note: "comps-loader" is comps's template loader for webpack, and you need do some configuration when use it. See detail
Load template in client-side when using comps-loader:
// load full template file
var tpl = require('./index.tpl')
// load pagelet of template
var pagelet = require('!!comps!./index.tpl?pagelet=list')
Pagelet result =>
<ul class="list">
<li>item</li>
</ul>
If you don't like require('!!comps!./index.tpl?pagelet=list')
, you can create an independ file for list template:
./index.tpl
<div class="index">
{% include $path="./list.tpl" /%}
</div>
./list.tpl
:
<ul class="list">
<li>item</li>
</ul>
Load templates:
// load full template file
var tpl = require('./index.tpl')
// load list template
var pagelet = require('./index.tpl')
Options
Options of rendering template with comps(options)
:
template
- Type:
<String>
HTML template for rendering.
pagelet
- Type:
<String>
- Optional
Render those template including in pagelet tag. It compare pagelet
option with pagelet tag's $id
.
See Using pagelet.
chunk
- Type:
<Boolean>
- Optional
Note: Chunk is enable default in
bigpipe
rendering.
If chunk is true, Comps
will render Chunk tag to CHUNK_SPLITER
, such as: <!--{% chunk /%}-->
.
See Using Bigpipe.
context
- Type:
<String>
- Optional
Note: Using with
include
tag.
Specify current directory path of the given template.
Comps Tags
All build-in available tag of comps.
component
Component tag is using to load and handle component template file
Example
{% component $id="header" /%}
It will call componentLoader
to loader component file by id "header".
Tag attributes:
- $id Id name of the component for load component file.
- $tag Specify tag name of component wrapper tag. Optional
- $replace Using component wrapper tag of not, default
false
. Set to "nomerge
" will not copy attributes to template container element, otherwise all attribute from the component tag will copy to template container element and overwrite exist attribute.Optional
Events
componentcreated(tagInstance)
beforecomponentload(id, tagInstance)
componentloaded(id, tagInstance, result)
After load, will get request/context of the component in "tagInstance", changing will change render result.
Insertion point
{% component $id="header" /%}Inner Content{% /component %}
Using $content
:
<div class="header">
{%> $content /%}
</div>
Will render to:
<div class="header">
Inner Content
</div>
noti: Comps's tags of
Inner Content
will be rendered by outer component scope
pagelet
Pagelet tag is using to render template only that included in pagelet if pagelet
option is given.
Example:
{% pagelet $id="header" $wrap=false %}
<div class="header"></div>
{%/ pagelet %}
If pagelet of rendering options is "header", it will render the template included in pagelet tag only.
Attributes:
- $id Id name of the pagelet for matching.
- $tag Specify tag name of pagelet wrapper tag. Optional
- $wrap Using pagelet wrapper tag of not, default
false
. Optional
include
Inline another HTML template file into current template.
Example:
{% include $path="./header.tpl" /%}
Attributes:
- $path File path, can be relative or absolute.
Events
beforefileload(request, context, tagInstance)
fileloaded(result, tagInstance)
After load, will get request/context of the file in "tagInstance", changing will change render result.
Passing data
{% include $path="./header.tpl" $data="{title: 'Comps passing data from include'}"/%}
Using in header.tpl
<div class="header">{%> title /%}</div>
Will render to:
<div class="header">Comps passing data from include</div>
chunk
Bigpipe chunk split tag, and declare data dependences of above chunk.
Example:
...
<div class="header">...</div>
{% chunk $require="title,name" /%}
<div class="footer">...</div>
...
chunk
event will be emitted if require dependences are done.
Attributes:
- $require Require dependences, multiple keys splited by "
,
" .
output(>)
Execute expression and output data that given by component.
Declare data in component tag:
{% component $id="main" $data="{ title: 'Output ag', content: 'Data from components' }" /%}
Templte of "main"
component:
<div>
{%> 'Title is: ' + title /%}
{%> 'Content is: ' + content /%}
</div>
Render result:
<div>
Title is: Output tag
Content is: Data from components
</div>
Build in properties and methods:
- $exist <
Function
> checkout the property in current scope exist or not - $get <
Function
> get property value from current scope - $data <
Object
> expose scope's data object
if(?)
Branch logic, it will render contents if condition's value is truly.
{% component $id="main"
$data="{ isShowText: true }"
/%}
Templte of "main"
component:
<div>
{%? isShowText%}
Hello world
{%/?%}
</div>
Render result:
<div>
Hello world
</div>
Has same build in properties and methods of output(>)
repeat
Create data scope and declare variables.
{% repeat $items="['Comps','Repeat']" $as="item" $index="index" %}
Index: {%> index /%}, Item: {%> item /%}
{% /data %}
Render result:
Index: 0, Item: Comps
Index: 1, Item: Reapt
data
Create data scope and declare variables.
{% data name="send" %}
My name: {%> name /%}
{% /data %}
Render result:
My name: send