node package manager
Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »



Sticky is a simple connect middleware to concatenate, minify and serve client-side javascript. It aims to be a bit more javascript centric and quicker to setup than similar projects like connect-assets and connect-assetmanager. It also provides a jade helper function to render it's namespaces.



via npm (recommended)

npm install connect-sticky --production

via git

git clone connect-sticky
cd connect-sticky
npm install --production

sticky.middleware([options], [namespace])

Returns the connect middleware function.


var sticky = require('connect-sticky');
connectapp.use(sticky.middleware({ root: '/src', path: '/js'}, {
    namespaceOne: {
        code: [ 'fileA.js', 'fileB.js' ]


Either an object or a function returning an object.

  • root: The filesystem path which contains the original javascript files, all files specified in the namespace definition are expected to be relative to this.
  • path: The web path at which to serve the original or generated javascript files.
  • concat: If true namespace components are rendered and served as a single file, generates individual script tags otherwise. Defaults to true.
  • minify: If true minifies the generated javascript via uglify-js. Defaults to true.
  • guard: If true and concat is used, wraps each generated javascript namespace with an IIFE. Defaults to true.
  • jade: Set to true to provide the jade helper function in response objects. Defaults to true.
  • silent: Suppress log messages. Defaults to false.
  • prefix: String to prefix all generated javascript filenames with. Defaults to _.
  • serve: When not using concat, sticky by default generates individual script tags for your original javascript files and serves these at path. This behaviour can be disabled by setting serve to false.
  • oncomplete: Callback called when all namespaces have been compiled.


Specify an object to define all namespaces. Can be an object, a function returning an object or a filename pointing to a JSON file.

Options per namespace:
  • concat: Overrides global option.
  • minify: Overrides global option.
  • guard: Overrides global option.
  • async: If true includes the HTML5 async attribte for all script tags generated by this namespace. Defaults to false.
  • code: Either one or an array containing the following:
    • filename: javascript file to include, relative to root.
    • inline: String containing javascript code.
    • namespace: String to reference another namespace.
    • function: A function that returns a string containing javascript code. The function receives the namespace name as it's first argument.
    namespaceOne: {
        concat: false,
        code: [
            'function mySillyFunction(){ return 42; }'
    namespaceTwo: {
        guard: false,
        code: [
    namespaceThree: {
        code: 'fileD.js'
    namespaceFour: {
        async: true,
        code: [
            function(namespacename){ return 'var ' + namespacename + ' = "awesome";'; }

Rendering with jade

If jade is set in the global options, each response object is provided with a jade helper function to render one or more namespaces.

!=stickyRender('namespaceOne', 'namespaceTwo', ...)

Note: If you specify an unknown namespace name, sticky will render a warning in form of a html comment.


Assuming path is set to /js and prefix to _, calling !=stickyRender('namespaceOne') with concat enabled will render to this:

    <script type="text/javascript" src="/js/_namespaceOne.js"></script> 

... with concat disabled:

    <script type="text/javascript" src="/js/fileA.js"></script> 
    <script type="text/javascript" src="/js/fileB.js"></script> 
    <script type="text/javascript">
        function mySillyFunction(){ return 42; }

Having guard enabled, the generated javascript for /js/_namespaceOne.js would look like this:

        /*contents of fileA.js*/
        /*contents of fileB.js*/
        function mySillyFunction(){ return 42; }


  • Pull requests are welcome
  • Report issues here
  • Contact the author