3

I'm developing a networked application between the browser and a server running node.js. I'm sharing a lot of code right now, but when I actually deploy this I'd like the client to only get client specific code. My options right now are:

1.) Implement any browser/node.js differences using inheritance. I've tried this in a few places and I end up with a lot of classes that are very, very basic customizations of their parent often only partially specializing a single function. This is not a style I like very much because it means a lot indirection when you're trying to find out what's actually going on.

2.) Define a constant like IS_BROWSER at global scope and then check it whenever I need to change code paths on the browser vs node.js. Then closure compile all js with advanced optimizations to remove dead code on the browser (setting IS_BROWSER = true). Are there any problems with this approach assuming I do whatever I need to do to get advanced optimizations going in closure compiler?

3.) ?? I'm open to suggestions.

btmorex
  • 476
  • 5
  • 16
  • What JavaScript library are you using? Quite a few JavaScript libraries will abstract away the differences between browsers and node/rhino for you. Using a global constant as per your #2 also works well, but I believe the best is to use a library that abstracts all these. – Stephen Chung Nov 07 '11 at 15:54
  • many of the diferences are actually application logic differences so they won't be abstracted away by a library. – btmorex Nov 07 '11 at 22:35
  • I'm curious, what logic differences will there be for a browser environment vs. a head-less server environment? AFAIK, they both support most of the same features in the environment. If there are concerns over CPU usage, threading etc., then I think using the "has.js" library to do environmental feature detection might be the most flexible way to go for the future. – Stephen Chung Nov 08 '11 at 11:59
  • @StephenChung: Could you give an example of "libraries will abstract away the differences between browsers and node/rhino for you"? – bukzor Nov 25 '11 at 18:17
  • @bukzor, for example Dojo supports most browsers, rhino and node (though I am not sure whether node support is officially out yet). – Stephen Chung Nov 26 '11 at 10:41
  • @btmorex Which better describes your situation: you have many functions which branch depending on whether you are running on a server or in a browser; or you have independent server and browser programs and they both depend on some platform-independent code? – ellisbben Nov 28 '11 at 05:57

1 Answers1

1

If you use advanced compilation, any unused code should be removed; if you use the compiler's export system correctly, any server-side code that your client code does not call will not be in the compiled version of the client code.

You could write all of your code in one big blob then, for your client, add one file with contents like

goog.require('my.client.app');
goog.exportSymbol('my.app.entryPoint', my.client.app.entryPoint);

the compiled code will not include anything that is not in the call tree of my.client.app.entryPoint. Likewise, if your compilation only exports a server entry point, client code will be excluded.

The above style is for writing your script to provide some function which will then get called by an inline script; to make the whole thing into a single script you could do something much simpler:

goog.require('my.client.app');
my.client.app.entryPoint();

To verify that you are not getting a lot of dead code in your compilation output, you could play around with something like this: ScriptCover

ellisbben
  • 6,352
  • 26
  • 43
  • This question is about node.js and closure-compiler. I don't see any mention of closure-library(cl), and cl will not work under node.js without a bunch of help from a third(fourth?)-party library, none of which are currently production quality. – bukzor Nov 25 '11 at 18:19
  • Good point. I wrote the example code in Closure library style, but that is entirely unnecessary. – ellisbben Nov 28 '11 at 05:41
  • When you say "it's unecessary" that implies that there's another way. Is there? – bukzor Nov 28 '11 at 06:29
  • The compiler treats `goog.require` and `goog.exportSymbol` in special ways, but any code that you would add through `require` could just be prepended to what you want to compile and `exportSymbol` can be replaced with `this["varName"] = varValue` (`this` hopefully defaulting to global or module scope) or `window["varName"] = varValue` for in the browser. If you access a property by the string of its name, the compiler will not rename that access. To guarantee that a field accessed in the .fieldName style is accessible with that name, you do have to use `exportSymbol` – ellisbben Nov 28 '11 at 19:22
  • That said, I would be surprised if base.js (which defines `require` and `exportSymbol`) couldn't work with node.js; they at least define and use a "am I in a browser?" function and they don't touch, e.g., DOM functionality. – ellisbben Nov 28 '11 at 19:26
  • ellisbben: I have another, related question about node.js + closure-compiler. The expert conclusion was that it's a dumb idea (sad face): http://stackoverflow.com/questions/8287597 – bukzor Nov 29 '11 at 19:12