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

assets-middleware

v0.0.3

Published

Abstract asset middleware for compilation, concatenation, and post-processing.

Downloads

4

Readme

assets-middleware

Abstract Express/Connect middleware for dealing with static assets like JS and CSS

Higher-level middleware (like LESS, Stylus, Coffeescript compilation, minifying, etc) or combinations of them can be built on top of this.

Installation

npm install assets-middleware

Usage

Here is an example that takes .coffee and .js files from the ./public directory and the ./lib/jquery.js file, calls compile on any CoffeeScript files, and then calls minify on the concatenated content.

var app = require('express')();
var assets = require('assets-middleware');

app.get('/my-scripts.js', assets({
    src : [ './public', './lib/jquery.js' ],
    pipeline : {
        prefilter : [ 'coffee', 'js' ],
        // don't include CSS files. You could use [ 'less', 'css' ] for them

        // compile any .coffee files
        mapContent : function(content, file, next) {
            file.extname === '.coffee' ?
                compile(content, next) :
                next(null, content);
        },

        // minify the batch
        postReduceContent : function (concatenatedContent, next) {
            minify(concatenatedContent, next);
        }
    }
}));

app.listen(8080);

Options

| Option | Default | Allowed values | Description |------------|------------------|----------------|-------------| | dest | identitySync | path, function(path) : path | The file path to write the resulting asset to. | | src | './public' | path, [path], function(path, callback) | The file paths and directories to read from. The passed in path is the destination file | | prefix | '/' | string | A prefix to remove from the URL path when converting it to a local file path. This is called before dest | | encoding | 'utf8' | string | The encoding to use for reading and writing files. | | force | 'ifnewer' | true, false, 'ifnewer' | Where to force regeneration on every request (true), if the last generated file is older than any source file ('ifnewer') or only if the file doesn't exist (false) | | logger | null | function(string, level) | An optional logger function that is called with a string output and string log level ('error', 'warn', 'info', 'debug') | | pipeline | streamy pipeline | Object | An object where each key is a step and its value is the function to execute. See the pipeline tables below |

Pipeline - Stringy

| Step | Default | Allowed values | Description | |---------------------|-------------|--------------------------------------------------------|-------------| | prefilter | asyncTrue | extension, [extension], function(file, callback) | This step offers a way to filter out files that shouldn't be included before any heavy processing is done. It can be a function, or use the extension-filtering shorthand. | | mapContent | identity | function(content, file, callback) | This step is where you transform the input content into output content. | | filter | asyncTrue | function(file, callback) | This step offers you a last ditch spot to exclude files from the output. You will rarely need to specify this step. | | postReduceContent | identity | function(content, callback) | This step is where you can act on the combined content of all your source files. |

Pipeline - Streamy

| Step | Default | Allowed values | Description | |---------------------|-------------|--------------------------------------------------------|-------------| | prefilter | asyncTrue | extension, [extension], function(file, callback) | This step offers a way to filter out files that shouldn't be included before any heavy processing is done. It can be a function, or use the extension-filtering shorthand. | | map | identity | function(content, file, callback) | This step is where you transform the input content into output content. | | filter | asyncTrue | function(file, callback) | This step offers you a last ditch spot to exclude files from the output. You will rarely need to specify this step. | | reduceSeed | createWritableStream | function(path, callback) | Generate a Writable stream from the output file path. | | reduce | pipe | function(writable, readable, callback) | Pipe your Readable stream into the Writable stream. | | postReduce | identity | function(content, callback) | This step is where you can act on the combined content of all your source files. |

Standard parameter shapes

| Parameter | Shape | |-------------|----------| | extension | string | | path | string | | content | string | | file | { path : string, stat : stat, extname : string, mapped : ?* } | | seed | Writable, { path : string, content : string } | | callback | function(err, result) |

  • Note that "mapped" is only present in a file after the map step. In the stringy pipeline, it's a content string. In the streamy pipeline, it's a Readable stream.

Tutorial

We're going to set up a basic compile + minify filter. Step one is to pick our source directories and files:

app.get('/my-scripts.js', assets({
    src : [ './public', './lib/jquery.js' ]
}));

We can choose a destination too. The default is to use the URL path, relative to the current working directory.

app.get('/my-scripts.js', assets({
    src : [ './public', './lib/jquery.js' ],
    dest : './new-location.js'
}));

The above example would take all the files in ./public and the single ./lib/jquery.js file and concatenate them into ./my-location.js. This is of somewhat questionable value since CSS and JS files that exist under ./public would all be included in the same output.

So let's work with this a bit more. assets-middleware gives you an optional pipeline for transforming your files. You can prefilter files based on the path, map to transform the content, filter them again if necessary, and reduce to combine them.

So let's filter out just the JS and skip CSS files. We can do this in our "prefilter" step:

app.get('/my-scripts.js', assets({
    pipeline : { prefilter : 'js' },
    src : [ './public', './lib/jquery.js' ], // specify the source files
}));

But maybe you like CoffeeScript. Let's include those too, and compile them in the "mapContent" step of the pipeline:

var path = require('path');
var fs = require('fs');
var coffee = require('coffee-script');
function compile(code, next) {
    try {
        next(null, coffee.compile(code));
    } catch(e) { // compile error
        next(e);
    }
}

app.get('/my-scripts.js', assets({
    pipeline : {
        prefilter : [ 'coffee', 'js' ],
        mapContent : function(content, file, next) {
            file.extname === '.coffee' ?
                compile(content, next) :
                next(null, content);
        }
    },
    src : [ './public', './lib/jquery.js' ]
}));

And you want it minified? Well then we should do that in the postReduceContent step:

var uglify = require('uglify-js');
function minify(code, next) {
    try {
        next(null, uglify.minify(code, { fromString : true }).code);
    } catch (e) {
        next(e);
    }
}

app.get('/my-scripts.js', assets({
    pipeline : {
        prefilter : [ 'coffee', 'js' ],
        mapContent : function(content, file, next) {
            file.extname === '.coffee' ?
                compile(content, next) :
                next(null, content);
        },
        postReduceContent : function (concatenatedContent, next) {
            minify(concatenatedContent, next);
        }
    },
    src : [ './public', './lib/jquery.js' ]
}));

And you're done!

Changelog

| Version | Changes | |---------|---------| | 0.0.1 | Initial npm publish |