namespace generation in compiled mode

78 views
Skip to first unread message

Fredrik

unread,
Mar 24, 2010, 7:02:32 PM3/24/10
to Closure Compiler Discuss
Hi,

I'm investigating using the Closure Compiler & library in an existing
web application.
This has some constraints in that not all scripts can/will (currently)
be managed by Closure, some code is injected as web-services for
example.

When using the module handling goog.provide/require in uncompiled mode
everything works fine. But, in compiled mode I get clashes with
existing code that shares namespaces.

This boils down to that goog.provide is "polite" in that it doesn't
replace existing namespaces. Compiled code on the other hand injects
explicit namespaces that doesn't do any checks. This results in that
uncompiled and compiled code aren't interchangeable with respect to
other code outside the control of Closure.

Example:
"goog.provide('Foo.Bar');" ---> compilation translates this to: "var
Foo = {}; Foo.Bar = {};"
Wouldn't it be possible to use this common pattern instead?
"if (typeof(Foo) == 'undefined') Foo = {}; Foo.Bar = Foo.Bar || {};"
add an "--enable_soft_namespaces" flag perhaps? :)
----

Essentially, I would like to be able to use compiled code but with
goog.provide style namespaces. Is this possible somehow?

// Fredrik

John Lenz

unread,
Mar 24, 2010, 8:34:56 PM3/24/10
to closure-comp...@googlegroups.com
I assume you are using simple mode? You can do this manually, by explicitly providing a definition for the namespace:

  goog.provide('Foo');
  goog.provide('Foo.Bar');

  var Foo = Foo || {};
  Foo.Bar = Foo.Bar || {};

The compiler will only provide a definition if one does not already exist.

To unsubscribe from this group, send email to closure-compiler-discuss+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.

bolinfest

unread,
Mar 24, 2010, 8:40:03 PM3/24/10
to Closure Compiler Discuss
If you're willing to mess with the Closure Compiler source code, I
believe you want to disable this option:

options.closurePass = false;

What compilation level are you using right now?

Also, a simpler workaround might be:

var myRequire = goog.require;

and then use myRequire instead of goog.require in your code, though
I'm not sure if that will work. This is based on the assumption that
the Compiler only rewrites calls to goog.require, but not aliased
ones.

Fredrik

unread,
Mar 25, 2010, 12:22:14 PM3/25/10
to Closure Compiler Discuss
Hi,
I use the simple compilation level (as said, my code needs to
interoperate with many separate modules like plugins for example,
basically ruling out advanced mode).

Is that option same as the "process_closure_primitives" CLI flag? In
that case I've already tried it (that's when I found this by the way;
http://code.google.com/p/closure-compiler/issues/detail?id=130).
Perhaps that's an option, but then I would need to add duplicate code
to describe namespaces everywhere? Similarly, using an aliased
goog.provide would mean both closurebuilder and depswriter (and my own
tool) would need to be patched. I'll try to do some more tests with
this though.

To clarify my scenario:
----------
This is the setup I was trying to achieve:
* Debug mode:
load base.js + deps file(s) that contains "all" available script
files. (this works fine)

* Compiled mode:
load base.js + deps files(s) that points to compiled modules. (here's
were I currently fail)
---------
Application code will then _always_ use goog.require calls. Debug vs
compiled mode is handled by simply switching the deps file.

I thought the above setup would be a simple and flexible way to get
most of the Closure benefits. Only thing that is "sacrificed" is
advanced compilation.
Does the above look reasonable? Or should I go with some other setup?

---
The ideal features needed to achieve this setup would be:
- Compiler should be able to output compiled code that keeps the
original goog.provide/require calls.
- When compiling modules the compiler should move all provide/require
tags to the top of the file so that
they can be parsed using depswriter (depswriter currently chokes and
outputs syntax errors on require/provides that are spread inside a
file).

I even tried using the "module_wrapper" flag to re-inject goog.provide/
requires at the top of the compiled module-files. If the compiler had
used "soft"
namespace merging that would have worked.

Digging in the compiler source.. would it perhaps be possible to
modify makeAssignmentExprNode and makeVarDeclNode in
ProcessClosurePrimitives.java to output code that would do namespace
merging? (Or am I getting waay out here?...)

Regards
// Fredrik

John Lenz

unread,
Mar 25, 2010, 12:43:03 PM3/25/10
to Fredrik, closure-compiler



On Thu, Mar 25, 2010 at 8:09 AM, Fredrik <fblom...@gmail.com> wrote:
Your suggestion looked plausible, but doesn't seem to work for me.
When compiling in simple mode the compiler inserts same "hard"
namespace code anyway.

I don't see this.  Ignoring the code from base.js, this is what I see:

var Foo=Foo||{};Foo.Bar=Foo.Bar||{};

Using http://closure-compiler.appspot.com/  this is what I did:

// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
// @output_file_name default.js
// @use_closure_library true
// @warning_level verbose
// ==/ClosureCompiler==



  goog.provide('Foo');
  goog.provide('Foo.Bar');

  var Foo = Foo || {};
  Foo.Bar = Foo.Bar || {};
 
Also, if using warning_level=VERBOSE, that pattern won't compile at
all since it is interpreted as duplicate variable declarations (Foo).


Where is the first definition of Foo?
 

Fredrik

unread,
Mar 25, 2010, 1:46:26 PM3/25/10
to Closure Compiler Discuss
Aha, I never provided base 'Foo' only the compound 'Foo.Bar'.
--- like so:
goog.provide('Foo.Bar');

var Foo = Foo || {};
Foo.Bar = Foo.Bar || {};

-----
(i.e the above will fail in when compiled in VERBOSE mode)

I figured a provide('Foo.Bar'); made provide('Foo') redundant (if I
didn't wan't to use it as a bundle module).
Logically I guess it is, but in this special case after compilation I
can see how it "fixes" things.

Short term this pattern might actually make my project compilable. I
need to add duplicate namespace declarations everywhere.
(note: can't seem to wrap it in a separate namespace generator
function if not using advanced mode compilation though. Simple mode
will not analyze the call and would still insert the "hard"
namespace).

Thanks!
// Fredrik

On Mar 25, 5:43 pm, John Lenz <concavel...@gmail.com> wrote:


> On Thu, Mar 25, 2010 at 8:09 AM, Fredrik <fblomqv...@gmail.com> wrote:
> > Your suggestion looked plausible, but doesn't seem to work for me.
> > When compiling in simple mode the compiler inserts same "hard"
> > namespace code anyway.
>
> I don't see this.  Ignoring the code from base.js, this is what I see:
>
> var Foo=Foo||{};Foo.Bar=Foo.Bar||{};
>

> Usinghttp://closure-compiler.appspot.com/ this is what I did:

John Lenz

unread,
Mar 25, 2010, 2:11:57 PM3/25/10
to closure-comp...@googlegroups.com
I agree this is not the most elegant, but there are limits to what the compiler can do automatically.  For instance:

Specifically, if Foo namespace is a Function object, instead of an anonymous object:

// File 1
var Foo = Foo || {};

// File 2
var Foo = Foo || function () {
   // the Foo object constructor code.
}

new Foo() //  <-- This fails if Foo was defined in File 1



To unsubscribe from this group, send email to closure-compiler-discuss+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.

Fredrik

unread,
Mar 26, 2010, 3:34:42 PM3/26/10
to Closure Compiler Discuss
FYI, my setup seems to work as I outlined above with the following
changes:
- use dual namespace namespace decl. (i.e both goog.provide and manual
vars)
- re-injecting of provides/requires after module compilation
- disabling the throw "namespace already declared" in goog.provide
(hackish..)

A bit cumbersome yes, but doable.

I'd be interested to hear about other suggestions for cases like this,
this kind of
requirements and constraints must be quite common I'd say(?).

During development of this I also wrote a generic "modulebuilder" tool
that figures out module-module
dependencies to enable easy module compilation.
Syntax example:
"pyhton modulebuilder.py --root code/myscripts --module
module1:ns1,ns2 --module module2:ns3 --keep_dep_tags true --
list_unused_files true --compiler_flags ...."
("keep_dep_tags" does the special provide/require re-injection I
needed)
If anyone is interested, I'm considering making it OS. Perhaps it
could even fit in the Closure toolbox? (It uses closurebuilder's
depstree extraction for example).

// Fredrik

> > > Usinghttp://closure-compiler.appspot.com/this is what I did:

John Lenz

unread,
Mar 26, 2010, 7:19:12 PM3/26/10
to closure-comp...@googlegroups.com
I thought about this some more and I think you are correct.  The behavior for goog.provide should be different in simple mode.

It should either define it in a friendly way:

goog.provide('foo.Bar');
foo.Bar = function () {...};

should translate to:

var foo = foo || {};
foo.bar = function () {...};

Or it should be left alone entirely.  Can you file an issue for this: http://code.google.com/p/closure-compiler/issues/



To unsubscribe from this group, send email to closure-compiler-discuss+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.

Fredrik

unread,
Mar 30, 2010, 7:09:21 PM3/30/10
to Closure Compiler Discuss
Done: http://code.google.com/p/closure-compiler/issues/detail?id=136

Thanks for your support
// Fredrik

> > > > > Usinghttp://closure-compiler.appspot.com/thisis what I did:

> > To unsubscribe from this group, send email to closure-compiler-discuss+

Reply all
Reply to author
Forward
0 new messages