Coder Social home page Coder Social logo

vanjs-org / mini-van Goto Github PK

View Code? Open in Web Editor NEW
89.0 5.0 3.0 291 KB

Mini-Van: A minimalist template engine for DOM generation and manipulation, working for both client-side and server-side rendering (SSR)

Home Page: https://vanjs.org/minivan

License: MIT License

JavaScript 65.43% Shell 0.99% TypeScript 6.73% HTML 16.68% CSS 10.17%
compose deno deno-module dom dom-manipulation grab-n-go html-template minimalist server-side-rendering template-engine

mini-van's Introduction

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.7kB in the minified bundle size (0.5kB 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())

Try on jsfiddle

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.5kB and (more importantly) 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>` printed 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}/`))

Preview via CodeSandbox.

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.js 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}/`))

Preview via CodeSandbox.

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:

Requires Deno 1.35 or later.

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>` printed in the console
console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())

console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`)
Deno.serve({port}, 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"},
  },
))

Preview via CodeSandbox.

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.

Sample code:

Requires Deno 1.35 or later.

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}/`)
Deno.serve({port}, 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"},
  },
))

Preview via CodeSandbox.

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.5.6.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.5.6.nomodule.min.js"></script>

Alternative, you can download the files (mini-van-0.5.6.min.js, mini-van-0.5.6.nomodule.min.js) and serve them locally.

You can find all relevant Mini-Van files in this Download Table.

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.

Support & Feedback

🙏 VanJS aims to build a better world by reducing the entry barrier of 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. It takes just one 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.

Contact us: [email protected]

mini-van's People

Contributors

pomdtr avatar tao-vanjs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mini-van's Issues

TS2345 type error when passing `undefined` to a HTML prop/attribute

import van from 'mini-van-plate'
const { a }  = van.tags
a({ id: undefined })

results in a TS2345 error

TS2345: Argument of type  { id:undefined; }  is not assignable to parameter of type  ChildDom<Element, Text>|Props 
Type  { id:undefined; }  is not assignable to type  undefined

Missing types for 'mini-van-plate/van-plate'?

I'm testing out the mini-van-plate/van-plate to create a basic text template on a minimal CodeSandbox instance but I am getting:

image

Therefore the usage:

image

Not sure if I have the tsconfig setup incorrectly or that the type declarations are simply missing. I do get the types when importing mini-van-plate though:

image

And in the usage:

image

Setup

tsconfig.json:

{
  "include": [
    "./src/*"
  ],
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020"],
    "esModuleInterop": true,
    "moduleResolution": "node",
    "allowJs": true
  }
}

package.json:

{
  "name": "node-ts-playground",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.ts",
  "scripts": {
    "start": "nodemon --exec ts-node --esm src/index.ts"
  },
  "dependencies": {
    "@types/node": "14.11.2",
    "jsdom": "21.1.1",
    "mini-van-plate": "^0.3.9",
    "ts-node": "^10.9.1",
    "typescript": "5.0.2"
  },
  "devDependencies": {
    "nodemon": "2.0.0"
  },
  "keywords": [],
  "type": "module"
}

ps. Love what you're doing with vanjs!

Stream rather than concat string?

I think your project is really neat. And was looking into the code. I noticed for the back end you concatenate a lot of strings. I noticed when I was doing it that way that there was a perceivable performance hit (I guess concatenating strings is supposed to use a lot of CPU).

I use this in my personal projects for my "back end" in service workers and thought it might give you some inspiration if you are interested. It uses function generators to stream the strings to the browser instead of concatenating.

https://github.com/jon49/html-template-tag-async

nodenext file resolution: Type error TS2307 Cannot find module 'mini-van-plate/van-plate' or its corresponding type declarations.

When importing mini-van-plate/van-plate from a package with the tsconfig.json:

{
	"compileOnSave": true,
	"compilerOptions": {
		"module": "ESNext",
		"moduleResolution": "nodenext",
		"target": "ESNext",
		"strict": true
	},
	"exclude": [
		"node_modules"
	],
	"references": []
}

The following error occurs:

Type error TS2307
  Cannot find module 'mini-van-plate/van-plate' or its corresponding type declarations.

See the workaround to resolve this issue. As far as I know, it's the simpler one of two solutions. Basically, you have to have the source files in the root directory (no src/ directory), add files: to package.json, & have "moduleResolution": "nodenext" in tsconfig.json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.