Mini-Van: A Minimalist Template Engine for Client/Server-side Rendering without JSX
Mini-Van is an ultra-lightweight template engine for DOM composition and manipulation. With only 0.5kB in the minified bundle size (0.4kB gzipped), Mini-Van enables you to build comprehensive UI with elegant and expressive vanilla JavaScript code:
// Reusable components can be just pure vanilla JavaScript functions.
// Here we capitalize the first letter to follow React conventions.
const Hello = () => div(
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
)
van.add(document.body, Hello())
// Alternatively, you can write:
// document.body.appendChild(Hello())
You can convert any HTML snippet into Mini-Van code with our online converter.
Mini-Van is the slimmed-down version of VanJS, which aims to provide an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Compared to VanJS, Mini-Van further reduces the gzipped minified bundle size to 0.4kB and can be used on the server-side as a template engine.
Server-Side: NPM Integration
Mini-Van can be used on the server side as a template engine to render dynamic web content for HTTP servers. An NPM package was published here: www.npmjs.com/package/mini-van-plate. Thus it can be used in Node.js or Bun.
There are 2 modes for server-side integration: van-plate
mode (based on text templating, thus doesn't need the DOM dependency), and mini-van
mode (based on DOM, thus needs the DOM dependency).
Install
npm install mini-van-plate
van-plate
mode
In van-plate
mode, HTML content is generated purely through text templating. It can be easily integrated with your HTTP server to render dynamic web content. See the sample code below:
import http from "node:http"
import van from "mini-van-plate/van-plate"
const {a, body, li, p, ul} = van.tags
const hostname = '127.0.0.1'
const port = 8080
console.log("Testing DOM rendering...")
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` in the console
console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())
const server = http.createServer((req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(van.html(
body(
p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
),
))
})
server.listen(port, hostname, () =>
console.log(`Server running at http://${hostname}:${port}/`))
As illustrated in the example, render
method can be called on the object returned from the tag function
to generate a string
that can be used for serving.
van.html
is a helper function defined in van-plate.js
that is equivalent to:
(...args) => "<!DOCTYPE html>" + tags.html(...args).render()
mini-van
mode
The behavior in mini-van
mode is similar to the behavior in browser context. i.e.: DOM objects will be created by tag functions
. As Node doesn't have the built-in support for DOM objects, you need to provide a 3rd-party Document
object before integrating with Mini-Van in this mode.
There are multiple 3rd-party options for the Document
object. In the example below, we will demonstrate the integration with the help of jsdom
.
Note that, mini-van
mode doesn't work in Bun yet due to the integration issue with jsdom
.
First, install jsdom
:
npm install jsdom
Sample code:
import http from "node:http"
import jsdom from "jsdom"
import van from "mini-van-plate"
const dom = new jsdom.JSDOM("")
const {html, tags} = van.vanWithDoc(dom.window.document)
const {a, body, li, p, ul} = tags
const hostname = '127.0.0.1'
const port = 8080
console.log("Testing DOM rendering...")
const anchorDom = a({href: "https://vanjs.org/"}, "🍦VanJS")
// anchorDom is an HTMLAnchorElement
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
console.log(anchorDom.outerHTML)
const server = http.createServer((req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(html(
body(
p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
),
))
})
server.listen(port, hostname, () =>
console.log(`Server running at http://${hostname}:${port}/`))
Similar to van-plate
mode, we have a helper function html
defined in mini-van.js
which is equivalent to:
(...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML
Server-Side: Deno Integration
Similarly, Mini-Van can work with Deno as well, in both van-plate
mode and mini-van
mode. A Deno module was published here: deno.land/x/minivan
.
van-plate
mode
Sample code:
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import van from "https://deno.land/x/[email protected]/src/van-plate.js"
const {a, body, li, p, ul} = van.tags
const port = 8080
console.log("Testing DOM rendering...")
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` in the console
console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())
console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`)
await serve(req => new Response(
van.html(
body(
p("Your user-agent is: ", req.headers.get("user-agent") ?? "Unknown"),
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
),
),
{
status: 200,
headers: {"content-type": "text/html; charset=utf-8"},
},
), {port})
mini-van
mode
Likewise, Mini-Van mode needs a 3rd-party DOM library to provide the Document
object. We will show an example with the integration of deno-dom
.
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import { DOMParser } from "https://deno.land/x/[email protected]/deno-dom-wasm.ts"
import van from "https://deno.land/x/[email protected]/src/mini-van.js"
const document = new DOMParser().parseFromString("", "text/html")!
const {tags, html} = van.vanWithDoc(document)
const {a, body, li, p, ul} = tags
const port = 8080
console.log("Testing DOM rendering...")
const anchorDom = a({href: "https://vanjs.org/"}, "🍦VanJS")
// anchorDom is an HTMLAnchorElement
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
console.log(anchorDom.outerHTML)
console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`)
await serve(req => new Response(
html(
body(
p("Your user-agent is: ", req.headers.get("user-agent") ?? "Unknown"),
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
),
),
{
status: 200,
headers: {"content-type": "text/html; charset=utf-8"},
},
), {port})
Client-Side: Getting Started
To get started on the client side, add the line below to your script:
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.3.9.min.js"
To code without ES6 modules, add the following line to your HTML file instead:
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.3.9.nomodule.min.js"></script>
Alternative, you can download the files (mini-van-0.3.9.min.js
, mini-van-0.3.9.nomodule.min.js
) and serve them locally.
Download Table
You can find all relevant Mini-Van files to download in the table below:
Files | Description |
---|---|
| Minified script file for ES6 modules, optimized for bundle size. |
| The source file without minification. |
| Similar to mini-van-0.3.9.min.js , but designed to work in non-module context, such as inline JavaScript or <script type="text/javascript"> . |
| Similar to mini-van-0.3.9.js , but designed to work in non-module context, such as inline JavaScript or <script type="text/javascript"> . |
API Reference
Mini-Van exposes the same set of APIs as VanJS for DOM composition and manipulation. Thus for API reference, you can refer to DOM Composition and Manipulation section of VanJS tutorial. Note that: state and state binding are not supported in Mini-Van.
Source Code
Support & Feedback
🙏 VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever. If you find VanJS interesting, or could be useful for you some day, please consider starring the project on GitHub. It takes just a few seconds but your support means the world to us and helps spread VanJS to a wider audience.
We're looking for the 1.0 milestone (commitment to API stability) soon, your precious feedback will be greatly appreciated. You can submit your feedback by creating issues with the link below:
Star Watch Issue Follow @vanjs-org
Contact us: [email protected]