https://github.com/transclusion/runtime
** IN ALPHA ** An isomorphic runtime for functional JavaScript programs.
https://github.com/transclusion/runtime
framework functional isomorphic javascript virtual-dom
Last synced: about 2 months ago
JSON representation
** IN ALPHA ** An isomorphic runtime for functional JavaScript programs.
- Host: GitHub
- URL: https://github.com/transclusion/runtime
- Owner: transclusion
- License: mit
- Created: 2017-09-22T17:18:07.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-04-03T22:31:55.000Z (about 8 years ago)
- Last Synced: 2025-09-14T16:54:15.074Z (9 months ago)
- Topics: framework, functional, isomorphic, javascript, virtual-dom
- Language: TypeScript
- Homepage:
- Size: 108 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# @transclusion/runtime
An isomorphic runtime for functional JavaScript programs.
## Features
* **Inspired by Elm**. Based on concepts similar to Elm’s – in good ol’ JavaScript – with server-side support.
* **Pure.** Write view components using pure functions. Handle side-effects in separate handler functions.
* **Typed**. Written in TypeScript.
## Documentation
### Philosophy
`runtime` separates application logic between the browser, worker and server.
| Scope | Responsibility |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Browser](packages/runtime-browser) | Responsible for updating the DOM and using other Web APIs such as Animation, History, Geolocation, and so on. |
| [Worker](packages/runtime-worker) | Responsible for keeping track of application state, virtual DOM and diffing. The worker also handles network requests. |
| [Server](packages/runtime-server) | Responsible for rendering the initial state of a program, given a set of input properties such as URL path, query parameters, cookies and so on. The server also handles network requests. |
### Motivation for using a worker thread
**Using a worker thread** for maintaining application state and diffing the virtual DOM, keeps heavy operations away
from the main UI thread. **The main UI thread** should mostly be idle, and sometimes perform DOM operations and interact
with other Web APIs.
## Getting started
First install the dependencies:
```sh
npm install @transclusion/vdom -S
npm install @transclusion/runtime-core -S
npm install @transclusion/runtime-browser -S
npm install @transclusion/runtime-server -S
npm install @transclusion/runtime-worker -S
```
### Create a program called `root.js`
Components in `runtime` are called _programs_ (like in Elm).
```jsx
/** @jsx createVElement */
import {createVElement} from '@transclusion/vdom'
// Expose message/command types that will be sent to the browser
export const ports = {
history: ['history/POP_STATE', 'history/PUSH_STATE', 'history/REPLACE_STATE']
}
// Initialize the program’s model value
export function init(props) {
return [{path: props.path, state: props.state, title: props.title}, null]
}
// Update the program’s model value (after which the view is re-rendered)
export function update(model, msg) {
switch (msg.type) {
case 'history/POP_STATE':
case 'history/PUSH_STATE':
case 'history/REPLACE_STATE':
return [{...model, path: msg.path, state: msg.state, title: msg.title}, null]
default:
return [model, null]
}
}
function navView() {
return (
)
}
// Render the view as virtual DOM
export function view(model) {
switch (model.path) {
case '/':
return (
{navView()}
Home screen
)
case '/blog':
return (
{navView()}
Blog screen
)
default:
return (
{navView()}
Not found: {model.path}
)
}
}
```
### In the browser
```js
import {run} from '@transclusion/runtime-browser'
const rootElm = document.getElementById('root')
run(
{
element: rootElm.firstChild,
props: __INITIAL_PROPS__,
worker: new Worker('worker.js')
},
({ports}) => {
ports.history.subscribe(msg => {
switch (msg.type) {
case 'history/PUSH_STATE':
history.pushState(msg.state, msg.title, msg.path)
break
case 'history/REPLACE_STATE':
history.replaceState(msg.state, msg.title, msg.path)
break
}
})
window.addEventListener('popstate', event => {
ports.history.send({
type: 'history/POP_STATE',
path: location.pathname,
state: event.state,
title: document.title
})
})
}
)
```
### In the worker
```js
import {run} from '@transclusion/runtime-worker'
import * as root from './root'
run({
program: root,
scope: this
})
```
### On the server
```js
import {run} from '@transclusion/runtime-server'
import express from 'express'
import * as root from './root'
const app = express()
app.get('/*', (req, res) => {
run({
program: root,
props: {path: req.path}
})
.then(context => {
res.send(`
${context.html}
var __INITIAL_PROPS__ = ${JSON.stringify(context.model)}
`)
})
.catch(err => {
res.status(500)
res.send(err.stack)
})
})
app.listen(3000)
```