Skip to content

Commit cdceb25

Browse files
committed
perf: add cross-engines benchmark
1 parent cc9b283 commit cdceb25

28 files changed

+38727
-8215
lines changed

.mocharc.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
require: "ts-node/register/transpile-only",
3+
reporter: "spec"
4+
}

benchmark/cross-engines.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env node
2+
3+
const Benchmark = require('benchmark')
4+
const data = require('./data/todolist.json')
5+
const path = require('path')
6+
7+
const engines = {
8+
liquid: require('./engines/liquid'),
9+
handlebars: require('./engines/handlebars'),
10+
react: require('./engines/react'),
11+
swig: require('./engines/swig')
12+
}
13+
14+
function crossEngines () {
15+
console.log(' cross engines')
16+
console.log('------------------------')
17+
return new Promise(resolve => {
18+
const suit = new Benchmark.Suite('cross engines')
19+
20+
for (const [name, { load, render }] of Object.entries(engines)) {
21+
const tpl = load(path.resolve(__dirname, `templates/todolist`))
22+
suit.add(name, () => render(tpl, data))
23+
}
24+
25+
suit.on('cycle', event => console.log(String(event.target)))
26+
suit.on('complete', resolve)
27+
suit.run({ async: true })
28+
})
29+
}
30+
31+
module.exports = { crossEngines }

benchmark/data/todolist.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
{
3+
"categories": [{
4+
"color": "red",
5+
"id": "CAT1",
6+
"title": "work"
7+
}, {
8+
"color": "red",
9+
"id": "CAT2",
10+
"title": "emergency"
11+
}, {
12+
"color": "green",
13+
"id": "CAT3",
14+
"title": "sport"
15+
}],
16+
"todos": [{
17+
"title": "fork and clone",
18+
"id": "TODO1",
19+
"category": "work"
20+
}, {
21+
"title": "make it better",
22+
"id": "TODO2",
23+
"category": "sport"
24+
}, {
25+
"title": "make a pull request",
26+
"id": "TODO3",
27+
"category": "work"
28+
}]
29+
}

benchmark/demo.js

100644100755
+6-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const Benchmark = require('benchmark')
22
const { Liquid } = require('..')
3+
const ctx = require('./data/todolist.json')
4+
const { resolve } = require('path')
35

46
const engine = new Liquid({
5-
root: __dirname,
7+
root: resolve(__dirname, 'templates'),
68
extname: '.liquid'
79
})
810

@@ -17,28 +19,14 @@ engine.registerTag('header', {
1719
}
1820
})
1921

20-
const ctx = {
21-
todos: ['fork and clone', 'make it better', 'make a pull request'],
22-
title: 'Welcome to liquidjs!'
23-
}
24-
25-
const template = `
26-
{%header content: "welcome to liquid" | capitalize%}
27-
28-
<ul>
29-
{% for todo in todos %}
30-
<li>{{forloop.index}} - {{todo}}</li>
31-
{% endfor %}
32-
</ul>
33-
`
34-
3522
function demo () {
36-
console.log('--- demo ---')
23+
console.log(' demo')
24+
console.log('------------------------')
3725
return new Promise(resolve => {
3826
new Benchmark.Suite('demo')
3927
.add('demo', {
4028
defer: true,
41-
fn: d => engine.parseAndRender(template, ctx).then(x => d.resolve(x))
29+
fn: d => engine.renderFile('todolist', ctx).then(x => d.resolve(x))
4230
})
4331
.on('cycle', event => console.log(String(event.target)))
4432
.on('complete', resolve)

benchmark/engines/handlebars.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const handlebars = require('handlebars')
2+
const { readFileSync } = require('fs')
3+
const { join } = require('path')
4+
5+
handlebars.registerPartial(
6+
'todo-icon',
7+
readFileSync(join(__dirname, '../templates/todo-icon.hbs'), 'utf8')
8+
)
9+
10+
handlebars.registerHelper('concat', function (...args) {
11+
return args.filter(x => typeof x === 'string').join('')
12+
})
13+
14+
handlebars.registerHelper('url', function (path) {
15+
return `http://example.com${path}`
16+
})
17+
18+
handlebars.registerHelper('inc', function (num) {
19+
return Number(num) + 1
20+
})
21+
22+
handlebars.registerHelper('capitalize', function (str) {
23+
return str[0].toUpperCase() + str.slice(1).toLowerCase()
24+
})
25+
26+
handlebars.registerHelper('upcase', function (str) {
27+
return str.toUpperCase()
28+
})
29+
30+
module.exports = {
31+
load: path => handlebars.compile(readFileSync(path + '.hbs', 'utf8')),
32+
render: (tpl, data) => tpl(data)
33+
}

benchmark/engines/liquid.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const { Liquid } = require('../..')
2+
const { readFileSync } = require('fs')
3+
const { join } = require('path')
4+
5+
const liquid = new Liquid({
6+
root: join(__dirname, '../templates'),
7+
extname: '.liquid'
8+
})
9+
10+
liquid.registerFilter('url', path => `http://example.com${path}`)
11+
12+
module.exports = {
13+
load: path => liquid.parse(readFileSync(path + '.liquid', 'utf8')),
14+
render: (tpl, data) => liquid.renderSync(tpl, data)
15+
}

benchmark/engines/react.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const { readFileSync } = require('fs')
2+
const React = require('react')
3+
const ReactDOMServer = require('react-dom/server')
4+
const babel = require('@babel/core')
5+
const requireFromString = require('require-from-string')
6+
7+
const babelConfig = {
8+
presets: ['@babel/preset-react', '@babel/preset-env']
9+
}
10+
11+
module.exports = {
12+
load: path => {
13+
const src = readFileSync(path + '.jsx', 'utf8')
14+
const transformed = babel.transform(src, babelConfig)
15+
return requireFromString(transformed.code)
16+
},
17+
render: (Component, data) => {
18+
return ReactDOMServer.renderToString(React.createElement(Component, data))
19+
}
20+
}

benchmark/engines/swig.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const swig = require('swig')
2+
3+
swig.setFilter('url', function (path) {
4+
return `http://example.com${path}`
5+
})
6+
7+
swig.setFilter('prepend', function (input, arg) {
8+
return arg + input
9+
})
10+
11+
swig.setFilter('append', function (input, arg) {
12+
return input + arg
13+
})
14+
15+
swig.setFilter('inc', function (num) {
16+
return Number(num) + 1
17+
})
18+
19+
swig.setFilter('capitalize', function (str) {
20+
return str[0].toUpperCase() + str.slice(1).toLowerCase()
21+
})
22+
23+
swig.setFilter('upcase', function (str) {
24+
return str.toUpperCase()
25+
})
26+
27+
module.exports = {
28+
load: path => swig.compileFile(path + '.swig'),
29+
render: (tpl, data) => tpl(data)
30+
}

benchmark/index.js

100644100755
+2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ const { tag } = require('./tag')
33
const { demo } = require('./demo')
44
const { layout } = require('./layout')
55
const { memory } = require('./memory')
6+
const { crossEngines } = require('./cross-engines')
67

78
async function main () {
89
await output()
910
await tag()
1011
await demo()
1112
await layout()
1213
await memory()
14+
await crossEngines()
1315
}
1416

1517
main()

benchmark/layout.js

100644100755
+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const template = `
1818
`
1919

2020
function layout () {
21-
console.log('--- layout ---')
21+
console.log(' layout')
22+
console.log('------------------------')
2223
return new Promise(resolve => {
2324
new Benchmark.Suite('layout')
2425
.add('cache=false', {

benchmark/memory.js

100644100755
+7-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ const engine = new Liquid(engineOptions)
1313
const SAMPLE_COUNT = 1024
1414

1515
function memory () {
16-
console.log('--- memory ---')
16+
console.log(' memory')
17+
console.log('------------------------')
1718
html()
1819
todolist()
1920
}
@@ -29,11 +30,11 @@ function html () {
2930
templates.push(engine.parse(str))
3031
}
3132
const diff1 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
32-
console.log(`${h(str.length)} lorem-html before GC x ${h(diff1)}/tpl (${SAMPLE_COUNT} instances sampled)`)
33+
console.log(`[lorem-html ${h(str.length)}][before GC] ${h(diff1)}/tpl (${SAMPLE_COUNT} runs sampled)`)
3334

3435
global.gc()
3536
const diff2 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
36-
console.log(`${h(str.length)} lorem-html after GC x ${h(diff2)}/tpl (${SAMPLE_COUNT} instances sampled)`)
37+
console.log(`[lorem-html ${h(str.length)}][after GC] ${h(diff2)}/tpl (${SAMPLE_COUNT} runs sampled)`)
3738
}
3839

3940
function todolist () {
@@ -47,15 +48,15 @@ function todolist () {
4748
templates.push(engine.parse(str))
4849
}
4950
const diff1 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
50-
console.log(`${h(str.length)} todolist before GC x ${h(diff1)}/tpl (${SAMPLE_COUNT} instances sampled)`)
51+
console.log(`[todolist ${h(str.length)}][before GC] ${h(diff1)}/tpl (${SAMPLE_COUNT} runs sampled)`)
5152

5253
global.gc()
5354
const diff2 = (getHeapStatistics().used_heap_size - base) / SAMPLE_COUNT
54-
console.log(`${h(str.length)} todolist after GC x ${h(diff2)}/tpl (${SAMPLE_COUNT} instances sampled)`)
55+
console.log(`[todolist ${h(str.length)}][after GC] ${h(diff2)}/tpl (${SAMPLE_COUNT} runs sampled)`)
5556
}
5657

5758
function h (size) {
58-
return (size / 1024).toFixed(3) + ' kB'
59+
return (size / 1024).toFixed(3) + ' KB'
5960
}
6061

6162
module.exports = { memory }

benchmark/output.js

100644100755
+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const { Liquid } = require('..')
44
const liquid = new Liquid()
55

66
function output () {
7-
console.log('--- output ---')
7+
console.log(' output')
8+
console.log('------------------------')
89
return new Promise(resolve => {
910
new Benchmark.Suite('output')
1011
.add('literal', test('{{false}}{{"foo"}}{{32.322}}'))

0 commit comments

Comments
 (0)