-->

Closure: --namespace Foo does not include Foo.Bar,

2019-08-19 06:22发布

问题:

I have a rather big library with a significant set of APIs that I need to expose. In fact, I'd like to expose the whole thing. There is a lot of namespacing going on, like:

FooLibrary.Bar FooLibrary.Qux.Rumps FooLibrary.Qux.Scrooge ..

Basically, what I would like to do is make sure that the user can access that whole namespace. I have had a whole bunch of trouble with this, and I'm totally new to closure, so I thought I'd ask for some input.

First, I need closurebuilder.py to send the full list of files to the closure compiler. This doesn't seem supported: --namespace Foo does not include Foo.Bar. --input only allows a single file, not a directory. Nor can I simply send my list of files to the closure compiler directly, because my code is also requiring things like "goog.assers", so I do need the resolver.

In fact, the only solution I can see is having a FooLibrary.ExposeAPI JS file that @require's everything. Surely that can't be right?

This is my main issue.

However, later the closure compiler, with ADVANCED_OPTIMIZATIONS on, will optimize all these names away. Now I can fix that by adding "@export" all over the place, which I am not happy about, but should work. I suppose it would also be valid to use an extern here. Or I could simply disable advanced optimizations.

What I can't do, apparently, is say "export FooLibrary.*". Wouldn't that make sense?

Finally, for working in source mode, I need to do goog.require() for every namespace I am using. This is merely an inconvenience, though I am mentioning because it sort of related to my trouble above. I would prefer to be able to do:

goog.requireRecursively('FooLibrary')

in order to pull all the child namespaces as well; thus, recreating with a single command the environment that I have when I am using the compiled version of my library.

I feel like I am possibly misunderstanding some things, or how Closure is supposed to be used. I'd be interested in looking at other Closure-based libraries to see how they solve this.

回答1:

You are discovering that Closure-compiler is built more for the end consumer and not as much for the library author.

If you are exporting basically everything, then you would be better off with SIMPLE_OPTIMIZATIONS. I would still highly encourage you to maintain compatibility of your library with ADVANCED_OPTIMIZATIONS so that users can compile the library source with their project.

First, I need closurebuilder.py to send the full list of files to the closure compiler. ...

In fact, the only solution I can see is having a FooLibrary.ExposeAPI JS file that @require's everything. Surely that can't be right?

You would need to specify an --root of your source folder and specify the namespaces of the leaf nodes of your file dependency tree. You may have better luck with the now deprecated CalcDeps.py script. I still use it for some projects.

What I can't do, apparently, is say "export FooLibrary.*". Wouldn't that make sense?

You can't do that because it only makes sense based on the final usage. You as the library writer wish to export everything, but perhaps a consumer of your library wishes to include the source (uncompiled) version and have more dead code elimination. Library authors are stuck in a kind of middle ground between SIMPLE and ADVANCED optimization levels.

What I have done for this case is maintain a separate exports file for my namespace that exports everything. When compiling a standalone version of my library for distribution, the exports file is included in the compilation. However I can still include the library source (without the exports) into a project and get full dead code elimination. The work/payoff balance of this though must be weighed against just using SIMPLE_OPTIMIZATIONS for the standalone library.

My GeolocationMarker library has an example of this strategy.