• Stars
    star
    321
  • Rank 130,752 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Torus is an event-driven model-view UI framework for the web, focused on being tiny, efficient, and free of dependencies.

Torus (torus-dom)

npm torus-dom TypeScript types Build Status gzip size install size

Torus is an event-driven model-view UI framework for the web, focused on being tiny, efficient, and free of dependencies.

You can find the 📄 full documentation for Torus here, on Github pages.

Torus also has an annotated, easy to read version of the entire (pretty concise) codebase, also on Github Pages. Check it out if you want to learn more about how the frameworks is designed, and how the virtual DOM and templating works!

Here's what Torus looks like in action! This is a fully functional counter app, no compilation or bundling steps needed.

Drop this script tag in your HTML

<script src="https://unpkg.com/torus-dom/dist/index.min.js"></script>

... and load this script.

// every view extends Component or StyledComponent
class App extends Torus.StyledComponent {

    init() {
        // initialize our local state
        this.count = 0;
    }

    styles() {
        // we can define dynamically and efficiently injected
        //  styles for our component with styles(), like this.
        //  These styles are also automatically scoped to the
        //  component, and we can use the full, nested SCSS syntax.
        return css`
        font-family: system-ui, sans-serif;
        h1 {
            text-align: center;
        }
        button {
            padding: 4px 8px;
            &:hover {
                opacity: .8;
            }
        }
        `;
    }

    compose() {
        // We define the structure of our component in compose(),
        //  using a JSX- and lit-html-like syntax as a template string.
        return jdom`<main>
            <h1>Hi! You clicked ${this.count} times.</h1>
            <button onclick="${() => {
                this.count ++;
                this.render();
            }}">Count up!</button>
        </main>`;
    }

}

// mount the app to the page
document.body.appendChild(new App().node);

Features

👌 Tiny without compromises

Torus has no production dependencies, requires no build step to take advantage of all of its features, and weighs in at under 5kB gzipped including the templating engine, renderer, component and event system, and CSS-in-JS wrapper. This makes it simple to adopt and ship, for anything from rendering a single component on the page to building full-scale applications.

🏃‍️ Fast and responsive by default

Torus isn't designed to be the fastest virtual DOM library (there are great alternatives like inferno), but performance and responsiveness are among the primary goals of the project. While remaining tiny, Torus tries to be as fast and responsive as possible, especially in rendering. Combined with the small bundle size, this makes Torus great for building web applications for anywhere, on any device.

💻 Portable across the web platform

Torus's architecture encapsulates all of the rendering and updating logic within the component itself, so it's safe to take Component#node and treat it as a simple pointer to the root DOM element of the component. You can move it around the page, take it in and out of the document, embed it in React or Vue components or even web components, and otherwise use it anywhere a traditional DOM element can be used. This allows you to include Torus components and apps in a variety of frontend architectures.

Combined with the small size of Torus, this makes it reasonable to ship torus with only one or a few components for a larger project that includes elements from other frameworks, if you don't want to or can't ship an entire Torus application.

🌍 Internationalization and extensibility

Torus doesn't concern itself with internationalization, but as developers, we can use the APIs available to us make internationalization possible inside our Torus components. Torus exposes much of the rendering process and the virtual DOM to you, the developer, and importantly allows us create a preprocessor that can take in JDOM, and modify it before it reaches the renderer, so we can make modifications to the DOM that the renderer sees with our own code. This makes Torus highly extensible and ideal for i18n. In fact, the component preprocessor API is what makes Torus's Styled() components possible. (Styled() adds a new class name to the JDOM before the component is rendered.)

For example, we might make an I18nComponent, which can act as a base component class for an internationalized project, like this.

class I18nComponent extends Component {

    // The default preprocess method just returns the jdom as-is. We can override it
    //  to modify the JDOM given by component's `#compose()` method before it reaches the
    //  virtual DOM renderer.
    preprocess(jdom, _data) {
        // Here, we might recursively traverse the JDOM tree of children
        //  and call some custom `translate()` function on each string child
        //  and any displayed props like `placeholder` and `title`.
        //  As a trivial example, if we only cared about text nodes on the page,
        //  we could write...
        const translate = jdom => {
            if (typeof jdom === 'string') {
                // translate text nodes
                return yourImplementationOfTranslateString(jdom);
            } else if (Array.isArray(jdom.children)) {
                // it's an object-form JDOM, so recursively translate children
                jdom.children = jdom.children.map(yourImplementationOfTranslateString);
                return jdom;
            }
            return jdom;
        }

        // In production, we'd also want to translate some user-visible properties,
        //  so we may also detect and translate attrs like `title` and `placeholder`.
        return translate(jdom);
    }

}

Examples

I (Linus) use Torus for most of my personal projects when I need a client-side UI library. Some of these projects include:

Influences

Torus's API is a mixture of declarative interfaces for defining user interfaces and views, and imperative patterns for state management, which I personally find is the best balance of the two styles when building large applications. As a general practice, components should try to remain declarative and idempotent, and interact with data models / state via public, stable imperative APIs exposed by data models.

Torus's design is inspired by React's component-driven architecture, and borrows common concepts from the React ecosystem, like the idea of diffing in virtual DOM before rendering, composition with higher order components, and mixing CSS and markup into JavaScript to separate concerns for each component into a single class. But Torus builds on those ideas by providing a more minimal, less opinionated lower-level APIs, and opting for a stateful data model rather than a view/controller layer that strives to be purely functional.

Torus also borrows from Backbone in its data models design, for Records and Stores, for having an event-driven design behind how data updates are bound to views and other models.

Lastly, Torus's jdom template tag was inspired by htm and lit-html, both template tags to process HTML markup into virtual DOM.

Runtime over compilation

Frontend development tooling has been on a trend to doing more and more at build time / compile time, making richer syntaxes and features possible, like adopting proposal-track JavaScript features and JSX. Svelte is a wonderful example of how compile-time tooling can create a categorically difference way of thinking about building user interfaces.

Torus doesn't try to be another build-time tool. One of Torus's goals is to be as useful as possible at runtime while sacrificing as little performance and overhead as possible, so we can eliminate the compile step in development. As a result, Torus is the gold-standard experience of prototyping user interface ideas: just drop a <script> tag in the document and start writing. The downside of this conscious prioritization of runtime over compile-time is that some features that aren't a part of JavaScript syntax just aren't possible without a compile step. Notably, the ECMAScript Decorator syntax and JSX syntax are not possible, but would be useful, were there to be a compile step in building Torus apps. We could write JDOM templates in JSX, which is syntactically very similar, and wrap state-updating methods and event listeners in @render and @bind decorators rather than calling this.render() and .bind(this) at every instance.

Adding compilation support is not currently on the roadmap, but it should be straightforward, since Torus is a subset of modern JavaScript. We may come back to addressing these marginal benefits of compilation in the future, especially if decorators show no progress in the proposal track.

A note on fragments

Similar declarative UI frameworks like React and Preact have introduced the notion of Fragments, which is syntax sugar for rendering an array of (virtual) DOM nodes from a function. This is because while having a component return an array of nodes doesn't make sense on its own, it's often useful to have internal functions that return parts of components and views as nodes without a wrapper element. Torus natively supports an array representation of a list of nodes -- just wrap JDOM objects in an array! Although, unlike in React, a component cannot render more than one node, most use cases of fragments are covered by simply being able to pass around a representation of a list of nodes in an array internally inside a component, and this is intuitively supported out-of-the box in Torus.

I've toyed with the idea of modifying the jdom template tag to be able to turn template representations of fragments like <>...</> into arrays of nodes. jdom is also capable of simply parsing adjacent top-level elements in the template and return them in a single array. However, I decided not to ship these features for now, because I believe these use cases are adequately covered by being able to return the .children of a jdom template, even perhaps one wrapped inside the <>...</> fragment markers for readability, or simply returning an array of JDOM objects. I appreciate the explicitness of the extra step involved in returning a nontraditional array from a rendering operation, and I think the occasional cost of returning arrays as intermediate representations of parts of a view is not worth the extra feature cost.

Compatibility

Torus uses Symbols, Maps, and Sets, so is compatible with the latest versions of all major browsers except Internet Explorer 11. On older browsers that don't support e.g. Array spread operators, you may need to transpile the library to ES5 using a tool like Babel.

Installation and usage

You can install Torus from NPM as torus-dom. Torus is still considered beta, and not to a 1.0 release yet. I believe the API is stable now and most of the major bugs have been squashed, but no guarantees until 1.0.

npm install --save torus-dom
# or
yarn add torus-dom
import { StyledComponent, Record, Store, Router } from 'torus-dom';

Alternatively, you can also just import Torus with:

<script src="https://unpkg.com/torus-dom/dist/index.min.js"></script>

Torus will export all of its default globals to window.Torus, so they're accessible as global names to your scripts. This isn't recommended in production apps, but great for experimenting.

Contributing

If you find bugs, please open an issue or put in a pull request with a test to recreate the bug against what you expected Torus to do. If you have feature requests, I might not necessarily honor it, because Torus is being built mostly to suit my personal workflow and architecture preferences. But I'm open to hearing your opinion! So feel free to open an issue, with the expectation that I might not decide to add the feature to Torus (especially if it'll inflate the bundle size or require a transpiler.)

Builds

You can use both npm and Yarn to develop Torus, but the npm scripts use Yarn, and Yarn is officially supported as it's what I use to develop and build Torus.

To build Torus from source, run

yarn build

This will run ./src/torus.js through a custom toolchain, first removing any debug function calls and running that result through Webpack, through both development and production modes. Both outputs, as well as the vanilla version of Torus without Webpack processing, are saved to ./dist/. Running yarn clean will delete any such build artifacts, as well as any generated coverage reports.

Generating documentation from comments

Torus has a unique system for generating documentation from code comments that begin with //>. To generate comment docs, run

yarn docs

Docs files will be generated at ./docs/ and are viewable on a web browser. Check out the Github page for this project for an example of what this script generates.

Running tests

To run Torus's unit tests and generate a coverage report to coverage/, run

yarn test

This will run the basic test suite on a development build of Torus. More comprehensive integration tests using full user interfaces like todo apps is on the roadmap.

We can also run tests on the production build, with:

yarn test:prod

This won't generate a coverage report, but will run the tests against a minified, production build at dist/torus.min.js to verify no compilation bugs occurred.

Linting

Torus lints with ESLint, using a custom configuration. To run the linter, run

yarn lint

or consider using an editor plugin for ESLint.

More Repositories

1

monocle

Universal personal search engine, powered by a full text search algorithm written in pure Ink, indexing Linus's blogs and private note archives, contacts, tweets, and over a decade of journals.
JavaScript
1,472
star
2

ink

Ink is a minimal programming language inspired by modern JavaScript and Go, with functional style.
Go
557
star
3

blocks.css

Add some dimension to your page with blocks 🚀
HTML
466
star
4

tabloid

A minimal programming language inspired by clickbait headlines
JavaScript
457
star
5

revery

A personal semantic search engine capable of surfacing relevant bookmarks, journal entries, notes, blogs, contacts, and more, built on an efficient document embedding algorithm and Monocle's personal search index.
JavaScript
273
star
6

unim.press

A Reddit front-page reader in the style of The New York Times.
JavaScript
244
star
7

oak

An expressive, simple, dynamic programming language.
HTML
231
star
8

polyx

Productivity suite written from scratch in Ink on the backend and Torus on the web
JavaScript
212
star
9

libsearch

Simple, index-free full-text search for JavaScript
JavaScript
159
star
10

merlot

Web based Markdown writing app built with isomorphic Ink and Torus
JavaScript
150
star
11

h12y

The email service for when just "hey.com" isn't enough.
HTML
147
star
12

modelexicon

This AI Does Not Exist: generate realistic descriptions of made-up machine learning models.
CSS
145
star
13

codeframe

The fastest, easiest way to build and deploy quick static webpages
JavaScript
127
star
14

draw

Real-time collaborative whiteboard on the web
JavaScript
126
star
15

inc

A note-taking tool based on the principles of incremental note-taking, designed for quickly capturing fleeting ideas and growing a knowledge base over time.
Makefile
126
star
16

histools

A collection of tools for generating data visualizations from browser history data
JavaScript
125
star
17

mira

A place for notes, but for the people I keep in touch with
JavaScript
116
star
18

tinyhumans

A little interactive sandbox for tiny people, tiny thoughts, and their tiny stories
HTML
116
star
19

lucerne

A Twitter reader designed for learning from the Twittersphere, built with Ink and Torus
JavaScript
115
star
20

calamity

Self-hosted GPT playground
CSS
110
star
21

stream

A Twitter-like micro-blog for personal project updates and snippets of thought, written in Oak
CSS
83
star
22

burds

Just some burds, jumpin' around in their own little world.
JavaScript
81
star
23

thingboard

A board of things, anywhere you want on the screen
JavaScript
67
star
24

ycvibecheck

Semantic search across every YC company ever. Vibe check your idea?
CSS
57
star
25

lovecroft

Minimal mailing list manager for static sites, with a simple JSON API
Go
57
star
26

frieden

My personal, read-only public availability calendar
JavaScript
55
star
27

paper.css

Lightweight, modern CSS to add some flair to your web-things 📜
HTML
41
star
28

klisp

A Lisp written in about 200 lines of Ink, featuring an interactive literate programming notebook
JavaScript
38
star
29

superstat

Git status + diff across every repo in a directory
Makefile
35
star
30

typogram

Small, minimalistic graphics for powerful ideas in a few words
JavaScript
34
star
31

plume

Small in-memory real time chat server with Go and WebSockets
Go
33
star
32

september

Ink to JavaScript compiler and toolchain, written in Ink itself
JavaScript
29
star
33

yolo

On the yolo page, anything goes... I'll merge any pull request you make to this website.
HTML
28
star
34

x-oak-notebook

Experimental tool for writing dynamic Markdown docs that embed interactive explorable visualizations
HTML
28
star
35

maverick

Web IDE and REPL for the Ink programming language, written in pure Ink on a self-hosted compiler toolchain
JavaScript
27
star
36

pico

Lightweight notepad for ephemeral memos, todos, meeting notes, and more
JavaScript
26
star
37

zone

A URL shortener / note sharing service.
JavaScript
25
star
38

kin

A refined tool for exploring open-source projects on GitHub with a file tree, rich Markdown and image previews, multi-pane multi-tab layouts and first-class support for Ink syntax highlighting.
JavaScript
24
star
39

august

Assembler from scratch written in Ink, supporting ELF on x86_64 and more.
Assembly
23
star
40

codesynth

Generate music from your source code 🎹
JavaScript
23
star
41

albatross

A simple to-do list app
CSS
23
star
42

spectre

Sparse autoencoders for Contra text embedding models
Jupyter Notebook
23
star
43

cornelia

Guess that Taylor Swift line <3
JavaScript
22
star
44

hfm

Hugging Face Download (Cache) Manager
Makefile
21
star
45

sistine

A simple, flexible, productive static site generator written entirely in Ink
HTML
21
star
46

shelf.page

An online, public “blog-shelf” for collecting and sharing interesting reads with your audience. What's on your digital shelf?
JavaScript
21
star
47

clozoom

Close your Zoom meeting tabs automatically
JavaScript
20
star
48

carlisle

A minimal template for a Hugo site
CSS
20
star
49

zerotocode

The best place on the web to learn to make stuff with code
HTML
19
star
50

litterate

Generate beautiful literate programming-style description of your code from comment annotations
JavaScript
19
star
51

xin

Xin (신/心) is a flexible functional programming language with a tiny core, inspired by Lisp and CSP
Go
19
star
52

animated-value

Imperative animation API for declarative UI renderers, like React, Preact, and Torus.
JavaScript
18
star
53

schrift

A more experimental runtime for Ink, focused on perf and instrumentation
Rust
17
star
54

rush

Rush lets you work on many files at once
Makefile
17
star
55

eliza

A modern port of the ELIZA conversational program to pure Ink to run as a command line and in the browser.
CSS
15
star
56

entr

A searchable repository of my personal notes from readings
JavaScript
15
star
57

sounds

A collection of sounds from places I've been
JavaScript
15
star
58

micropress

An Ink library for automatic text summarization
14
star
59

dotink

dotink (.ink) is the Ink programming language's blog, and my general technical blog
HTML
14
star
60

matisse

Gallery of generative art written with Ink
HTML
12
star
61

socialite

Fast social sharing metadata tag generator
JavaScript
12
star
62

traceur

Experimental pathtracing 3D renderer written in Ink
Makefile
12
star
63

tsqdm

TQDM for TypeScript / Deno
TypeScript
12
star
64

xi

A dynamic, stack-based concatenative toy programming language.
Logos
11
star
65

ink-vscode

Support for the Ink programming language in Visual Studio Code
10
star
66

x-oak-klisp

A Klisp (scheme-like flavor of Lisp) implementation in Oak
Vim Script
9
star
67

wintermute

Generating fake blog posts from my blog with a Markov chain
Go
8
star
68

looking-glass

A simple web screenshot API using Puppeteer
JavaScript
8
star
69

lambda

The untyped lambda calculus, implemented in Ink
8
star
70

etch

Dead simple project scaffolding for my commonly used layouts
CSS
7
star
71

oak-syntax-visualizer

Oak syntax visualizer, made for GopherCon 2021
CSS
7
star
72

vanta

Port of thesephist/klisp to pure Go
Go
6
star
73

dotfiles

Config, scripts, rc files 💻
JavaScript
5
star
74

ky

A modal text editor
Go
5
star
75

rational-arithmetic

A no-dependency, lightweight JS library for arithmetic with rational numbers
JavaScript
5
star
76

inkfmt

Code formatter for the Ink programming language
Shell
4
star
77

markovify

Using Markov chains to naively generate sequences of words from training samples.
JavaScript
4
star
78

nought

Personal people-manager, what some people might call a personal CRM
HTML
3
star
79

dessi

A quick, simple server-side-includes expander
JavaScript
3
star
80

papyrus

Small, static-site for hosting read-optimized content, like stories or e-books
HTML
3
star
81

codeliner

Generate codelines: like silhouette outlines, but for your source code
3
star
82

inker

Web API to run Ink code on any device 💻
JavaScript
3
star
83

state-of-startups-bearx

BearX's State of Startups Report
HTML
3
star
84

web-audio-workshop-2020

Web Audio API Workshop for Hack the Fog and hackswiftly 2020
JavaScript
3
star
85

send-tweet

Small Ink program to send tweets using the Twitter JSON API
2
star
86

korona

Take any JavaScript data and get back a reasonably unique hex or rgb color with an optional alpha channel 🖌
JavaScript
2
star
87

strat

Minimal framework for futures, options, and cryptocurrency investments built on the Robinhood (private) API
JavaScript
2
star
88

brandish

Visual branding for humans
JavaScript
2
star
89

hurricane

Zero-configuration, read-only JSON API proxy in front of an Airtable base
Go
2
star
90

traceur-web

Web and JavaScript port of thesephist/traceur
JavaScript
2
star
91

ittr

Small library of iterator-related utility functions for JavaScript
JavaScript
2
star
92

ansi.ink

Ink library for printing with ANSI escape sequences
1
star
93

pandora

A small, HTML5 quiz SPA
JavaScript
1
star
94

generator-vanilla-extension

Yeoman generator for simple chrome extensions
JavaScript
1
star
95

thesephist.github.io

Placeholder for personal website
HTML
1
star
96

pyro

Check if any of the routes in a list of critical routes of an app are failing
Go
1
star
97

sigil

My full-time to-do list and task manager 🔥
JavaScript
1
star
98

notepad

Short bash script to pull up $EDITOR
Shell
1
star
99

talaria

Inward-out gesture recognition in a wearable
Python
1
star
100

blocky-logos

Blocky logos, an exploratory creative project about logo and branding 🌁
HTML
1
star