Nimble Pirate Monitor

    feral

    0.1.5 • Public • Published

    Feral

    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.

    Installation

    npm install feral
    

    feral.create

    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 functionsource.com:

    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) ->
            request.agent().historyAvailable
        }
        {
          legacy: (request) ->
            not request.agent().historyAvailable
        }
      ]
      cache:
        index:
          url: '/:page?'
          targets:
            mobile: true
            legacy: (browser,next) ->
              # do something only when taking a snapshot for a legacy target
              next()
          callback: (browser,next) ->
            # do something when taking a snapshot for any target
            next()
        tag:
          url: '/tags/:tag/:page?'
          targets:
            legacy: true
        post: 
          url: '/post/:slug'
          targets:
            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.

    HTTP API

    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:

    http://localhost:3000/feral/post?slug=slug_name
    

    Will trigger Feral to send a Zombie to:

    http://localhost:3000/post/slug_name
    

    And will cache the result at:

    /cache/legacy/post/slug_name
    

    server.cache

    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"
    

    Request

    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 functionsource.com:

    for path in [
      "/:page?"
      "/tags/:tag/:page?"
      "/post/:slug"
    ]
      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'
      else
        next()

    Keywords

    none

    Install

    npm i feral

    DownloadsWeekly Downloads

    5

    Version

    0.1.5

    License

    none

    Last publish

    Collaborators

    • syntacticx
    • eastridge