LiquidJS supports both sync and async evaluate, and can be used with Promises. To reuse the same set of tag/filter implementations in both sync and async, LiquidJS tags are implemented as generators.
Sync and Async API
All major methods on Liquid supports both sync and async. These methods return Promises:
render()renderFile()parseFile()parseAndRender()evalValue()
The synchronous version of methods contains a Sync suffix:
renderSync()renderFileSync()parseFileSync()parseAndRenderSync()evalValueSync()
Implement Sync-Compatible Tags
LiquidJS uses a generator-based async implementation to support both async and sync in one piece of tag implementation. For example, below UpperTag can be used in both engine.renderSync() and engine.render().
1 | import { TagToken, Context, Emitter, TopLevelToken, Value, Tag, Liquid } from 'liquidjs' |
All builtin tags are implemented this way and safe to use in both sync and async (I’ll call it sync-compatible). To make your custom tag sync-compatible, you’ll need to:
- declare render function as
* render(), in which - do not directly
return <Promise>, and - do not call any APIs that returns a Promise.
Call APIs that return a Promise
But LiquidJS is Promise-friendly, right? You can still call Promise-based functions and wait for that Promise within tag implementations. Just replace await with yield. e.g. we’re calling fs.readFile() which returns a Promise:
1 | * render (ctx: Context, emitter: Emitter) { |
Now that this * render() calls an API that returns a Promise, so it’s no longer sync-compatible.
Non Sync-Compatible TagsNon sync-compatible tags are also valid tags, will work just fine for asynchronous API calls. When called synchronously, tags that return a
Promisewill be rendered as[object Promise].
Convert LiquidJS async Generator to Promise
You can convert a Generator to Promise by toPromise, for example:
1 | import { TagToken, Context, Emitter, TopLevelToken, Value, Tag, Liquid, toPromise } from 'liquidjs' |
Async only Tags
If your tag is intend to be used only asynchronously, it can be declared as async render() so you can use await in its implementation directly:
1 | import { toPromise, TagToken, Context, Emitter, TopLevelToken, Value, Tag, Liquid } from 'liquidjs' |