• Stars
    star
    123
  • Rank 290,145 (Top 6 %)
  • Language
    JavaScript
  • License
    Other
  • Created over 8 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Use variables, JS-like expressions, and even markup-powered logic in your HTML.

npm node tests coverage code style

Expressions Plugin

Install

npm i -D posthtml-expressions

Usage

const { readFileSync } = require('fs')

const posthtml = require('posthtml')
const expressions = require('posthtml-expressions')

posthtml(expressions({ locals: { foo: 'bar' } }))
  .process(readFileSync('index.html', 'utf8'))
  .then((result) => console.log(result.html))

This plugin provides a syntax for including local variables and expressions in your templates, and also extends custom tags to act as helpers for conditionals and looping.

You have full control over the delimiters used for injecting locals, as well as the tag names for the conditional and loop helpers, if you need them. All options that can be passed to the expressions plugin are shown below:

Options

Option Default Description
delimiters ['{{', '}}'] Array containing beginning and ending delimiters for escaped locals os expressions
unescapeDelimiters ['{{{', '}}}'] Array containing beginning and ending delimiters for unescaped locals
locals {} Object containing any local variables you want to be available inside your expressions
localsAttr locals Attribute name for the tag script which contains locals
removeScriptLocals false Will remove tag script which contains locals
conditionalTags ['if', 'elseif', 'else'] Array containing names for tags used for if/else statements
switchTags ['switch', 'case', 'default'] Array containing names for tags used for switch/case/default statements
loopTags ['each'] Array containing names for for loops
scopeTags ['scope'] Array containing names for scopes
ignoredTag 'raw' String containing name of tag inside which parsing is disabled
strictMode true Boolean value set to false will not throw an exception if a value in locals not found or expression could not be evaluated
missingLocal undefined string defining the replacement value in case value not found in locals. May contain {expression} placeholder

Locals

You can inject locals into any piece of content in your html templates, other than overwriting tag names. For example, if you passed the following config to the expressions plugin:

locals: { className: 'intro', name: 'Marlo', 'status': 'checked' }
<div class="{{ className }}">
  <input type="radio" {{ status }}>
  My name is {{ name }}
</div>
<div class="intro">
  <input type="radio" checked="">
  My name is Marlo
</div>

You can also use the script tag with the attribute locals or you custome attribute containing data to interpolate in the template.

<script locals>
  module.exports = {
    name: 'Scrum'
  }
</script>

<div>My name: {{name}}</div>
<script locals>
  module.exports = {
    name: 'Scrum'
  }
</script>

<div>My name: Scrum</div>

In addition, the use of script tag allow you to use locals defined globally to assign data to variables.

posthtml(expressions({ locals: { foo: 'bar' } }))
  .process(readFileSync('index.html', 'utf8'))
  .then((result) => console.log(result.html))
<script locals>
  module.exports = {
    name: 'Scrum',
    foo: locals.foo || 'empty'
  }
</script>

<div>My name: {{name}}</div>
<div>Foo: {{foo}}</div>
<script locals>
  module.exports = {
    name: 'Scrum',
    foo: locals.foo || 'empty'
  }
</script>

<div>My name: {{name}}</div>
<div>Foo: bar</div>

Missing locals

What to produce in case of referencing a value not in locals can be configured by the missingLocal and strictMode options.

When strictMode is true (default) and leaving the missingLocal option undefined, then "'foo' is not defined" exception is thrown.

Setting strictMode false and leaving the missingLocal option undefined results the string undefined in the output

Setting the option missingLocal to a string will produce that string in the output regardless the value of option strictMode. missingLocal can contain the placeholder {local} which will be replaced with the name of the missing local in the output. This solution allows to:

  1. Silently ignore missing locals by setting missingLocal to ""
  2. Include the name of the missing local in the output to help detect the which value is missing in locals like "#Missing value: {local}"
missingLocal strictMode output
undefined (default) true (default) Error is thrown
undefined (default) false 'undefined'
'' false/true '' (not output)
{local} false/true original reference like {{foo}}

Unescaped Locals

By default, special characters will be escaped so that they show up as text, rather than html code. For example, if you had a local containing valid html as such:

locals: { statement: '<strong>wow!</strong>' }
<p>The fox said, {{ statement }}</p>
<p>The fox said, &lt;strong&gt;wow!&lt;strong&gt;</p>

In your browser, you would see the angle brackets, and it would appear as intended. However, if you wanted it instead to be parsed as html, you would need to use the unescapeDelimiters, which by default are three curly brackets, like this:

<p>The fox said, {{{ strongStatement }}}</p>

In this case, your code would render as html:

<p>The fox said, <strong>wow!<strong></p>

Expressions

You are not limited to just directly rendering local variables either, you can include any type of javascript expressions and it will be evaluated, with the result rendered. For example:

<p class="{{ env === 'production' ? 'active' : 'hidden' }}">in production!</p>

With this in mind, it is strongly recommended to limit the number and complexity of expressions that are run directly in your template. You can always move the logic back to your config file and provide a function to the locals object for a smoother and easier result. For example:

locals: {
  isProduction: (env) => env === 'production' ? 'active' : 'hidden'
}
<p class="{{ isProduction(env) }}">in production!</p>

Ignoring Expressions

Many JavaScript frameworks use {{ and }} as expression delimiters. It can even happen that another framework uses the same custom delimiters you have defined in this plugin.

You can tell the plugin to completely ignore an expression by prepending @ to the delimiters:

<p>The @{{ foo }} is strong with this one.</p>

Result:

<p>The {{ foo }} is strong with this one.</p>

Conditionals

Conditional logic uses normal html tags, and modifies/replaces them with the results of the logic. If there is any chance of a conflict with other custom tag names, you are welcome to change the tag names this plugin looks for in the options. For example, given the following config:

locals: { foo: 'foo' }
<if condition="foo === 'bar'">
  <p>Foo really is bar! Revolutionary!</p>
</if>

<elseif condition="foo === 'wow'">
  <p>Foo is wow, oh man.</p>
</elseif>

<else>
  <p>Foo is probably just foo in the end.</p>
</else>
<p>Foo is probably just foo in the end.</p>

Anything in the condition attribute is evaluated directly as an expressions.

It should be noted that this is slightly cleaner-looking if you are using the SugarML parser. But then again so is every other part of html.

if(condition="foo === 'bar'")
  p Foo really is bar! Revolutionary!

elseif(condition="foo === 'wow'")
  p Foo is wow, oh man.

else
  p Foo is probably just foo in the end.

conditionalTags

Type: array
Default: ['if', 'elseif', 'else']

You can define custom tag names to use for creating a conditional.

Example:

conditionalTags: ['when', 'elsewhen', 'otherwise']
<when condition="foo === 'bar'">
  <p>Foo really is bar! Revolutionary!</p>
</when>

<elsewhen condition="foo === 'wow'">
  <p>Foo is wow, oh man.</p>
</elsewhen>

<otherwise>
  <p>Foo is probably just foo in the end.</p>
</otherwise>

Note: tag names must be in the exact order as the default ones.

Switch statement

Switch statements act like streamline conditionals. They are useful for when you want to compare a single variable against a series of constants.

locals: { foo: 'foo' }
<switch expression="foo">
  <case n="'bar'">
    <p>Foo really is bar! Revolutionary!</p>
  </case>
  <case n="'wow'">
    <p>Foo is wow, oh man.</p>
  </case>
  <default>
    <p>Foo is probably just foo in the end.</p>
  </default>
</switch>
<p>Foo is probably just foo in the end.</p>

Anything in the expression attribute is evaluated directly as an expressions.

switchTags

Type: array
Default: ['switch', 'case', 'default']

You can define custom tag names to use when creating a switch.

Example:

switchTags: ['clause', 'when', 'fallback']
<clause expression="foo">
  <when n="'bar'">
    <p>Foo really is bar! Revolutionary!</p>
  </when>
  <when n="'wow'">
    <p>Foo is wow, oh man.</p>
  </when>
  <fallback>
    <p>Foo is probably just foo in the end.</p>
  </fallback>
</clause>

Note: tag names must be in the exact order as the default ones.

Loops

You can use the each tag to build loops. It works with both arrays and objects. For example:

locals: {
  array: ['foo', 'bar'],
  object: { foo: 'bar' }
}

Array

<each loop="item, index in array">
  <p>{{ index }}: {{ item }}</p>
</each>
<p>1: foo</p>
<p>2: bar</p>

Object

<each loop="value, key in anObject">
  <p>{{ key }}: {{ value }}</p>
</each>
<p>foo: bar</p>

The value of the loop attribute is not a pure expressions evaluation, and it does have a tiny and simple custom parser. Essentially, it starts with one or more variable declarations, comma-separated, followed by the word in, followed by an expressions.

<each loop="item in [1,2,3]">
  <p>{{ item }}</p>
</each>

So you don't need to declare all the available variables (in this case, the index is skipped), and the expressions after in doesn't need to be a local variable, it can be any expressions.

loopTags

Type: array
Default: ['each']

You can define custom tag names to use for creating loops:

Example:

loopTags: ['each', 'for']

You can now also use the <for> tag when writing a loop:

<for loop="item in [1,2,3]">
  <p>{{ item }}</p>
</for>

Loop meta

Inside a loop, you have access to a special loop object, which contains information about the loop currently being executed:

  • loop.index - the current iteration of the loop (0 indexed)
  • loop.remaining - number of iterations until the end (0 indexed)
  • loop.first - boolean indicating if it's the first iteration
  • loop.last - boolean indicating if it's the last iteration
  • loop.length - total number of items

Example:

<each loop='item in [1,2,3]'>
  <li>Item value: {{ item }}</li>
  <li>Current iteration of the loop: {{ loop.index }}</li>
  <li>Number of iterations until the end: {{ loop.remaining }} </li>
  <li>This {{ loop.first ? 'is' : 'is not' }} the first iteration</li>
  <li>This {{ loop.last ? 'is' : 'is not' }} the last iteration</li>
  <li>Total number of items: {{ loop.length }}</li>
</each>

Scopes

You can replace locals inside certain area wrapped in a <scope> tag. For example you can use it after posthtml-include

locals: {
  author: { name: 'John'},
  editor: { name: 'Jeff'}
}
<scope with="author">
  <include src="components/profile.html"></include>
</scope>
<scope with="editor">
  <include src="components/profile.html"></include>
</scope>
<div class="profile">
  <div class="profile__name">{{ name }}</div>
  <img class="profile__avatar" src="{{ image }}" alt="{{ name }}'s avatar" />
  <a class="profile__link" href="{{ link }}">more info</a>
</div>

scopeTags

Type: array
Default: ['scope']

You can define a custom tag name to use for creating scopes:

Example:

scopeTags: ['context']

You can now also use the <context> tag when writing a scope:

<context with="author">
  <include src="components/profile.html"></include>
</context>

Ignored tag

Anything inside this tag will not be parsed, allowing you to output delimiters and anything the plugin would normally parse, in their original form.

<raw>
  <if condition="foo === 'bar'">
    <p>Output {{ foo }} as-is</p>
  </if>
</raw>
<if condition="foo === 'bar'">
  <p>Output {{ foo }} as-is</p>
</if>

You can customize the name of the tag:

var opts = {
  ignoredTag: 'verbatim',
  locals: { foo: 'bar' } }
}

posthtml(expressions(opts))
  .process(readFileSync('index.html', 'utf8'))
  .then((result) => console.log(result.html))
<verbatim>
  <if condition="foo === 'bar'">
    <p>Output {{ foo }} as-is</p>
  </if>
</verbatim>
<if condition="foo === 'bar'">
  <p>Output {{ foo }} as-is</p>
</if>

Maintainers


Jeff Escalante

Denis Malinochkin

Contributors


Michael Ciniawsky

Krillin

Cosmin Popovici

More Repositories

1

posthtml

PostHTML is a tool to transform HTML/XML with JS plugins
JavaScript
2,937
star
2

htmlnano

Modular HTML minifier, built on top of the PostHTML
JavaScript
237
star
3

posthtml-include

Include HTML Plugin
HTML
188
star
4

posthtml-parser

Parse HTML/XML to PostHTMLTree
TypeScript
112
star
5

posthtml-minify-classnames

๐Ÿ“ฉ Rewrites classnames and ids in HTML and CSS to reduce file size.
JavaScript
84
star
6

posthtml-modules

Modules Plugin
JavaScript
84
star
7

posthtml-css-modules

Use CSS modules in HTML
JavaScript
54
star
8

posthtml-postcss

PostCSS Plugin
JavaScript
48
star
9

posthtml-extend

Template extending (Jade-like)
JavaScript
47
star
10

posthtml-render

Render PostHTMLTree to HTML/XML
TypeScript
44
star
11

posthtml-loader

PostHTML for Webpack
JavaScript
42
star
12

posthtml-web-component

Server Side Web Component Render.
JavaScript
35
star
13

posthtml-cli

CLI for PostHTML
JavaScript
29
star
14

posthtml-img-autosize

Auto setting the width and height of <img>
JavaScript
28
star
15

posthtml-beautify

A posthtml plugin to beautify you html files. Online service -
HTML
28
star
16

sugarml

SugarML Parser
JavaScript
24
star
17

posthtml-content

Apply functions to tags through custom attributes
JavaScript
23
star
18

posthtml-inline-css

CSS Inliner
JavaScript
22
star
19

posthtml-mso

Makes writing Outlook conditionals in HTML emails easy.
JavaScript
21
star
20

posthtml-postcss-modules

PostCSS CSS Modules Plugin
JavaScript
20
star
21

posthtml-hint

HTML HINT Plugin
JavaScript
19
star
22

gulp-posthtml

PostHTML for Gulp
JavaScript
18
star
23

posthtml-pug

Pug Parser
JavaScript
17
star
24

posthtml-retext

PostHTML Retext plugin
JavaScript
17
star
25

awesome-posthtml

A curated list of awesome things related to PostHTML
16
star
26

posthtml-custom-elements

Custom Elements Plugin
JavaScript
16
star
27

posthtml-plugins

PostHTML Plugins Catalog
HTML
15
star
28

posthtml.org

Website for posthtml.
HTML
15
star
29

posthtml-components

A PostHTML plugin for creating components with HTML-friendly syntax inspired by Laravel Blade. Slots, stack/push, props, custom tag and much more.
HTML
15
star
30

posthtml-w3c

W3C HTML Validation for PostHTML
JavaScript
15
star
31

posthtml-textr

Textr for PostHTML
JavaScript
13
star
32

posthtml-attrs-parser

PostHTML helper that provides a better API to work with tag attributes.
JavaScript
13
star
33

posthtml-fetch

PostHTML plugin for fetching and displaying remote content.
JavaScript
12
star
34

posthtml-head-elements

Build HTML head elements from a JSON file
HTML
11
star
35

posthtml-match-helper

A helper to expand CSS selectors into PostHTML matcher objects
JavaScript
11
star
36

posthtml-style-to-file

Save DOM styles to CSS file
JavaScript
11
star
37

posthtml-prism

PostHTML plugin for code syntax highlighting with Prism.
JavaScript
11
star
38

posthtml-external-link

Add "rel='external noopenner nofollow'" and "target=_blank" to all external links
TypeScript
11
star
39

posthtml-cache

Add a nanoid to links in you tags
JavaScript
11
star
40

express-posthtml

PostHTML for Express
JavaScript
10
star
41

posthtml-highlight

๐ŸŽจ Syntax Highlighting for PostHTML
TypeScript
9
star
42

posthtml-insert-at

PostHTML plugin to append or prepend HTML to a selector
TypeScript
9
star
43

posthtml-jsxhtml-freemarker

Experimental plugin to convert normalised jsx into java freemarker template
JavaScript
9
star
44

posthtml-tidy

Tidy Plugin
JavaScript
9
star
45

posthtml-jsx

JSX Renderer
JavaScript
8
star
46

posthtml-markdownit

A PostHTML plugin to transform Markdown using markdown-it
JavaScript
8
star
47

posthtml-safe-class-names

Replace escaped characters in CSS selectors and HTML class names.
JavaScript
7
star
48

koa-posthtml

PostHTML for Koa
JavaScript
7
star
49

posthtml-hash

PostHTML plugin for hashing file names
TypeScript
7
star
50

posthtml-spaceless

Spaceless tag to remove whitespace between HTML tags
JavaScript
7
star
51

metalsmith-posthtml

PostHTML for Metalsmith
JavaScript
6
star
52

posthtml-base-url

Prepend a string to source paths in your HTML.
JavaScript
6
star
53

posthtml-sugar-srcset

This shortens the description of the value of srcset.
JavaScript
6
star
54

posthtml-remove-tags

A posthtml plugin for removing tags
JavaScript
6
star
55

posthtml-each

Repeat your HTML-elements with attribute
JavaScript
6
star
56

posthtml-noopener

PostHTML plugin to add 'rel="noopener noreferrer"' to links that open in a new tab
TypeScript
5
star
57

posthtml-extra-attributes

Add new attributes to elements in your HTML
JavaScript
5
star
58

posthtml-mixins

๐Ÿ“ฎ Mixins allow you to create reusable blocks of code.
TypeScript
5
star
59

posthtml-webp

Add webp supporting in your html
JavaScript
5
star
60

rollup-plugin-posthtml

PostHTML plugin for Rollup
JavaScript
5
star
61

posthtml-urls

PostHTML plugin for transforming URLs.
JavaScript
5
star
62

electron-posthtml

PostHTML for Electron
JavaScript
4
star
63

grunt-posthtml

PostHMTL Grunt Plugin
HTML
4
star
64

posthtml-toc

๐Ÿ“‘Table of contents
JavaScript
4
star
65

posthtml-doctype

Doctype Plugin
JavaScript
3
star
66

posthtml-url-parameters

Add parameters to URLs with PostHTML.
JavaScript
3
star
67

posthtml-rtl

A flexible utility to convert HTML to RTL (right to left) and vice versa.
JavaScript
3
star
68

posthtml-reporter

Reporter Plugin
JavaScript
3
star
69

posthtml-stream

Stream Wrapper for PostHTML
JavaScript
3
star
70

posthtml-replace

JavaScript
3
star
71

project-stub

HTML
3
star
72

posthtml-md2html

Render markdown inside html elements.
JavaScript
3
star
73

posthtml-load-plugins

Autoload Plugins for PostHTML
JavaScript
3
star
74

posthtml-nonce

A posthtml plugin create whitelist for specific inline scripts using a cryptographic nonce
JavaScript
3
star
75

posthtml-postcss-treeshaker

posthtml plugin to tree shake css styles using postcss
JavaScript
3
star
76

posthtml-postcss-merge-longhand

Merge longhand properties from inline CSS into shorthand with PostCSS.
JavaScript
3
star
77

posthtml-lint

PostHTML plugin to lint static markup
TypeScript
2
star
78

posthtml-include-md

Include markdown plugin for PostHTML
JavaScript
2
star
79

gulp-htmlnano

Minify HTML with htmlnano
JavaScript
2
star
80

posthtml-plugins-idea

2
star
81

posthtml-rename-attrs

Programmatically rename HTML attributes
JavaScript
2
star
82

posthtml-atomizer

Generate Atomic CSS with Atomizer via PostHTML
JavaScript
2
star
83

posthtml-load-config

Autoload Config for PostHTML
JavaScript
2
star
84

posthtml-inline-favicon

PostHTML plugin to inline favicons
HTML
2
star
85

posthtml-plugin-ts-boilerplate

Create new PostHTML plugins on TypeScript
TypeScript
1
star
86

posthtml-plugin-starter

A starter project for building PostHTML plugins.
JavaScript
1
star
87

posthtml-import

Import HTML Plugin
JavaScript
1
star
88

posthtml-noscript

PostHTML plugin to insert noscript content
TypeScript
1
star
89

posthtml-color-shorthand-hex-to-six-digit

Posthtml plugin convert shorthand hex color codes into full
JavaScript
1
star
90

posthtml-load-options

Autoload Options for PostHTML
JavaScript
1
star
91

posthtml-component

component PostHTML plugin
JavaScript
1
star
92

hapi-posthtml

PostHTML for Hapi
JavaScript
1
star
93

create-posthtml

Add PostHTML to your project
JavaScript
1
star
94

posthtml-i18n

Internalization with PostHTML
JavaScript
1
star
95

posthtml-class-to-css-module

A posthtml plugin for clone class to attribute css-module
JavaScript
1
star
96

esm

webpack HTML Module Helpers
JavaScript
1
star