Skip to content

switer/comps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

comps

npm version travis-ci

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: Repeat

data

Create data scope and declare variables.

{% data name="send" %}
    My name: {%> name /%}
{% /data %}

Render result:

My name: send

About

Professional modular builder for HTML template.

Resources

License

Stars

Watchers

Forks

Packages

No packages published