├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── composition.js └── server.js ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # tmp files 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | # tmp folders 12 | pids/ 13 | logs/ 14 | results/ 15 | coverage/ 16 | 17 | # node.js 18 | node_modules/ 19 | npm-debug.log 20 | 21 | # osx 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "1" 3 | - "2" 4 | sudo: false 5 | language: node_js 6 | script: "npm run test-cov" 7 | after_script: "npm i -g codecov.io && cat ./coverage/lcov.info | codecov" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vel 2 | [![NPM version][npm-image]][npm-url] 3 | [![build status][travis-image]][travis-url] 4 | [![Test coverage][codecov-image]][codecov-url] 5 | [![Downloads][downloads-image]][downloads-url] 6 | [![js-standard-style][standard-image]][standard-url] 7 | 8 | Efficiently create and render 9 | [virtual-dom](https://github.com/Matt-Esch/virtual-dom) elements. 10 | 11 | ## Installation 12 | ```bash 13 | $ npm install vel 14 | ``` 15 | 16 | ## Usage 17 | ```js 18 | const vel = require('vel') 19 | 20 | const el = vel((h, state) => h.html(`
hello ${state.type} world
`)) 21 | const node = el({ type: 'cruel' }) 22 | 23 | document.body.appendChild(node) 24 | //hello cruel world
25 | ``` 26 | 27 | ## API 28 | ### el = vel(cb(h, state)) 29 | Initialize a new virtual element. Listen to the `render` event. Expects a 30 | `vdom` tree to be returned. `h` accepts [`virtual-dom` elements](https://github.com/Matt-Esch/virtual-dom), 31 | `h.html` accepts 32 | [HTML strings](https://github.com/azer/virtual-html) and `h.svg` 33 | accepts 34 | [`virtual-dom` SVG elements](https://github.com/substack/virtual-hyperscript-svg). 35 | 36 | ### el([state]) 37 | Render the element's vdom tree to DOM nodes which can be mounted on the DOM. 38 | Uses [main-loop](https://github.com/Raynos/main-loop) under the hood. Calling 39 | the method again will re-render the DOM nodes with the new state. Alias: 40 | `el.render([state])`. 41 | 42 | ### el.toString([state]) 43 | Render the element's vdom tree to a string. For example useful to pre-render 44 | HTML on the server, or save to a static file. 45 | 46 | ### vtree = el.vtree([data]) 47 | Get the element's vdom tree. Useful for element composition. 48 | 49 | ## FAQ 50 | ### why did you write this? 51 | Using `virtual-dom` requires quite some boilerplate. `vel` removes the need for 52 | that boilerplate without adding extra features, making it easier to write 53 | `virtual-dom` systems. 54 | 55 | ### why is there no state transport mechanism included? 56 | `vel` does one thing, and only one thing. Instead of including a state transport 57 | mechanism I felt it made more sense to let users decide for themselves how they 58 | want their state to flow between components. 59 | 60 | ### what's the difference between virtual-dom and react? 61 | `react` is an opinionated framework that uses non-standard syntax to create 62 | systems. It forces users to write JS in OO style and is hard to switch from 63 | once you buy into it. `virtual-dom` does away with those opinions, giving users 64 | a blazingly fast rendering engine without the overhead of a framework. 65 | 66 | ### this module sound lot like base-element! 67 | Yeah, definitely! I'm actually a huge fan of 68 | [`base-element`](https://www.npmjs.com/package/base-element). However I wanted 69 | something a little more barebone favoring composition over inheritance. If 70 | inheritance is your thing, definitely check out 71 | [`base-element`](https://www.npmjs.com/package/base-element) (and say hi to 72 | [@shama](https://github.com/shama) for me :grin:). 73 | 74 | ## See Also 75 | - [virtual-dom](https://github.com/Matt-Esch/virtual-dom) 76 | - [virtual-hyperscript-svg](https://github.com/substack/virtual-hyperscript-svg) 77 | - [main-loop](https://github.com/Raynos/main-loop) 78 | - [virtual-html](https://github.com/azer/virtual-html) 79 | - [vdom-to-html](https://github.com/nthtran/vdom-to-html/) 80 | 81 | ## License 82 | [MIT](https://tldrlegal.com/license/mit-license) 83 | 84 | [npm-image]: https://img.shields.io/npm/v/vel.svg?style=flat-square 85 | [npm-url]: https://npmjs.org/package/vel 86 | [travis-image]: https://img.shields.io/travis/yoshuawuyts/vel/master.svg?style=flat-square 87 | [travis-url]: https://travis-ci.org/yoshuawuyts/vel 88 | [codecov-image]: https://img.shields.io/codecov/c/github/yoshuawuyts/vel/master.svg?style=flat-square 89 | [codecov-url]: https://codecov.io/github/yoshuawuyts/vel 90 | [downloads-image]: http://img.shields.io/npm/dm/vel.svg?style=flat-square 91 | [downloads-url]: https://npmjs.org/package/vel 92 | [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 93 | [standard-url]: https://github.com/feross/standard 94 | -------------------------------------------------------------------------------- /examples/composition.js: -------------------------------------------------------------------------------- 1 | const vel = require('vel') 2 | 3 | const header = vel((h, state) => { 4 | return h('h1', state.header) 5 | }) 6 | 7 | const body = vel((h, state) => { 8 | return h('p', state.body) 9 | }) 10 | 11 | const wrap = vel((h, state) => { 12 | return h('section', [ 13 | header.vtree(state), 14 | body.vtree(state) 15 | ]) 16 | }) 17 | 18 | const state = { 19 | header: 'my header', 20 | body: 'lorem ipsum' 21 | } 22 | 23 | document.body.appendChild(wrap.render(state)) 24 | // =>lorem ipsum
27 | // =>Hello my name is ${state.name}
6 | `) 7 | }) 8 | 9 | el.toString({ name: 'Happy Hank' }) 10 | // =>Hello my name is Happy Hank
11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const toHtml = require('vdom-to-html') 2 | const mainLoop = require('main-loop') 3 | const vdom = require('virtual-dom') 4 | const h = require('virtual-dom/h') 5 | const assert = require('assert') 6 | 7 | h.svg = require('virtual-hyperscript-svg') 8 | h.html = require('virtual-html') 9 | 10 | // required for event delegation 11 | // to be handled correctly 12 | require('dom-delegator')() 13 | 14 | module.exports = vel 15 | 16 | // initialize a new virtual element 17 | // fn -> null 18 | function vel (rend) { 19 | assert.equal(typeof rend, 'function') 20 | 21 | var update = null 22 | render.toString = toString 23 | render.render = render 24 | render.vtree = vtree 25 | return render 26 | 27 | // render the element's vdom tree to DOM nodes 28 | // which can be mounted on the DOM 29 | // any? -> DOMNode 30 | function render (state) { 31 | if (update) return update(state) 32 | const loop = mainLoop(state, renderFn(rend), vdom) 33 | update = loop.update 34 | return loop.target 35 | } 36 | 37 | // render the element's vdom tree to a string 38 | // any? -> str 39 | function toString (state) { 40 | return toHtml(renderFn(rend)(state)) 41 | } 42 | 43 | // Get the element's vdom tree. 44 | // any? -> obj 45 | function vtree (state) { 46 | return rend(h, state) 47 | } 48 | } 49 | 50 | // render function 51 | // (fn, fn) -> fn(any?) -> obj 52 | function renderFn (rend) { 53 | return function (state) { 54 | return rend(h, state) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vel", 3 | "version": "1.2.0", 4 | "description": "Create and render virtual-dom elements with ease", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "standard && NODE_ENV=test node test", 8 | "test-cov": "standard && NODE_ENV=test istanbul cover test.js", 9 | "watch": "watch 'npm t'" 10 | }, 11 | "repository": "yoshuawuyts/vel", 12 | "keywords": [ 13 | "helper", 14 | "main-loop", 15 | "render", 16 | "vdom", 17 | "virtual-dom", 18 | "vtree" 19 | ], 20 | "license": "MIT", 21 | "dependencies": { 22 | "dom-delegator": "^13.1.0", 23 | "main-loop": "^3.1.0", 24 | "vdom-to-html": "^2.1.1", 25 | "virtual-dom": "~2.0.1", 26 | "virtual-html": "^2.0.0", 27 | "virtual-hyperscript-svg": "^2.0.0" 28 | }, 29 | "devDependencies": { 30 | "istanbul": "^0.3.17", 31 | "jsdom": "^5.6.1", 32 | "noop2": "^2.0.0", 33 | "raf": "^3.1.0", 34 | "standard": "^4.5.4", 35 | "tape": "^4.0.1", 36 | "watch": "^0.16.0" 37 | }, 38 | "files": [ 39 | "LICENSE", 40 | "README.md", 41 | "index.js" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const noop = require('noop2') 2 | const test = require('tape') 3 | const raf = require('raf') 4 | const vel = require('./') 5 | 6 | test('el = vel() should assert input types', function (t) { 7 | t.plan(1) 8 | t.throws(vel, /function/) 9 | }) 10 | 11 | test('el = vel() should be a function', function (t) { 12 | t.plan(1) 13 | const el = vel(noop) 14 | t.equal(typeof el, 'function') 15 | }) 16 | 17 | test('el() should render an element', function (t) { 18 | t.plan(5) 19 | 20 | const el = vel(function (h, state) { 21 | t.equal(typeof state, 'object') 22 | t.equal(typeof h, 'function') 23 | t.equal(state.foo, 'bar') 24 | return h('div') 25 | }) 26 | const node = el({ foo: 'bar' }) 27 | 28 | t.equal(typeof node, 'object') 29 | t.equal(node.nodeType, 1, 'is dom') 30 | }) 31 | 32 | test('el() can parse string templates', function (t) { 33 | t.plan(2) 34 | 35 | const el = vel(function (h, state) { 36 | return h.html('