Nimble Pirate Monitor


    0.1.5 • Public • Published


    Express + Zombie caching content server.

    Store static HTML snapshots of JavaScript applications, conditionally serving those static snapshots to clients that are not capable of running the application.


    npm install feral


    Create a new Feral + Express server. Create takes a single object with the following keys as it's only argument:

    • port - Number
    • public - String, path to serve static files from
    • cacheDir - String, path to write
    • targets - Object, name: callback pairs. callback will receive an http.ServerRequest object and must return boolean.
    • cache - Object, name: Object option pairs. options can contain:
      • url - String, route. May be relative or a fully qualified URL.
      • targets - Object, name: true || callback pairs. If specifying a callback it will receive a zombie.Browser instance and a continuation callback. The continuation callback must be called.
      • callback - Function. Will receive a zombie.Browser instance and a continuation callback. The continuation callback must be called.
      • debug - Boolean
      • runScripts - Boolean
      • userAgent - String

    The following is used to serve

    feral = require 'feral'
    server = feral.create
      port: 3000
      public: __dirname + '/public/'
      cacheDir: __dirname + '/cache/'
      targets: [
          mobile: (request) ->
            request.agent().name in ['ios','android']
          html5: (request) ->
          legacy: (request) ->
            not request.agent().historyAvailable
          url: '/:page?'
            mobile: true
            legacy: (browser,next) ->
              # do something only when taking a snapshot for a legacy target
          callback: (browser,next) ->
            # do something when taking a snapshot for any target
          url: '/tags/:tag/:page?'
            legacy: true
          url: '/post/:slug'
            legacy: true

    To make an existing Express server Feral, pass it as the first argument (you must still pass the port number in the options object):

    server = express.createServer()
    # server setup logic here
    feral.create server, options

    Targets & Cache Middleware

    Feral installs a middleware method which is similar to express.static, but will conditionally serve files based on the target. The following files would be served when a request for "/" is initiated:

    mobile: /cache/mobile/index.html
    legacy: /cache/legacy/index.html
    html5: (no match, let other middleware respond)

    Like middleware, order matters when defining targets and the first target callback that returns true will determine which file will be served. In our example above a browser may be both HTML5 capable and a mobile device, but mobile was specified first, so the request will be treated as a "mobile" target.


    For each cache name specified Feral exposes a corresponding HTTP GET method. Visiting this URL will trigger Feral to send a Zombie to cache the page for each target. Given the example shown in feral.create visiting:


    Will trigger Feral to send a Zombie to:


    And will cache the result at:



    A wrapper for the HTTP API

    server.cache post: slug: 'slug_name', -> # on complete callback

    Can also be used in cache definition callbacks to have one cache trigger another (i.e. when caching a blog post also cache the front page of the blog).

    Cache Sweeping

    Like Rails, sweeping the cache is an application specific task that is up to you to implement. Two convenience methods are provided to assist.

    server.urlForCache (cache_name,params) - Returns the url that would be visited by a Zombie.

    server.urlForCache("post",slug: "post_name") == "/post/post_name"

    server.pathForCache (cache_name,target_name,params) - Returns the path in the filesystem where the cache would be stored.

    server.pathForCache("post","mobile",slug: "post_name") == "/cache/mobile/post/post_name"


    Feral adds an agent method to every http.ServerRequest request object which is useful in creating targets. The agent method returns an object with the following attributes:

    • name - String, name of the user agent, will be one of the following:
      • chrome
      • firefox
      • safari
      • ios
      • android
      • opera
      • ie
      • bing
      • google
      • ask
      • yahoo
      • unknown
    • version - String, user agent version.
    • historyAvailable - Boolean, does the agent support the HTML5 history API?
    • robot - Boolean, is the agent a robot?
    • targets - Object, containing target_name: boolean pairs for each of the specified targets.

    Browser Object

    Every browser object in Feral is a zombie.Browser object with the following additional methods:

    • addScript (src) - Add a script tag to the browser.window's head.
    • removeScript (src = false) - Remove a script tag from the browser.window's head. Not specifying a src will remove all.

    Single File Targets

    Serving a single file to a given target (i.e. an HTML page that will load a JS application) for all requests can be accomplished with an Express middleware method. The following code is used in conjunction with Feral on

    for path in [
      server.get path, (request,response,next) ->
        return next() if not request.agent().targets.html5
        response.sendfile __dirname + '/cache/html5/index.html'

    Protecting Feral

    By default the Feral HTTP API is publicly accessible. It can be protected with an Express middleware method:

    server = feral.create ...
    server.get /^\/feral\/.*/, (request,response,next) ->
      if not request.query.admin?
        next new Error 'Not admin'




    npm i feral

    DownloadsWeekly Downloads






    Last publish


    • syntacticx
    • eastridge