BrowserSync SSI Recipe

BrowserSync is my Node.js web browser app development server of choice. This gulpfile is a work in progress to address support for server side includes when using a BrowserSync static server.

gulpfile.js
var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var minimist = require('minimist');

var serverConfig = {
    site: './src',
    directory: false,
    host: 'localhost',
    ssi: '.inc',
    index: 'index.html'
}

// from https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-arguments-from-cli.md
// seems to make sense since gulp itself uses minimist.
var optionsConfig = {
    string: 'host',
    default: { host: process.env.NODE_ENV || serverConfig.host }
};
var options = minimist(process.argv.slice(2), optionsConfig);

// Static server
gulp.task('server', function() {
    browserSync.init({
        server: {
            baseDir: serverConfig.site,
            directory: serverConfig.directory,
            index: serverConfig.index
        }
    });
});

// BrowserSync static server with ssi support
// https://www.npmjs.com/package/ssi#supported-instructions
// ------------------------------------------------
// Known issues:
//   virtual include directives to an absolute URL path
//   do not work as expected. For example, given this file context,
//   http://localhost:3000/subdir/index.html
//     works:
//     <!--#include virtual="../incl/head.inc" -->
//     does NOT work correctly, include directives in this include may not be found:
//     <!--#include virtual="/incl/head.inc" -->
//
//     workaround: use gulp server-proxy task
// ------------------------------------------------
function ssiMiddleware (req, res, next) {

    var fs  = require('fs');
    var path = require('path');
    var ssi = require("ssi");
    var url = require('url');

    var pathname = url.parse(req.originalUrl || req.url).pathname;
    var filename = path.join(serverConfig.site, pathname.substr(-1) === '/' ? pathname + serverConfig.index : pathname);

    if (fs.existsSync(filename)) {

        var matcher = '/**/*' + serverConfig.ssi;
        var parser = new ssi(serverConfig.site, serverConfig.site, matcher);

        var contents = parser.parse(filename, fs.readFileSync(filename, {
            encoding: 'utf8'
        })).contents;

        res.writeHead(200, {
            'Content-Type': 'text/html'
        });
        res.end(contents);

        browserSync.emitter.on('service:running', function(data) {
            if (!snippet) {
                snippet = data.options.get('snippet');
            }
            inject();
        });
    }
    else {
        next();
    }
}
gulp.task('server-ssi', function() {
    browserSync.init({
        server: {
            baseDir: serverConfig.site,
            directory: serverConfig.directory,
            index: serverConfig.index
        },
        middleware: ssiMiddleware
    });
});

// Proxy
// http://www.browsersync.io/docs/options/#option-proxy
// useful if apache needed for .htaccess, ssi, rewrite, etc.
// usage: $ gulp server-proxy --host [host]
// e.g.,  $ gulp server-proxy --host local.dev
gulp.task('server-proxy', function() {
    browserSync.init({
        proxy: options.host
    });
});
Required Modules
$ gulp server-ssi
comments powered by Disqus