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

clumper

v0.0.8

Published

Runtime module bundling, request batching, anticipated dependency loading, and localStorage caching to eliminate extraneous HTTP requests for javascript assets.

Downloads

24

Readme

clumper

Runtime module bundling, request batching, anticipated dependency loading, and localStorage caching to eliminate extraneous HTTP requests for javascript assets.

It works in requirejs compatible AMD projects by injecting requirejs and hijacking its HTTP loading functionality. Requests can then be batched and if a module is cached in memory or localStorage, it can be evaluated immediately without an HTTP request.

Important Note

This module has not been thoroughly tested, does not have unit tests, has not been run in every modern browser, does not fallback gracefully for older browsers, and SHOULD NOT be used (yet) in production. It is currently a proof of concept of a way to make AMD applications much more efficient.

Installing

Install clumper

npm install clumper --save

Or clone the repo and try out the demo:

Install dependencies

npm install

Build JS assets (make sure you have coffee-script >1.7 and gulp installed)

gulp

Run the server on port 3000

npm start

The basic demo will be running at http://localhost:3000/demo.html

Usage

Server

var express = require('express');
var clumper = require('clumper');

// Simple configuration
clumper.config.configure({
  baseDir: __dirname + "/public"
});

app = express();

app.use(app.router);
app.use(express.static(__dirname + "/public");

// Add one route to express
app.get('/scripts.:format?', clumper.request);

app.get('/', function (req, res, next) {
  res.redirect('/demo.html');
});

app.listen(3000);

Client

<!-- Include the base library and initial scripts in one request -->
<script src="/scripts.js?include=true&amp;files=demo/test2,other/module,third/module"></script>
<script>
require(['/demo/test2.js'], function (test2) { test2("Demo!"); });
</script>

Tricks

Code can be inlined to execute synchronously using <script src="/scripts.js?files=... or you can use requirejs's require() and define() statements, which will trigger a batched request to /scripts.json?files=

When testing, you will sometimes need to blow away your localStorage (localStorage.clear()) and your cookies (document.cookie = 'clumper='). You should also clear your cache, heavily, to prevent 304s from the servers or 200s from the browser's cache.

You can embed multiple <script> tags, in case you want the first to be cached and the second to be dynamic to the page you're landing on. Just make sure the first has include=true (prepends clumper client library before modules) and subsequent tags do not.

Requirejs allows you to create aliases (e.g. app/main => /./main.js) which can confuse clumper's dependency anticipation. On the server, you'll need to write your own transformations to turn aliases into real paths to real files.

clumper.config.configure({
  pathFilter: function (path) {
    path = path.replace(/^[\/\.]*app\//, './');
    if (path.charAt(0) != '/') {
      path = "/" + path;
    }
    return path;
  }
});

Clumper includes an optional in-memory cache (larger projects may want to use a more optimal key-value store). All javascript files are read and parsed for requires() and defines() in order to anticipate dependencies and send them to the browser before the browser even knows it wants them. Doing this for every request would suck. At the very least, use the basic in-memory cache:

clumper.config.configure({
  cache: clumper.basicCache
});

Some apps depend on JS assets that don't actually exist on disk. If clumper can't fs-read a path, it will send the browser a 302 redirect to the normal path if it is the only module being requested by a /scripts.js request. If there are multiple modules being requested, or if the browser is expecting a JSON response, the clumper client library will see the failure and fall back to loading the file via XHR.

To prevent an extra roundtrip to the server, include the module in the initial <script> tag. That way, the next request will be to the static file.

URLs and caches are invalidated when the server sees a file has changed. However, the server does not watch your files—it will only see a file has changed if the browser does not have it in localStorage, requests the file, and the server-side caching mechanism doesn't have a response. Then, the next response to any request will invalidate old caches. The process is not perfect, but when aggressively caching and trying to eliminate HTTP requests, it becomes difficult to invalidate all layers of cache.