npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

useless

v0.1.355

Published

Use Less. Do More. JavaScript on steroids.

Downloads

871

Readme

Use Less. Do More.

A research project, from which I learned a lot. Especially how one shouldn't write code and web frameworks in particular :)

In near future, it will be split into several loosely coupled, clean and maintainable NPM modules, for everyone's convenience. Stay tuned.

Installing | Wiki

> npm install useless

Browser builds

Upcoming features

  • Splitting of distinct framework parts to separate projects (finally, useful ones).

Recent updates / changelog

  • You can override config with command line args, e.g. node example webpack.offline=false, using server/config.js trait.

  • You can now handle interactive terminal input with server/stdin.js trait.

  • ololog logging facility is now separate project (redesigned from a scratch)

  • meta-fields facility now available as a separate NPM module.

  • webpack server trait now supports compress option for crunching scripts with Google Closure Compiler.

  • Webpack Hot Module Replacement now works (run the example app and try change example/index.css). It was previously broken due to webpack-dev-server incompatilibity with Webpack 2. This is solved by introducing webpack-hot-fix.js.

  • You can now use ES6 getter syntax for defining properties in components/traits: get something () { ... }

  • Working on webpack and babel integration for building front-end code (see the webpack server trait and the example app). Will feature continuous builds, hot module replacement, CSS imports and shared code extraction — all configurable from server's config.

  • More NPM modules to come: StackTracey and get-source.

  • ANSI color management now available as separate NPM module: ansicolor.

  • asTable function now available as a separate NPM module: as-table.

  • String.ify function now available as a separate NPM module: string.ify.

  • A wiki entry explaining the Stream concept. Thanks to @kroitor for the translation/adaptation from Russian!

  • Build system now utilizes webpack for squashing require imports. All external dependencies (e.g. underscore) now embedded in useless.client.js — no need to link them separately.

  • Component methods init / beforeInit / afterInit now support Promise interface for asynchronous initialization. Old callback-passing style is gone.

  • A wiki entry explaining the new __ namespace (brought by Promise+). It contains a pack of highly abstract data-processing algorithms that can handle any type of data (arrays, objects, scalars) and any kind of operator function (either sync or async).

  • An early alpha of the new HTTP server framework built around the recent Androgene subsystem. See a brief example here. It allows to write and debug complex asynchronous chains in no time, with unprecedented level of the error reporting legibility.

  • A working prototype of Androgene subsystem, delivering the "supervised Promises" concept for asynchronous/nonlinear logging and stack traces. It is also a core mechanism behind the upcoming unit test system (will replace the old Testosterone thing).

  • Read more...

Running example app

node example

If everything's ok, example app will be running at http://localhost:1333. Currently there's not much example code, but it's on the way.

You may want to look into these projects (built upon Useless.js):

  • Skychat — a simple WebRTC paint/chat app.
  • Wyg — a revolutionary WYSIWYG editor (demo).

Server app framework

require ('./useless')

UselessApp = $singleton (Component, {

    $defaults: {
        webpackEntries: {
            entry: {
                'shared': { // duplicate code will be extracted to shared.js
                    'useless.client':   "./node_modules/useless/build/useless.client.js",
                    'useless.devtools': "./node_modules/useless/build/useless.devtools.js",
                    'index':            "./example/index.js",
                }
            }
        },
        config: {
            webpack: {
                hotReload: true
            }
        }
    },

    $depends: [
        require ('./server/supervisor'), // for auto-reload on code change
        require ('./server/webpack'),
        require ('./server/http')
    ],

/*  Members starting with "/" are HTTP request handlers         */

    '/hello-world':       () => "Hello world!",          // text/plain; charset=utf-8
    '/hello-world/json':  () => ({ foo: 42, bar: 777 }), // application/json; charset=utf-8

/*  File serving  */

    '/':             () => $this.file ('./static/index.html'), // $this is a smart alias for `this`, accessible from anywhere in the request execution context
    '/static/:file': () => $this.file ('./static'),            // any file from ./static folder

/*  Query params matching  */

    '/sqr?x={\\d+}':          ({ x    }) => Math.pow (Number (x),         2),  // x²
    '/pow?x={\\d+}&n={\\d+}': ({ x, n }) => Math.pow (Number (x), Number (n)), // x^n
                 
/*  Put your JSONAPI stuff in /api    */

    '/api': { // tree-style definitions are supported
        
        'login':  { post: async () => $this.doLogin (await $this.receiveJSON) },
        'logout': { post:       () => $http.removeCookies (['email', 'password']) },
    },

/*  A complex request handler example, demonstrating some core features.

    All execution is wrapped into so-called "supervised Promise chain",
    so you don't need to pass the request context explicitly, it is always
    available as $http object in any promise callback related to request
    represented by that object.
    
    All thrown errors and all log messages are handled by the engine
    automagically. It builds a process/event hierarchy that reflects the
    actual execution flow, so you don't need to run a debugger to see what's
    going on, it's all in the log. Request is automatically ended when an
    unhandled exception occurs, no need to trigger it explicitly.               */

    async doLogin ({ email, password }) {

        if (await this.findUser ({ email, password })) {

            $http.setCookies ({ email, password })

        } else {

            throw new Error ('Wrong credentials')
        }
    },

    async findUser (criteria) { /* ... */ },

    init () {

        log.ok ('App started')
    }
})

Example report generated from a Promise chain:

Promise stack demo

Following are $traits defined at useless/server:

Macro processor for prototype definitions

How-to & Examples

Vec2 = $prototype ({

    /*  Constructor
     */
    constructor: function (x, y) { this.x = x; this.y = y },

    /*  Instance method
     */
    add (other) { return new Vec2 (this.x + other.x, this.y + other.y) }

    /*  Instance property (.length)
     */
    get length () { return Math.sqrt (this.x * this.x + this.y * this.y) }),

    /*  Static property: Vec2.zero
     */
    zero: $static ($property (function () { return new Vec2 (0, 0) })),

    /*  Static method: Vec2.dot (a, b)
     */
    dot: $static (function (a, b) { return a.x * b.x + a.y * b.y }),

    /*  Tag groups for convenience
     */
    $static: {
        unit: $property (function () { return new Vec2 (1, 1) }),
        one:  $alias ('unit') }, // member aliases
})

/*  Inheritance (relies on native JavaScript prototype semantics)
 */
BetterVec2 = $extends (Vec2, { /* ... */ })

Component model

How-to & Examples

  • Binds own methods to this automatically
  • Manages bindable $trigger / $barrier / $observableProperty members
  • Tracks bound components / auto-unbinds upon deinitialization
  • Holds parent-child relationship / handles automatic deinitialization
  • Enables $traits to chain into method calls by overlapping method definitions
  • Enforces configuration contracts ($requires, $defaults)

Multicast model for method calls with simple functional I/O

How-to & Examples | Reference

  • _.trigger, _.triggerOnce / one-to-many broadcast
  • _.barrier / synchronization primitive
  • _.observable / state change notifications

Raw API (same for every mentioned primitive):

var mouseMoved = _.trigger ()

/*  Binding
 */
mouseMoved (function (x, y) { }) // bind
mouseMoved (someCallback)        // bind another
mouseMoved.once (someCallback)   // bind with 'once' semantics (auto-unbinds itself upon calling)

/*  Calling
 */
mouseMove (12, 33)               // call

/*  Unbinding
 */
mouseMove.off (someCallback)     // unbinds specific listener
mouseMove.off ()                 // unbinds everything
_.off (someCallback)             // unbinds callback from everything it's bound to

Using $component:

Compo = $component ({

    didLayout:     $trigger (),
    layoutReady:   $barrier (),             // it's like jQueryish $(document).ready
    value:         $observableProperty (),  // for property change notifications
    
    init: function () {
        doSomeUselessAsyncJob (function () {
           this.layoutReady () }) }, // signals that layout is ready

    doLayout: function () {
        this.didLayout () } })       // simply call to perform multicast
compo = new Compo ()

compo.didLayout (function () {
    /*  Gets called whenether layout has rebuilt */ })

compo.layoutReady (function () {
    /*  Postpones until DOM is ready.
        If already, calls immediately (like $(document).ready) */ })

compo.valueChange (function (value, oldValue) {
    /*  Gets called whenether property has assigned distinct value */ })

compo.value = 10 // simply assign a value to notify listeners
compo.value = 10 // won't trigger, as not changed

Bindable methods for ad-hoc code injection

Raw API:

_.onAfter   (Player.prototype, 'move', function (x, y) { /* this will execute after move calls */ })
_.onBefore  (Player.prototype, 'move', function (x, y) { /* this will execute before */ })
_.intercept (Player.prototype, 'move', function (x, y, originalMethod) {
    originalMethod.call (this, x, y) })

Using $component + 'once' semantics:

Button = $component ({
    layout: $bindable (function () { /* ... */ }) })
    
button = new Button ()
button.layout.onceBefore (function () { log ("I'm called before next layout()") })
button.layout ()
button.layout () // won't print anything

Math utility for front-end works

Reference

Working with ranges:

    _.lerp  (t, min, max)  // linear interpolation between min and max
    _.clamp (n, min, max)  // clips if out of range
    
    /*  Projects from one range to another (super useful in widgets implementation)
     */
    _.rescale (t, [fromMin, fromMax], [toMin, toMax], { clamp: true })

Vector math (Vec2, Transform, BBox, Bezier, intersections):

   var offsetVec = this.anchor.sub (this.center).normal.perp.scale (
                       Bezier.cubic1D (
                           Vec2.dot (direction.normal, upVector), 0, 1.22, 0, 1.9))
   var where = this.bodyBBox.nearestPointTo (this.anchor, this.borderRadius)
   domElement.css (BBox.fromPoints (pts).grow (20).offset (position.inverse).css)

Error handling

node.js stacktrace

Panic.js demo

  • Cross-platform uncaught exception handling (works around incomplete 'onerror' impl. in Safari).
  • Uncaught exceptions pass through network API calls
  • Client displays server's exceptions as if it was single environment
  • Complete API for it's internals
  • Strips third party calls (clean mode)
  • Fetches source code (local/remote)
  • Nice output
    • Console mode (replaces default Node.js exception printer)
    • GUI mode (a pop-up dialog with expandable source lines)

Test framework

How-to & Examples

assertion demo

assertion demo

  • Tests before code
  • Tests as documentantion
  • Rich library of assertions
  • Asynchronous / nested assertions
  • Intercepts global log, displaying it in running assertion context
  • Custom assertions
  • Humane error reporting
  • Browser-side support (see demo: youtube.com/watch?v=IWLE8omFnQw)

And more..