Skip to content

Commit

Permalink
perf: make the most of streamed rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Harttle authored and harttle committed Oct 1, 2021
1 parent 4358c96 commit aea3441
Show file tree
Hide file tree
Showing 13 changed files with 65 additions and 71 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![npm version](https://img.shields.io/npm/v/liquidjs.svg?logo=npm&style=flat-square)](https://www.npmjs.org/package/liquidjs)
[![npm downloads](https://img.shields.io/npm/dm/liquidjs.svg?style=flat-square)](https://www.npmjs.org/package/liquidjs)
[![Coverage](https://img.shields.io/coveralls/harttle/liquidjs.svg?style=flat-square)](https://coveralls.io/github/harttle/liquidjs?branch=master)
[![Build Status](https://img.shields.io/github/checks-status/harttle/liquidjs/master?style=flat-square)](https://travis-ci.org/harttle/liquidjs)
[![Build Status](https://img.shields.io/github/workflow/status/harttle/liquidjs/Check/master.svg?style=flat-square)](https://github.com/harttle/liquidjs/actions/workflows/check.yml?query=branch%3Amaster)
[![David dependencies](https://img.shields.io/david/harttle/liquidjs.svg?style=flat-square)](https://david-dm.org/harttle/liquidjs)
[![DUB license](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](https://github.com/harttle/liquidjs/blob/master/LICENSE)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/harttle/liquidjs)
Expand Down
18 changes: 14 additions & 4 deletions demo/nodejs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { Liquid } = require('liquidjs')
const engine = new Liquid({
root: __dirname,
extname: '.liquid',
globals: {title: 'LiquidJS Demo'}
globals: { title: 'LiquidJS Demo' }
})

engine.registerTag('header', {
Expand All @@ -21,6 +21,16 @@ const ctx = {
todos: ['fork and clone', 'make it better', 'make a pull request']
}

engine.renderFile('todolist', ctx)
.then(console.log)
.catch(err => console.error(err.stack))
async function main () {
console.log('==========renderFile===========')
const html = await engine.renderFile('todolist', ctx)
console.log(html)

console.log('===========Streamed===========')
const tpls = await engine.parseFile('todolist')
engine.renderToNodeStream(tpls, ctx)
.on('data', data => process.stdout.write(data))
.on('end', () => console.log(''))
}

main()
2 changes: 1 addition & 1 deletion demo/nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"start": "node index.js"
},
"dependencies": {
"liquidjs": "*"
"liquidjs": "latest"
}
}
40 changes: 17 additions & 23 deletions src/builtin/tags/block.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,39 @@
import BlockMode from '../../context/block-mode'
import { BlockDrop } from '../../drop/block-drop'
import { ParseStream, TagToken, TopLevelToken, Template, Context, TagImpl, Emitter } from '../../types'
import { TagToken, TopLevelToken, Template, Context, TagImpl, Emitter } from '../../types'

export default {
parse (this: TagImpl, token: TagToken, remainTokens: TopLevelToken[]) {
const match = /\w+/.exec(token.args)
this.block = match ? match[0] : ''
this.tpls = [] as Template[]
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
.on('tag:endblock', () => stream.stop())
this.liquid.parser.parseStream(remainTokens)
.on('tag:endblock', function () { this.stop() })
.on('template', (tpl: Template) => this.tpls.push(tpl))
.on('end', () => {
throw new Error(`tag ${token.getText()} not closed`)
})
stream.start()
.on('end', () => { throw new Error(`tag ${token.getText()} not closed`) })
.start()
},

* render (this: TagImpl, ctx: Context, emitter: Emitter) {
const blockRender = this.getBlockRender(ctx)
yield this.emitHTML(ctx, emitter, blockRender)
if (ctx.getRegister('blockMode') === BlockMode.STORE) {
ctx.getRegister('blocks')[this.block] = blockRender
} else {
yield blockRender(new BlockDrop(), emitter)
}
},

getBlockRender (this: TagImpl, ctx: Context) {
const { liquid, tpls } = this
const extendedBlockRender = ctx.getRegister('blocks')[this.block]
const defaultBlockRender = function * (superBlock: BlockDrop) {
const renderChild = ctx.getRegister('blocks')[this.block]
const renderCurrent = function * (superBlock: BlockDrop, emitter: Emitter) {
// add {{ block.super }} support when rendering
ctx.push({ block: superBlock })
const result = yield liquid.renderer.renderTemplates(tpls, ctx)
yield liquid.renderer.renderTemplates(tpls, ctx, emitter)
ctx.pop()
return result
}
return extendedBlockRender
? (superBlock: BlockDrop) => extendedBlockRender(new BlockDrop(() => defaultBlockRender(superBlock)))
: defaultBlockRender
},

* emitHTML (this: TagImpl, ctx: Context, emitter: Emitter, blockRender: (block: BlockDrop) => string) {
if (ctx.getRegister('blockMode', BlockMode.OUTPUT) === BlockMode.STORE) {
ctx.getRegister('blocks')[this.block] = blockRender
} else {
emitter.write(yield blockRender(new BlockDrop()))
}
return renderChild
? (superBlock: BlockDrop, emitter: Emitter) => renderChild(new BlockDrop(() => renderCurrent(superBlock, emitter)), emitter)
: renderCurrent
}
}
11 changes: 6 additions & 5 deletions src/builtin/tags/layout.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { assert, Tokenizer, Emitter, Hash, TagToken, TopLevelToken, Context, TagImplOptions } from '../../types'
import BlockMode from '../../context/block-mode'
import { parseFilePath, renderFilePath } from './render'
import { BlankDrop } from '../../drop/blank-drop'

export default {
parseFilePath,
Expand All @@ -16,8 +17,7 @@ export default {
const { renderer } = liquid
if (file === null) {
ctx.setRegister('blockMode', BlockMode.OUTPUT)
const html = yield renderer.renderTemplates(this.tpls, ctx)
emitter.write(html)
yield renderer.renderTemplates(this.tpls, ctx, emitter)
return
}
const filepath = yield this.renderFilePath(this['file'], ctx, liquid)
Expand All @@ -28,13 +28,14 @@ export default {
ctx.setRegister('blockMode', BlockMode.STORE)
const html = yield renderer.renderTemplates(this.tpls, ctx)
const blocks = ctx.getRegister('blocks')
if (blocks[''] === undefined) blocks[''] = () => html

// set whole content to anonymous block if anonymous doesn't specified
if (blocks[''] === undefined) blocks[''] = (parent: BlankDrop, emitter: Emitter) => emitter.write(html)
ctx.setRegister('blockMode', BlockMode.OUTPUT)

// render the layout file use stored blocks
ctx.push(yield hash.render(ctx))
const partial = yield renderer.renderTemplates(templates, ctx)
yield renderer.renderTemplates(templates, ctx, emitter)
ctx.pop()
emitter.write(partial)
}
} as TagImplOptions
4 changes: 2 additions & 2 deletions src/context/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export class Context {
this.globals = opts.globals
this.environments = env
}
public getRegister (key: string, defaultValue = {}) {
return (this.registers[key] = this.registers[key] || defaultValue)
public getRegister (key: string) {
return (this.registers[key] = this.registers[key] || {})
}
public setRegister (key: string, value: any) {
return (this.registers[key] = value)
Expand Down
6 changes: 5 additions & 1 deletion src/drop/block-drop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import { Drop } from './drop'
export class BlockDrop extends Drop {
constructor (
// the block render from layout template
private superBlockRender: () => Iterable<string> = () => ''
private superBlockRender: () => Iterable<any> = () => ''
) {
super()
}
/**
* Provide parent access in child block by
* {{ block.super }}
*/
public super () {
return this.superBlockRender()
}
Expand Down
9 changes: 8 additions & 1 deletion src/emitters/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export interface Emitter {
/**
* Write a html value into emitter
* @param html string, Drop or other primitive value
*/
write (html: any): void;
end (): void;
/**
* Buffered string
*/
buffer: string;
}
15 changes: 6 additions & 9 deletions src/emitters/keeping-type-emitter.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { stringify, toValue } from '../util/underscore'
import { Emitter } from '../types'

export class KeepingTypeEmitter {
public html: any = '';
export class KeepingTypeEmitter implements Emitter {
public buffer: any = '';

public write (html: any) {
html = toValue(html)
// This will only preserve the type if the value is isolated.
// I.E:
// {{ my-port }} -> 42
// {{ my-host }}:{{ my-port }} -> 'host:42'
if (typeof html !== 'string' && this.html === '') {
this.html = html
if (typeof html !== 'string' && this.buffer === '') {
this.buffer = html
} else {
this.html = stringify(this.html) + stringify(html)
this.buffer = stringify(this.buffer) + stringify(html)
}
}

public end () {
return this.html
}
}
8 changes: 2 additions & 6 deletions src/emitters/simple-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import { stringify } from '../util/underscore'
import { Emitter } from './emitter'

export class SimpleEmitter implements Emitter {
public html: any = '';
public buffer = '';

public write (html: any) {
this.html += stringify(html)
}

public end () {
return this.html
this.buffer += stringify(html)
}
}
2 changes: 1 addition & 1 deletion src/emitters/streamed-emitter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { stringify } from '../util/underscore'

export class StreamedEmitter {
public html: any = '';
public buffer = '';
public stream = new (require('stream').PassThrough)()
public write (html: any) {
this.stream.write(stringify(html))
Expand Down
15 changes: 0 additions & 15 deletions src/render/emitter.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/render/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { KeepingTypeEmitter } from '../emitters/keeping-type-emitter'
export class Render {
public renderTemplatesToNodeStream (templates: Template[], ctx: Context): NodeJS.ReadableStream {
const emitter = new StreamedEmitter()
toThenable(this.renderTemplates(templates, ctx, emitter))
toThenable(this.renderTemplates(templates, ctx, emitter)).then(() => emitter.end())
return emitter.stream
}
public * renderTemplates (templates: Template[], ctx: Context, emitter?: Emitter): IterableIterator<any> {
Expand All @@ -29,6 +29,6 @@ export class Render {
throw err
}
}
return emitter.end()
return emitter.buffer
}
}

0 comments on commit aea3441

Please sign in to comment.