4

I'm trying to use the Google Closure Compiler to split my application code based on where it's going to be run (on the server vs the client) via a single variable. In this example, everything that's going to be called on the server is behind an isServerSide var, BUT, the code is being compiled for the client. So I'll set isServerSide to false and let the compiler remove everything that wouldn't be run by the client...

Inside of app.js:

goog.provide('my.app');
my.app.log = function(message) {
  document.write(message);
}
my.app.initClientSide = function() {
  my.app.log('hello client');
}

my.app.initServerSide = function() {
  my.app.log('hello server');
}

if (isServerSide) {
  my.app.log('initing server');
  my.app.initServerSide()
}else my.app.initClientSide();

Inside of externs.js:

/**
 * @define {boolean} is server side?
 */
var isServerSide=false;

Command:

java -jar bin/compiler.jar --js closure-library/closure/goog/base.js --js app.js --externs externs.js --manage_closure_dependencies true --process_closure_primitives true --summary_detail_level 3 --warning_level VERBOSE --compilation_level=ADVANCED_OPTIMIZATIONS --closure_entry_point my.app

Expected output:

document.write("hello client");

Actual output:

isServerSide?(document.write("initing server"),document.write("hello server")):document.write("hello client");

If I manually type isServerSide=false; in app.js then I can get it to compile to this:

isServerSide=false;document.write("hello client");

Which makes me think I'm setting up my externs.js wrong (or I just don't understand what externs should actually be used for).

Any suggestions on how to get this working?

Lite Byte
  • 689
  • 1
  • 6
  • 11
  • Externs are for reserving external names and defining function/type signatures (e.g., [jQuery](http://code.google.com/p/closure-compiler/source/browse/trunk/contrib/externs/jquery-1.3.2.externs.js?r=66)), so I don't think the compiler pays attention to their values. Is it possible to split `app.js` into `app_client.js` and `app_server.js` and have the client/server code always call their respective versions? – hyperslug Nov 09 '11 at 04:04
  • As @hyperslug says, externs are to indicate to the compiler that the variable is defined in an outside script. The compiler **IGNORES ITS VALUE**, assuming that the variable will be set by that outside script. Therefore, you can see that the compiler does not remove *either* of the two branches in the if-statement, because it does not know what the value of that extern variable is. What you need is a `@define` within your script, and then use the `--define` compiler switch to turn it on/off. In this case, you'll get your expected output. – Stephen Chung Nov 09 '11 at 12:35
  • Thanks guys. Just to confirm, what you both said was absolutely correct :) – Lite Byte Nov 13 '11 at 18:41
  • Just to be clear, you need to add /** @define {boolean} */ isServerSide=false; to each and every script that needs the value of isServerSide? – pgraham Mar 07 '14 at 17:58

1 Answers1

6

You specify @define values by setting them in the compiler call directly. Externs serve a different purpose like hyperslug correctly states.

You achieve the expected result by putting the @define definition(from your extern) into app.js and then calling the compiler like this:

java -jar compiler.jar \
--define "isServerSide=false" \
--js closure-library/closure/goog/base.js \
--js app.js \
--manage_closure_dependencies true \
--process_closure_primitives true \
--summary_detail_level 3 \
--warning_level VERBOSE \
--compilation_level=ADVANCED_OPTIMIZATIONS \
--closure_entry_point my.app
Carsten
  • 539
  • 4
  • 10
  • Thanks, that did the trick. In case anyone's wondering, I created a new file (`isServerSide.js`) and I `goog.require` that in to `my.app`. That way I don't clutter up app code w/ define statements, but, I can set the `define` in the compiler cmd... – Lite Byte Nov 13 '11 at 18:43