In the tutorial mentioned here, the namespace provided by the module is:
goog.provide('tutorial.notepad.Note');
But I am wondering why not this:
goog.provide('tutorial.notepad');
Since, according to the rule mentioned below:
tutorial = tutorial || {};
tutorial.notepad = tutorial.notepad || {};
tutorial.notepad.Note = tutorial.notepad.Note || {};
If we just provided:
goog.provide('tutorial.notepad');
then, we would already have:
tutorial = tutorial || {};
tutorial.notepad = tutorial.notepad || {};
to which we could have added property Note
tutorial.notepad.Note = function() {};
Hence, my question is:
Why not just declare goog.provide('tutorial.notepad')
and then use that to include top level Classes
, instead its recommended to use goog.provide('tutorial.notepad.Note')
for each Class
which feels redundant to me.
Having goog.provide('tutorial.notepad');
creates an entry in the "tree of dependencies" for that namespace, but it does not create an entry for the class tutorial.notepad.Note
. If you manually create tutorial.notepad.Note
as in your example code then you don't activate closure-compiler mechanisms to include the class tutorial.notepad.Note
into the tree of namespace dependencies that closure-compiler uses.
The reason is that goog.provide
is used by closure compiler to set up the tree of dependencies used to figure out what namespaces to load and in what order.
By not using goog.provide
, but mimicking its effects with the code you show, the compiler doesn't learn about the class Note
and how it fits into the tree of namespaces and classes and their dependencies.
There are two ways to run closure-compiler based code: compiled and uncompiled. Each of these build and use the tree of namespace dependencies differently:
UNCOMPILED One of the great things about closure-compiler is that you can run all your code uncompiled. A necessary step in that process is to use depswriter.py
, a Python program which reads all your source files (looking for goog.provide
and goog.require
calls) and produces a file deps.js
. That deps.js
file is the embodiment of the namespace dependency tree. Here is one sample line (of 333) from my project's deps.js
file:
goog.addDependency('../../../src/lab/app/ViewPanner.js',
['myphysicslab.lab.app.ViewPanner'], ['myphysicslab.lab.util.DoubleRect',
'myphysicslab.lab.util.UtilityCore', 'myphysicslab.lab.util.Vector',
'myphysicslab.lab.view.CoordMap', 'myphysicslab.lab.view.LabView'], false);
When I run my code in the uncompiled state, there is a <script>
tag that runs that deps.js
script. Doing that causes an in-memory version of the namespace dependency tree to be created which is accessed by goog.require
at run-time to load whatever other files are needed for that particular class.
References:
https://github.com/google/closure-compiler/wiki/Managing-Dependencies
https://github.com/google/closure-compiler/wiki/Debugging-Uncompiled-Source-Code
Responding to your comment:
Why not just declare
goog.provide('tutorial.notepad')
and then use that to include top levelClasses
, instead its recommended to usegoog.provide('tutorial.notepad.Note')
for eachClass
which feels redundant to me.
I think this gets into issues about the goals and design of closure-compiler. As @Technetium points out, using closure-compiler "is extremely verbose" - it requires annotating your JavaScript code with comments to tell what are the input and output types of every method (function) and the type of each property of an object (class).
(I'm no compiler expert but) I think doing what you suggest would require the compiler to "understand" your code and make guesses about what you regard to be a class, and what you regard to be the constructor and methods or other properties of that class. This would be a much harder problem than what the closure-compiler designers arrived at - especially because JavaScript is such a "loose" language which allows you to do almost anything you can think of.
In practice I find the goog.provide
to be not at all troublesome. I usually am defining only one class per file. What I find much more of a bother is all the goog.require
statements. I can often have 20 or 30 of these in a file and this list of files is often repeated in a similar class. I have 3870 occurrences of goog.require
in my code.
Even this would be OK, but what makes it worse is that closure-compiler has a goog.scope
mechanism which lets you use shorter names, like I can then say Vector
instead of new myphysicslab.lab.util.Vector
. That's very nice, but the problem is that each class you've already goog.require
d you then have to make a short variable within the goog.scope
with a line like this:
var Vector = myphysicslab.lab.util.Vector;
Anyway, my point is: yes, closure-compiler requires a lot more code than raw JavaScript. But the goog.provide
is the least of the issues in that regard.
One more thing: user @Technetium states
The real reason to use it is to run your Google Closure code through the javascript-to-javascript Closure Compiler that removes dead/unused code while minimizing and obfuscating the pieces you do use.
While that's an incredibly useful feature, there is another hugely important reason to use closure-compiler: type checking. If you take the time to add the annotations to your functions, then the compiler will "have your back" by catching errors. This is a big help on any project, but becomes critical when you have multiple developers working on a project and is one of the main reasons that Google developed closure compiler.