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

osh-page

v0.0.5

Published

openscihub.org: abstract webpage for isomorphic webdev

Downloads

4

Readme

Page

A Page is a javascript abstraction of a webpage meant to help you build isomorphic web apps. You can think of it as the model layer. It was built with ReactJS in mind as the view/rendering layer but is generic enough for use with any templating/view system (e.g. Handlebars).

The abstraction helps you with:

  • "isomorphism"
  • progressive enhancement
  • AJAX on the client
  • API interaction

with the following client/server interaction flow in mind (forward in time is down):

................                ..................              .......
|    Browser   |                |  Page server   |              | API |
|              |  Request page  |                |              |     |
|              |--------------->|                |              |     |
|              |                |                |   GET data   |     |
|              |                |                |<------------>|     |
|              |                | 1. Render HTML |              |     |
|              |                | 2. Stash data  |              |     |
|              |    Send HTML   |                |              |     |
|              |<---------------|                |              |     |
| 1. See HTML! |                |                |              |     |
|              |    GET js      |                |              |     |
|              |<-------------->|                |              |     |
| 1. Get stash |                |                |              |     |
| 2. Enhance   |                |                |              |     |
|    HTML w js |                |                |              |     |
| 3. Navigate  |                |                |              |     |
|              |    GET js?     |                |              |     |
|              |<-------------->|                |              |     |
|              |                |                |              |     |
|              |                |................|              |     |
|              |                                                |     |
|              |                     GET data?                  |     |
|              |<---------------------------------------------->|     |
| 1. Render    |                                                |     |
|    HTML      |                                                |     |
|      .       |                                                |  .  |
|      .       |              (AJAX from here down)             |  .  |
|      .       |                                                |  .  |
v              v                                                v     v

The design of Page closely ties data with URIs. That is, requests for more/different data should be accompanied by navigation/URI-changes and vice versa. This is a necessary design choice if your app promises to serve static pages; otherwise, you will be serving the same dataset under two different URIs (maybe not so bad) or different datasets under the same URI (bad for linking).

URL hash fragments should be used for different views of the same page, since the hash fragment is not sent to the server when requesting a page. This means Page supports AJAX through the HTML5 history API.

Installation

npm install osh-page

Example

Here is a minimal yet complete example. There is no dynamic js on the client yet; this is a simple static page server. Run this in Node.js (script is at example/simple.js).

var Page = require('..');
var express = require('express');
var request = require('superagent');
var html = require('html');
var http = require('http');

var page = Page({
  title: 'My page', 
  path: {
    pattern: '/home'
  },
  body: function(props) {
    return '<h1>Welcome!</h1>';
  }
});

var app = express();
page.serve(app);

var server = http.createServer(app);
server.listen(3333, function() {
  request.get('localhost:3333/home')
  .end(function(res) {
    console.log(
      html.prettyPrint(res.text)
    );
    server.close();
  });
});

A small mess of html should print to the console that looks something like:

<!DOCTYPE html>
<html>

    <head>
        <title>My page</title>
    </head>

    <body>
        <div id="__mount">
            <h1>Welcome!</h1>
        </div><span id="__stash" data-stash="{&quot;data&quot;:{},&quot;params&quot;:{},&quot;query&quot;:{},&quot;id&quot;:&quot;/home&quot;,&quot;uri&quot;:&quot;/home&quot;}"></span>
    </body>

</html>

Documentation

Configuration

Create a new Page instance by calling Page(...) with a config object holding the following properties.

title (String|Function)

The title can be a simple string or a function that accepts a props object as its single argument.

path (Object|Path)

A Path instance or config object. The page will be served at this url after a call to Path.serve().

body (Function)

The body function takes the props object and returns a string. This string is injected into the <div id="__mount"> tag as shown above.

ui (Function)

This function is called after a Page has been rendered to the DOM. On an initial page load, the

data (Object)

The data object is more complex and is at the heart of Page's functionality. This object is a set of namespaces of the developer's choosing, each equipped with the following properties.

var page = Page({
  // ...
  data: {
    user: {
      stash: function(user) {
        // Return only a subset of user if you don't want to stash everything.
        return user;
      },
      find: function(user) {
        var username = document.getElementById('username').textContent;
        return extend(user, {username: username});
      },
      get: function(props, callback) {
        superagent.get('https://api.github.com/...')
        .end(function(err, res) {
          callback(err, res.body);
        });
      }
    },
    post: { /* e.g. a blog post */ }
  },
  // ...
});
data.{namespace}.get (Function)

Signature

get(Object props, Function callback)

Make a request for some data (asynchronously) and pass the data to a callback when finished. The returned data will be assigned to props.data.{namespace} (see the props object).

Note, the props object passed as first argument to this function does not include the data property.

data.{namespace}.path (Path)

This must be a Path instance, and will be queried (via GET request) automatically by Page when it is gathering its data prior to rendering. It is a convenience for data.{namespace}.get.

Note that the path and query parameters given to a data path GET request are those given to the various methods that request a Page (e.g. visit()). If a translation is required between page parameters and data path parameters, you must use data.{namespace}.get instead.

data.{namespace}.stash (Function|Boolean)

Signature

stash(* namespace)

This function is called on the server and determines what data is stashed in the <span id="__stash"> element. If not a function, its truthiness determines whether to stash all or none of this namespace's data (default is undefined which is falsey).

On initial page load in the browser, Page automatically loads data from <span id="__stash">, passing it to ui() for progressive enhancement (and/or body() on subsequent navigation). If the data namespace does not exist in the stash, it is loaded via an API request.

The purpose of the stash option is to prevent duplicate requests to APIs on initial page load if raw data is needed by your page's javascript; the API requests are made once on the server, and the resulting data is stashed in the DOM for immediate use on the client.

The design of the callback allows selective stashing for when only some of the data under a namespace is large. Simply return from the stash function the data you would like saved to <span id="__stash">. Use the find callback to recover the unstashed data from the DOM.

data.{namespace}.find (Function)

Signature

find(* namespace)

Recover unstashed data for this namespace from the DOM in the browser. This function is given the namespace data recovered from <span id="__stash"> and should return the fully recovered namespace data (this often means calling something like extend() on the data recovered from <span id="__stash"> and returning the result).

The props object

After a Page has finished gathering data, it will pass a props object to various rendering callbacks defined on the Page config object. The props object will have the following properties:

id (String)

An id describing which Page instance this props belongs to.

uri (String)

The Page uri built from the given path and query parameters. parameters.

data (Object)

The object of data namespaces.

params (Object)

Page path params.

query (Object)

Page query params.

License

MIT