Skip to content

Commit

Permalink
feat(rewrite-rules): enable live updating of rewrite rules for both s…
Browse files Browse the repository at this point in the history
…tatic server & proxy
  • Loading branch information
shakyShane committed May 24, 2015
2 parents 7354547 + e7d551c commit a4e2bf6
Show file tree
Hide file tree
Showing 15 changed files with 348 additions and 41 deletions.
4 changes: 4 additions & 0 deletions lib/async-tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ module.exports = [
step: "Merging middlewares from core + plugins",
fn: async.mergeMiddlewares
},
{
step: "Setting the rewrite rules middleware for snippet",
fn: async.setRewriteRules
},
{
step: "Starting the Server",
fn: async.startServer
Expand Down
12 changes: 12 additions & 0 deletions lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,18 @@ module.exports = {
}
});
},
setRewriteRules: function (bs, done) {
var snippetUtils = require("./snippet").utils;
done(null, {
instance: {
snippetMw: snippetUtils.getSnippetMiddleware(
bs.options.get("snippet"),
bs.options.get("snippetOptions"),
bs.options.get("rewriteRules")
)
}
});
},
/**
* @param {BrowserSync} bs
* @param {Function} done
Expand Down
39 changes: 39 additions & 0 deletions lib/browser-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,45 @@ BrowserSync.prototype.setMany = function (fn, opts) {
return this.options;
};

/**
* Remove a rewrite rule by id
*/
BrowserSync.prototype.removeRewriteRule = function (id) {
var bs = this;
var mode = bs.options.get("mode");

if (mode === "server") {
bs.snippetMw.opts.rules = bs.snippetMw.opts.rules.filter(fn);
}

if (mode === "proxy") {
bs.proxy.config.rules = bs.proxy.config.rules.filter(fn);
}

function fn (item) {
if (item.id) {
return item.id !== id;
}
return true;
}
};

/**
* Add a new rewrite rule to the stack
* @param {Object} rule
*/
BrowserSync.prototype.addRewriteRule = function (rule) {
var bs = this;

if (bs.options.get("mode") === "server") {
bs.snippetMw.opts.rules.push(rule);
}

if (bs.options.get("mode") === "proxy") {
bs.proxy.config.rules.push(rule);
}
};

/**
* Handle Browser Reloads
*/
Expand Down
29 changes: 14 additions & 15 deletions lib/server/proxy-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var snippetUtils = require("./../snippet").utils;
var _ = require("lodash");
var utils = require("./utils");
var Immutable = require("immutable");

/**
* @param {BrowserSync} bs
Expand All @@ -21,9 +22,9 @@ module.exports = function createProxyServer (bs, scripts) {

var opts = getOptions(bs, scripts);

var app = require("foxy")(options.getIn(["proxy", "target"]), opts);
bs.proxy = require("foxy").create(options.getIn(["proxy", "target"]), opts);

var proxy = utils.getServer(app, bs.options);
var proxy = utils.getServer(bs.proxy.app, bs.options);

/**
* How best to handle websockets going forward?
Expand All @@ -41,19 +42,15 @@ function getOptions (bs, scripts) {

var options = bs.options;

var snippetOptions = options.get("snippetOptions").toJS();
var proxyOptions = options.getIn(["proxy", "proxyOptions"]);
var rewrites = [snippetUtils.getRegex(options.get("snippet"), options.get("snippetOptions"))];

if (bs.options.get("rewriteRules")) {
rewrites = rewrites.concat(bs.options.get("rewriteRules").toJS());
}
var proxyOptions = options.getIn(["proxy", "proxyOptions"]);
var rules = bs.snippetMw;
var cookies = options.getIn(["proxy", "cookies"]);

var out = {
rules: rewrites,
whitelist: snippetOptions.whitelist,
blacklist: snippetOptions.blacklist,
middleware: options.get("middleware").push(getPluginMiddleware(bs, scripts)),
rules: rules.opts.rules,
whitelist: rules.opts.whitelist,
blacklist: rules.opts.blacklist,
middleware: options.get("middleware").toJS().concat(getPluginMiddleware(bs, scripts)),
errHandler: function (err) {
bs.logger.debug("{red:[proxy error]} %s", err.message);
}
Expand All @@ -67,8 +64,10 @@ function getOptions (bs, scripts) {
out.reqHeaders = options.getIn(["proxy", "reqHeaders"]);
}

if (options.getIn(["proxy", "cookies"])) {
out.cookies = options.getIn(["proxy", "cookies"]);
if (!_.isUndefined(cookies)) {
if (Immutable.Map.isMap(cookies)) {
out.cookies = cookies.toJS();
}
}

return out;
Expand Down
10 changes: 2 additions & 8 deletions lib/server/static-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

var connect = require("connect");
var utils = require("./utils.js");
var snippetUtils = require("./../snippet").utils;

/**
* @param {BrowserSync} bs
Expand Down Expand Up @@ -39,14 +38,9 @@ module.exports = function createServer (bs, scripts) {

/**
* Add snippet injection middleware
* This also includes any additional middleware given from the user
*/
app.use(
snippetUtils.getSnippetMiddleware(
options.get("snippet"),
options.get("snippetOptions"),
options.get("rewriteRules")
)
);
app.use(bs.snippetMw.middleware);

/**
* Add user-provided middlewares
Expand Down
10 changes: 8 additions & 2 deletions lib/snippet.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,21 @@ var utils = {
};
},
getSnippetMiddleware: function (snippet, options, rewriteRules) {
return lrSnippet.create(utils.getRules(snippet, options, rewriteRules));
},
getRules: function (snippet, options, rewriteRules) {

var rules = [utils.getRegex(snippet, options)];

if (rewriteRules) {
rules = rules.concat(rewriteRules.toJS());
}
return lrSnippet({

return {
rules: rules,
blacklist: options.get("blacklist").toJS(),
whitelist: options.get("whitelist").toJS()
});
};
},
/**
* @param {String} scripts - the client side JS
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"easy-extender": "^2.3.1",
"eazy-logger": "^2.1.2",
"emitter-steward": "^0.0.1",
"foxy": "^10.1.2",
"foxy": "^11.0.0",
"immutable": "^3.6.4",
"localtunnel": "^1.3.0",
"lodash": "^3.8.0",
Expand All @@ -50,7 +50,7 @@
"pad-left": "^1.0.2",
"portscanner": "^1.0.0",
"query-string": "^2.0.0",
"resp-modifier": "^2.1.0",
"resp-modifier": "^3.1.2",
"serve-index": "^1.6.3",
"serve-static": "^1.9.1",
"socket.io": "^1.3.5",
Expand Down
4 changes: 2 additions & 2 deletions test/specs/e2e/proxy/e2e.proxy.cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("E2E proxy test with custom cookies options passed to foxy", function (
logLevel: "silent"
};

spy = require("sinon").spy(require.cache[foxyPath], "exports");
spy = require("sinon").spy(require.cache[foxyPath].exports, "create");
bs = browserSync.init(config, done).instance;
});

Expand All @@ -44,7 +44,7 @@ describe("E2E proxy test with custom cookies options passed to foxy", function (

it("sets cookie stripDomain: false", function (done) {

assert.isFalse(spy.getCall(0).args[1].cookies.toJS().stripDomain); // check fn passed to foxy
assert.isFalse(spy.getCall(0).args[1].cookies.stripDomain); // check fn passed to foxy

spy.restore();

Expand Down
2 changes: 1 addition & 1 deletion test/specs/e2e/proxy/e2e.proxy.proxy.options.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("E2E proxy test with `proxyOptions`", function () {
logLevel: "silent"
};

spy = require("sinon").spy(require.cache[foxyPath], "exports");
spy = require("sinon").spy(require.cache[foxyPath].exports, "create");
bs = browserSync.init(config, done).instance;
});

Expand Down
2 changes: 1 addition & 1 deletion test/specs/e2e/proxy/e2e.proxy.req.headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe("E2E proxy test with custom req headers", function () {
logLevel: "silent"
};

spy = require("sinon").spy(require.cache[foxyPath], "exports");
spy = require("sinon").spy(require.cache[foxyPath].exports, "create");
bs = browserSync.init(config, done).instance;
});

Expand Down
74 changes: 74 additions & 0 deletions test/specs/e2e/proxy/e2e.proxy.rewrite.rules.add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"use strict";

var browserSync = require("../../../../index");

var connect = require("connect");
var serveStatic = require("serve-static");
var request = require("supertest");
var assert = require("chai").assert;

describe("E2E proxy test with adding rewrite rules dynamically", function () {

var bs, server, options;

before(function (done) {

browserSync.reset();

var app = connect();
app.use(serveStatic("test/fixtures"));
server = app.listen();
var proxytarget = "http://localhost:" + server.address().port;

var config = {
proxy: proxytarget,
logLevel: "silent",
open: false,
rewriteRules: [
{
match: /BrowserSync/g,
fn: function () {
return "BROWSERSYNC";
}
}
]
};

bs = browserSync.init([], config, function (err, bs) {
options = bs.options;
done();
}).instance;
});

after(function () {
bs.cleanup();
server.close();
});

it("can add rules on the fly", function (done) {

request(bs.server)
.get("/index.html")
.set("accept", "text/html")
.expect(200)
.end(function (err, res) {

assert.include(res.text, "BROWSERSYNC");

bs.addRewriteRule({
match: "BROWSERSYNC",
replace: "browsersync"
}, {id: "myrule"});

request(bs.server)
.get("/index.html")
.set("accept", "text/html")
.expect(200)
.end(function (err, res) {
assert.include(res.text, "browsersync");
assert.notInclude(res.text, "BROWSERSYNC");
done();
});
});
});
});
19 changes: 9 additions & 10 deletions test/specs/e2e/proxy/e2e.proxy.rewrite.rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ var assert = require("chai").assert;

describe("E2E proxy test with rewrite rules", function () {

var instance, server, options;
var bs, server, options;

before(function (done) {

browserSync.reset();

var app = connect();
app.use(serveStatic("./test/fixtures"));
app.use(serveStatic("test/fixtures"));
server = app.listen();
var proxytarget = "http://localhost:" + server.address().port;

Expand All @@ -26,33 +26,32 @@ describe("E2E proxy test with rewrite rules", function () {
open: false,
rewriteRules: [
{
match: /Forms/g,
match: /BrowserSync/g,
fn: function () {
return "Shane's forms";
return "BROWSERSYNC";
}
}
]
};

instance = browserSync.init([], config, function (err, bs) {
bs = browserSync.init([], config, function (err, bs) {
options = bs.options;
done();
}).instance;
});

after(function () {
instance.cleanup();
bs.cleanup();
server.close();
});

it("serves files with HTML rewritten", function (done) {

request(instance.server)
it("can add rules on the fly", function (done) {
request(bs.server)
.get("/index.html")
.set("accept", "text/html")
.expect(200)
.end(function (err, res) {
assert.include(res.text, "Shane's forms");
assert.include(res.text, "BROWSERSYNC");
done();
});
});
Expand Down
Loading

0 comments on commit a4e2bf6

Please sign in to comment.