Git Product home page Git Product logo

virtual-dom's Introduction

virtual-dom

A JavaScript DOM model supporting element creation, diff computation and patch operations for efficient re-rendering

build status NPM version Coverage Status Davis Dependency status experimental Join the chat at https://gitter.im/Matt-Esch/virtual-dom

Sauce Test Status

Motivation

Manual DOM manipulation is messy and keeping track of the previous DOM state is hard. A solution to this problem is to write your code as if you were recreating the entire DOM whenever state changes. Of course, if you actually recreated the entire DOM every time your application state changed, your app would be very slow and your input fields would lose focus.

virtual-dom is a collection of modules designed to provide a declarative way of representing the DOM for your app. So instead of updating the DOM when your application state changes, you simply create a virtual tree or VTree, which looks like the DOM state that you want. virtual-dom will then figure out how to make the DOM look like this efficiently without recreating all of the DOM nodes.

virtual-dom allows you to update a view whenever state changes by creating a full VTree of the view and then patching the DOM efficiently to look exactly as you described it. This results in keeping manual DOM manipulation and previous state tracking out of your application code, promoting clean and maintainable rendering logic for web applications.

Example

var h = require('virtual-dom/h');
var diff = require('virtual-dom/diff');
var patch = require('virtual-dom/patch');
var createElement = require('virtual-dom/create-element');

// 1: Create a function that declares what the DOM should look like
function render(count)  {
    return h('div', {
        style: {
            textAlign: 'center',
            lineHeight: (100 + count) + 'px',
            border: '1px solid red',
            width: (100 + count) + 'px',
            height: (100 + count) + 'px'
        }
    }, [String(count)]);
}

// 2: Initialise the document
var count = 0;      // We need some app data. Here we just store a count.

var tree = render(count);               // We need an initial tree
var rootNode = createElement(tree);     // Create an initial root DOM node ...
document.body.appendChild(rootNode);    // ... and it should be in the document

// 3: Wire up the update logic
setInterval(function () {
      count++;

      var newTree = render(count);
      var patches = diff(tree, newTree);
      rootNode = patch(rootNode, patches);
      tree = newTree;
}, 1000);

View on RequireBin

Documentation

You can find the documentation for the seperate components in their READMEs

For information about the type signatures of these modules feel free to read the javascript signature definition

DOM model

virtual-dom exposes a set of objects designed for representing DOM nodes. A "Document Object Model Model" might seem like a strange term, but it is exactly that. It's a native JavaScript tree structure that represents a native DOM node tree. We call this a VTree

We can create a VTree using the objects directly in a verbose manner, or we can use the more terse virtual-hyperscript.

Example - creating a VTree using the objects directly

var VNode = require('virtual-dom/vnode/vnode');
var VText = require('virtual-dom/vnode/vtext');

function render(data) {
    return new VNode('div', {
        className: "greeting"
    }, [
        new VText("Hello " + String(data.name))
    ]);
}

module.exports = render;

Example - creating a VTree using virtual-hyperscript

var h = require('virtual-dom/h');

function render(data) {
    return h('.greeting', ['Hello ' + data.name]);
}

module.exports = render;

The DOM model is designed to be efficient to create and read from. The reason why we don't just create a real DOM tree is that creating DOM nodes and reading the node properties is an expensive operation which is what we are trying to avoid. Reading some DOM node properties even causes side effects, so recreating the entire DOM structure with real DOM nodes simply isn't suitable for high performance rendering and it is not easy to reason about either.

A VTree is designed to be equivalent to an immutable data structure. While it's not actually immutable, you can reuse the nodes in multiple places and the functions we have exposed that take VTrees as arguments never mutate the trees. We could freeze the objects in the model but don't for efficiency. (The benefits of an immutable-equivalent data structure will be documented in vtree or blog post at some point)

Element creation

createElement(tree:VTree) -> DOMNode

Given that we have created a VTree, we need some way to translate this into a real DOM tree of some sort. This is provided by create-element.js. When rendering for the first time we would pass a complete VTree to create-element function to create the equivalent DOM node.

Diff computation

diff(previous:VTree, current:VTree) -> PatchObject

The primary motivation behind virtual-dom is to allow us to write code independent of previous state. So when our application state changes we will generate a new VTree. The diff function creates a set of DOM patches that, based on the difference between the previous VTree and the current VTree, will update the previous DOM tree to match the new VTree.

Patch operations

patch(rootNode:DOMNode, patches:PatchObject) -> DOMNode newRootNode

Once we have computed the set of patches required to apply to the DOM, we need a function that can apply those patches. This is provided by the patch function. Given a DOM root node and a set of DOM patches, the patch function will update the DOM. After applying the patches to the DOM, the DOM should look like the new VTree.

Original motivation

virtual-dom is heavily inspired by the inner workings of React by facebook. This project originated as a gist of ideas, which we have linked to provide some background context.

Tools

virtual-dom's People

Contributors

chrisinajar avatar cmtt avatar cogell avatar dylanmcdiarmid avatar eculver avatar ih2502mk avatar jails avatar jameshfisher avatar jesseditson avatar kuraga avatar matt-esch avatar mattlummus avatar melnikov-s avatar mmckegg avatar mtyaka avatar neonstalwart avatar pdehaan avatar raynos avatar rgbboy avatar safareli avatar saming avatar san650 avatar shinnn avatar staltz avatar stoeffel avatar teropa avatar uberesch avatar unframework avatar zolmeister 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

virtual-dom's Issues

How is semver used

Could you explain the reason behind version and semver?

I would like to understand how its used and why, thanks

Root node for patch

I presume that you need to pass in the node created from render() into patch()

var rootNode = render(currTree)
var patches = diff(currTree, nextTree)
patch(rootNode, patches)

Then rootNode will contain the state of nextTree.

What happens when nextTree is ["ul", ...] instead of ["div", ...]. To be able to patch that you would have to somehow mutate the parent of the <div> that is rootNode, which is only possible if rootNode is in the real DOM now instead of being a detached element.

Maybe changing the tagName of the top of a vdom tree is stupid.

Usage for serverside or html-string rendering

So far you have convinced me that the "properties of the js dom object" is a better approach than the "attributes of the html element", at least as long as clientside js is concerned.

However, it would be nice if virtual-dom would also be useful on the server, or to just render a html string.

So instead of just a node = createElement(virtualnode), you could also have a htmlstring = toString(virtualnode)

The svg story

For svg you actually want to set attributes for almost everything.

Like a <circle r=50> the only way you change the radius is to circle.setAttributes("r", "500")

Not sure what a good story for svg is since properties won't really work. maybe a hash table / bloom filter of tagName vs propName to determine whether a certain property should be an attribute.

Tests are not browser safe

In chrome 33 on windows, if you set a style with no valid style properties, no underlying style attribute is created, causing an error in assertEqualNode, which will assert equal attributes.

Setting things like style.foo and style.bar should be avoided if we are going to get sensible results in the browser tests.

Implement Component / Widget

A widget is a primitive similar to Diffable<T>

It allows for implementing sub applications, components, sub tree re-rendering, stateful components, thunks and other concepts outside of virtual-dom

A widget consists of a init, update and destroy methods

type Widget := {
  init: () => DOMElement,
  update: (previous: Widget) => void,
  destroy: () => void
}

When virtual-dom encounters a widget it will init() it if it hasnt seen it before and replace the DOMElement with the created DOMElement.

If virtual-dom encounters a widget in both the left and the right tree it will call right.update(left) to update the right widget with the previous state.

If the virtual-dom sees that a widget has been removed i.e. left is a widget and right is some other kind of node it will call destroy() in which widget can do cleanup.

See an example stateful-widget here

Ability to convert real dom to virtual-dom

In my project, I have a fromDOM method that takes a real dom element (or DocumentFragment) and converts it into a virtualdom node or array.

Would be nice to have that ability here as well.

Hook execution guarantees

Some work is required to ensure that hooks execute on consistent assumptions for inserts. If a new subtree is created and inserted, ideally the hooks are executed after the node has been inserted in the DOM. This means that the render process is a DOM renderer followed by an hook patch operation.

Ideally we would also be able to apply the same strategy to the root node, so it would appear that the vdom render function should return a root node and a set of patch ops for hook execution. Either this or we provide the render function with a mounting function so that we can internally apply the hooks post-mount.

Interested to hear your thoughts on this.

"virtualize" method for creating virtual DOM nodes modelled after the real DOM.

Hello,

I'm very interested in DOM-diffing and was also intrigued by the apparent huge potential hidden in reacts diff algorithm and I'd love to see this project grow into a solid and slick tool, that I would very much like to myself! ;)

Additionally, I wanted to propose a project(realDOMNode) method ("virtualize" is prolly a better name), that will create a virtual DOM from a a real DOM node. This would be very useful together with contenteditable / HTML WYSIWYG editors (e.g. so one could create a diff to get the changes a user made).

Reordering bug

There is a known reordering bug due to the tree-order mutations. It's related to the fact that reordering happens before any deletions, as all patches are applied in tree order (inserts are operations on the parent). This is currently being worked on and should be updated soon, bumping a new version. Using the 2048 example on mercury to show correctness.

todomvc reference implementation

I authored a todomvc reference implementation using virtual-dom

This application is currently very modular. I want to pull all the modules I use into a "framework" that just re-exports them.

At this point i would love some feedback on the structure and how virtual-dom is used.

I would also love to see other reference implementations.

cc @Matt-Esch @neonstalwart @navaru

Pair with DOM-Diff?

At the moment there are two projects in this area with the same goal, I think.
https://github.com/Matt-Esch/virtual-dom and https://github.com/Pomax/DOM-diff

@Pomax has implemented an extensive, functional DOM-diff algorithm and @johanneswilm has been working to refactor and improve it. Meanwhile @Matt-Esch has started building virtual-dom, also with the intention of building a DOM-diffing tool.

I've been following Pomax/DOM-diff for a while, discovered virtual-dom only recently.

Wouldn't it make sense to join each other, work together? I don't know if a merge is feasible/acceptable/favorable, but I thought joined forces usually produce even more awesomeness.

(Also, I'm sorry if the above summary of the work that's been done should turn out not to be fully correct.)

consider removing the `undefined` means do not touch feature

This feature causes confusion as shown in Raynos/mercury#35 (comment)

This issue is dependent on #77

An example of confusion is:

function render() {
  return h('div', [
    Math.random() < 0.5  ?
      h('div', { hidden: true }, 'red') :
      h('div', {}, 'blue')
  ]);
}

Because of the undefined semantics when the blue div is rendered after the red div said diff will stay hidden because no-one ever creates a VPatch record to set hidden to false.

Intuitively you might look at this and assume hidden is set to false.

add an index.js

// index.js
module.exports = {
  diff: require('./diff.js'),
  patch: require('./patch.js'),
  h: require('./h.js')
}

VNodes are missing a namespace

You can just do document.createElement('svg'), but that doesn’t make it an instanceof SVGSVGElement. You really need createElementNS for that, so virtual-dom needs some notion of a namespace, even if it defaults to none (the html one in that case)

Support immutable trees

var vdomH = require('virtual-dom/h')

function h() {
  return Object.freeze(vdomH.apply(null, arguments)
}

// pure function
function renderApp() {
  return h('main', [ ... ])
}

renderApp is a pure function that returns a immutable vtree.

virtual-dom should operate as normally.

support setting attributes

here is one use case for attributes rather than properties...

f = document.createElement('form');
document.body.appendChild(f);
i = document.createElement('input');
f.appendChild(i);
i.value = 'foo';
f.reset(); // i.value is ''
i.setAttribute('value', 'foo');
i.value = 'bar';
f.reset(); // i.value is 'foo';

it should be simple to indicate that you want to use an attribute via the use of [attribute=value] in the tagName string.

h('input.check[type=checkbox][data-foo=bar][name=baz]')

Add diff / patch hints `checkBeforeSet`, `alwaysForceSet`

checkBeforeSet has the semantics of checking whether a property is that value before setting it in patch, effectively adding a GET before SET. (genuine use case)

alwaysForceSet has the semantics of always creating a patch record in the diff function even if the previous value is the same, (speculative use case)

move hooks into a seperate property on vtree

It might make sense to have a separate object for all the hooks instead of putting them in the properties object.

This means h() will have to remove any hook keys from the properties hash and create a hash of hooks.

This is useful as we can then treat properties as generic key value pairs we set in vdom.

stateful vs stateless hooks

We discovered there are two types of hooks

  • stateful. These hooks should be evaluated always, even if diff says the subtrees are equal.
  • stateless. These hooks can be unevaluated if diff says the subtrees are equal.

Currently i believe all hooks are stateful.

Allowing for stateless hooks may increase performance.

tombstone feature

There was talk as being able to mark a dom element in the dom as a tombstone.

This would allow patch in vdom to ignore the element and pretend it doesn't exist.

This has two uses

  • mark elements that will be removed in the future (once an animation is done) as tomb stoned and thus have future patches works whilst its being animated
  • mark elements in the DOM that have been statically rendered but are not represented in virtual dom as tomb stones.

cc @maxogden

Execution of hooks - v0.1.0

There are outstanding questions that need a solid answer before a v0.1.0 release:

  • I want to execute the hook before all properties are set
  • I want to execute the hook after all properties are set
  • I want to execute the hook in-order with properties (key order)
  • I want to set property/execute hook immediately before adding/removing from the DOM
  • I want to set property/execute hook immediately after adding/remove from the DOM
  • I want to delay hook execution until I have appended the root node to the DOM
  • I want to execute hooks only if the parent node is different (soft hooks)

A diff thunk

type Thunk := {
  vnode: VNode,
  render: (prev: Thunk) => VNode
}

type VNode := VTree | Thunk

diff := (VNode, Vnode) => Array<VPatches>

We suspect that our usage of Widget and nested diff() & patch() stops global optimization and causes inefficiencies.

Having a Thunk type in vtree that allows you to basically halt early on diff just like how we use vdom-thunk would allow for an alternative way to do lazy rendering.

canvas or terminal patch

There is an idea floating around that h() can be used to generate templates like

h("surface", [
  h("rect", { x: 100, y: 100, size: 20 }),
  h("line", { x: 100, y: 100, direction: "up", length: 20 })
])

Or can be used to generate

h("terminal-screen", [
  h("line", { indent: colOffset }, "some text"),
  h("line", { indent: colOffset }, "some other text")
])

You can imagine using similar data structures and generalizing h() and diff to anything similar to XML instead of being very DOM specific.

We might need a second h() one that is unopinionated and one that is DOM specific. But diff() could work with anything and generate well structured patch records.

Then we would have dom-patch, canvas-patch and tty-patch

rename `render.js` to something more specific

render is a very vague term that is likely to cause confusion with general application structure.

Elm has a recommended structure of 'Input, Model, Update, Render'. When structuring applications like that there is confusion between virtual-dom/render and the Render.

The same issue occurs when writing a game that has a render loop.

Maybe we should rename this file to to-tree.js as-element.js to-target.js or something similar.

Browser support

What is the target browsers that should be supported?

Personally I would like the code to work with ES5+ and patch older browsers for ES5, so it should target Chrome / Firefox / IE9+

Thoughts?

use git tags and npm version.

If you use npm version patch to increment versions npm will correctly tag your source code.

I tried to review your changes using git lg HEAD v0.0.4 and noticed that your version commits do not have tags.

If you used tags it would be easier to jump around your code and review it :)

Vapoware?

I'm confused by the Example -warning in the readme:

Warning: Vaporware. The virtual-dom is not implemented yet.

What do you mean?

Drop parse-tag, maybe

If I understand from the code h/parse-tag.js is used to allow h('.some-class', ...) and automatically assign a div to it, correct?

Could this be dropped from the core, as its easy to implement outside?

Personally I would write something like this in the render function:

div({ className: 'component' },
  h1('text here'),
  p('more text')
)

Fine grained diffing for classes

Over at https://github.com/Swatinem/virtualdom, I have separated class, data, style and other attributes.
Reason is that class has .classList, data has .dataset and style has .style (with all its inconsistencies)

While I do not particularly care about data or style, I do think that having class be an array (a Set, really) does have some advantages.

Any thoughts?

Roadmap

It would be cool to document a todo of things that are useful here.

This way people that are interested in collaborating can do things that are useful.

Like tests / benchmarks / docs / examples / modularization of lib / etc / etc.

Virtual DOM indexing

Indexing the nodes in a tree is very helpful. It allows us to index the patches and by using a pre-order index we can also eliminate recursion down branches when we know that no child nodes exist in the range. For example

                                    Root (0)

Child (1)                           Child (13)                      Child 3 (18)
childNodes(2 - 12)              childNodes(14 - 17)           childNodes(19- 20)

If we have patches for say, node 19, we don't have to search for DOM nodes in Child (1) or Child(13). It effectively gives us a way to count descendants of a node to determine if an index is a descendant of any given node.

At the moment this indexing occurs on diff. We could eliminate indexing a tree more than once by baking the indexing of nodes into h.

There is a problem with indexing nodes, and that is what happens if a node is inserted into the tree more than once? Should we take care of this use case?

var moose = h ("span", "moose")
var root = h("div", [moose, moose, moose])

We need 3 separate child nodes or the indexing doesn't work. Alternatively we could have the parent keep an index of it's children.

@Raynos do you think we should handle this? Should we index the nodes on creation of the tree and clone the nodes if an index has been set already?

Property diff

Discussion on this has been neglected so I would like to solicit feedback on properties so that we have a mechanism for performing all operations

So the basic mechanism is

diffProps({ test: "hello" }, { test: "goodbye"}) -> { test: "goodbye" }

so basically, if 2 identical keys relate to different values, we patch the value

@Raynos tests suggest this should also work for undefined, but I am not 100% in agreement with this

diffProps({ test: "hello" }, { test: undefined })
// -> { test: undefined }`

Next we consider complex properties:

diffProps({ test: { a: 1, b: 2 } }, { test: { a: 1, b: 3 } })
// -> { test: { b: 3 } }

Note here that the diff produced excludes a, so a is left as it is.

Next we consider unset props

diffProps({ a: 1, b: 2 }, { a : 1 }) -> {}

So in this case, not setting b means "leave it as it is". This is where I would like to center the discussion since it's the most questionable. I believe this is valid. The shape of things to me is that all properties unspecified on a DOM node mean "leave it as the underlying value".

Hooks present us some trouble because if we want a hook to execute only once, there is currently no way to do this without setting the associated value to something or persisting the hook over multiple diffs.

If we accept my suggestion then { value: hook } followed by {} means that the hook for value gets executed and then value is left alone. Furthermore, currently using { value: undefined } means the same thing. This is particularly nice in ternary expressions { value : resetting ? resetValueHook("") : undefined }

Generally speaking, all props tend to be enumerated, so the unset key is natural coding style. I think it's pretty valid to allow unset keys to remain untouched, I think we must consider if we use the value undefined to mean don't touch as well. Either we add a hook to mean don't touch, or if we use undefined to mean don't touch and add an undefined value hook.

So to make that clearer in code form, an execute hook once statement can either look like

  • { value : resetting ? resetValueHook("") : undefined }

Or we can define a noop hook

  • { value : resetting ? resetValueHook("") : noop }

Also, there is still the question of how we perform a delete operation. It seems reasonably valid to delete a key, but I would not imagine this is the norm. Hooks can do this, but perhaps we want something better?

Finally we need to consider if nested properties should be able to contain hooks. While it sounds like an extension of what we currently have, the "propName" value would be up for debate. Without nested hooks, and assuming we rely on hooks to delete keys, the only way to delete a key from a nested object would be to set the entire object with a hook.

To summarise the points that need clarifying:

  • Do we agree that undefined keys should mean "don't touch"
  • Do we use undefined to mean "don't touch" or expose a noop hook?
  • Do we need a mechanism for deleting keys or will hooks suffice?
  • Should hooks be limited to the root or should we allow them to be nested?

Support `component`

Well everyone has his favorite package/build manager.

Since I love using component, it would be awesome if virtual-dom supported that as well.

Hooks

With the discussion about "forcedUpdate" and "sensitiveUpdate" properties in #7, I think it might make sense to expose hooks into the diff and patch functions.

I am not sure how that could work, but just wanted to throw it in.

Using a hook, the user could implement their own rules that might be more complex than "forcedUpdate"/"sensitiveUpdate". I.e. one could try to preserve the cursor position in an <input> if only part of its value changed, or a text diff algorithm could be used in case setting the new value directly is disruptive (might come in handy if multiple entities add to a string, e.g. the class attribute or an <input> value).

(I intend to implement an operational transformation algorithm for DOM diffs. So, I like to bring up use cases that emerge when more than one side changes the tree. Is this something you are interested in supporting with this library?)

Optional purity + referential transparancy

// pure rendering function. Returns new vtree
function ComplexLoginComponent() {
  return ...
}

// pure rendering function. Returns new vtree
function menuBar() {}

// pure rendering function. Returns new vtree
function footerBar() {}

// pure rendering function. returns new vtree
function renderPage() {
  var login = ComplexLoginComponent()

  return h('main', [
    h('header', [
      menuBar(),
      login
    ]),
    mainSection(),
    h('footer', [
      footerBar(),
      login
    ])
  ])
}

If a component is re-used in a vtree twice because computing it is expensive and we want to show it twice on the page it would be nice if this was possible.

This means

  1. vdom should not mutate a vtree
  2. vdom Widget should be able to be implemented without mutation (consider state monad)

check whether property is equal to new value before setting in patch

When implementing some kind of two way data bound input field

function Input(text) {
  return h("input", { value: text, "data-event": "change:on_change_handler" })
}

If we were to keep track of the value of the <input> somehow and re-render the Input function with the current text it would effectively be doing inputElem.value = value in the patch state machine.

This means it would be setting the value property of an inputElem to a value it already has. Doing so mutates the position of the cursor input element. (see http://jsfiddle.net/Cvs4U/ )

If patch were to check whether a property is already the value X before setting it to X it would not have the current position resetting effect that it would have currently.

Implement equality early bail in diff

If you have a currTree and a newTree that you are diffing and the diff algorithm finds two nodes that are the same vdom instance then it can trivially stop recursing (assuming no-one mutates vdom instances, which they should never do).

Use case:

function Header() { ... }

var head = Header()

function render() {
  return h("div", [
    head, body(), footer()
  ])
}

Here we statically create a header for our web app and re-use it everywhere as the contents of the header never changes

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.