diegoles / closure-library

Automatically exported from code.google.com/p/closure-library
0 stars 0 forks source link

Fix documentation regarding use of goog/deps.js in compiled mode #565

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
To improve newcomers experience with Closure Compiler, add to documentation
that it is necessary to include the file closure-library/closure/goog/deps.js in
the compilation.

When I started using Closure Compiler in December 2012 I encountered the same
issue as 401 (http://code.google.com/p/closure-library/issues/detail?id=401)
(and issue 493 is similar) when I got errors from doing
    goog.require('goog.events');
which I worked around by adding statements like 
    goog.require('goog.debug.ErrorHandler');
    goog.require('goog.events.EventHandler');
    goog.require('goog.events.EventTarget');
and later I was even editing those files in Closure Library to try to fix what 
I 
thought was a circular dependency in Closure Library.

There is a FAQ in the Closure Library wiki at
http://code.google.com/p/closure-library/wiki/FrequentlyAskedQuestions#When_I_co
mpile_with_type-checking_on,_I_get_warnings_about_unkno
that explains this issue; my suggestion here is that the information should be
included in the documentation more widely. This FAQ is very obscure to a
newcomer and will seem to not be relevant and probably go unnoticed.

The fix described in the FAQ is to include the goog/deps.js file in the
compilation.

My understanding before yesterday was that the deps.js file is ONLY used when
running in "uncompiled mode" directly from the source files. I think this was a
reasonable conclusion. Below are some of the references that lead a reader to
this incorrect interpretation.

From the Micheal Bolin book on Closure Compiler: about calcdeps.py:
    The output from deps mode is often used to load local files for testing and
    development,

Bolin book about goog.require(namespace) 
    Because COMPILED was set to its default value, false, base.js ran the
    following code when it was evaluated:
        document.write('<script type="text/javascript" src="deps.js"></script>'); 
    Note that deps.js lives in the same directory as base.js and that it
    contains many calls to goog.addDependency() (which is explained in the next
    section). These calls load Closure’s dependency graph as created by
    calcdeps.py. When COMPILED is false, goog.require() looks at this dependency
    graph to determine all of goog.dom’s dependencies. For each dependency it
    finds, it adds another <script> tag pointing to the file that contains the
    corresponding call to goog.provide().

Bolin book about goog.addDependency:
    In the compiled case, there is no need for the dependency graph to be
    constructed on the client, so goog.addDependency() and the global constants
    it depends on are defined in such a way that they will be stripped from the
    output when COMPILED is true. By comparison, uncompiled Closure code relies
    on the information from goog.addDependency() to determine which additional
    JavaScript files to load.

from https://developers.google.com/closure/library/docs/depswriter 
    Using ClosureBuilder briefly covered Closure Library's debug loader.
    When you use the uncompiled source, requiring a namespace with
    goog.require() fetches that namespace by appending an additional <script>
    tag whose src attribute is a URL to the script that provides that namespace.

    But how does Closure Library know which files provide which namespaces?
    Included in Closure Library is a default dependency file named deps.js. This
    file contains one line for every JavaScript file in the library, each
    specifying the file location (relative to base.js), the namespaces it
    provides, and the namespace it requires.

    In debug mode, a goog.require() statement looks to see if the require
    namespace was specified and, if so, fetch the files that provide it and all
    of its dependencies.

NOTE: that should read "In uncompiled mode" not "In debug mode".

from https://developers.google.com/closure/library/docs/closurebuilder 
    The closurebuilder.py tool, located in closure/bin/build, is a tool to help
    build compiled JavaScript files. It scans your files and the Closure Library
    files and can calculate orderings of script files in dependency order. It
    can output either the scripts' filenames or their contents in dependency
    order, or can pass the files along to the Closure Compiler to produce a
    compiled version.

    Each --root flag tells ClosureBuilder to scan that directory for .js files.
    Each file is scanned for goog.provide and goog.require statements, which
    indicate that the file provides a namespace or requires a namespace provided
    in another file.

    Scanning all files allows ClosureBuilder to build an in-memory dependency
    tree of all namespaces. The --namespace flag tells ClosureBuilder to start
    with the myproject.start namespace in that tree and get all of its
    dependencies. By default, it outputs the results as a list of files, in
    dependency order. For every file in the list, every required namespace is
    provided by another file that appears earlier in the list.

A reader's reasonable interpretation of the above: "oh, then closurebuilder
doesn't need deps.js, because closurebuilder is figuring out all the
dependencies".

Suggested actions:
=================
Update the pages about depswriter and closurebuilder to include more accurate 
information about how deps.js is needed during compilation.

1. On https://developers.google.com/closure/library/docs/closurebuilder add the
suggested flag from the FAQ to the suggested usage of closurebuilder, this is -f
"--js closure-library/closure/goog/deps.js".  More clear would be to use the 
long 
option name:
     --compiler_flags="--js=closure-library/closure/goog/deps.js"

2. On https://developers.google.com/closure/compiler/docs/gettingstarted_app add
the compiler option --js closure-library/closure/goog/deps.js in the Hello World
example Although this example doesn't include anything from closure-library, so
perhaps this doesn't make sense. Perhaps instead add a note to this page saying
that "if you use closure library, then you will also need to use the compiler
option --js closure-library/closure/goog/deps.js", or refer to the FAQ.

3. Develop a second "Hello World" example that includes a minimal example of
using closure-library, and therefore shows using the --js
closure-library/closure/goog/deps.js option.

4. On https://developers.google.com/closure/compiler/docs/error-ref add to the
section about JSC_PARSE_ERROR to link to the FAQ. Also add information like
"this error has come up when users do something like goog.require('goog.events')
but are not including the deps.js file in the compilation." This will make it
easier to find this information.

5. Update the pages about closurebuilder and depswriter to include information
like that provided in the FAQ: that the deps.js file IS used during compilation,
to resolve forward-references. As stated on the FAQ:
    Closure Library contains a deps.js file. The deps file serves two purposes:
    * It lists the location of files, so we can bootstrap them for uncompiled testing.
    * It forward-declares all type names even if their files are not included in  
    compilation.
And fix the sentence on
https://developers.google.com/closure/library/docs/depswriter to say "In
uncompiled mode" instead of "In debug mode".

6. Add a hint to the error message, to read something like this:
    closure/closure/goog/events/events.js:896: ERROR - Bad type annotation. Unknown type goog.debug.ErrorHandler.  Consider adding goog/deps.js to the set of files to compile with the --js compiler flag.
    * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to
    ^
Especially because the error comes up in a closure-library file, not in the
user's code, this is very confusing to a new user. Maybe add that hint only if
you detect the error is on a file from the Closure Library.

7. If the Bolin book is ever revised, update the sections mentioned above to
explain that the deps.js file is used for forward references during compilation.
Consider adding this to the online errata for the Bolin book.

Regards,
--ErikN

Original issue reported on code.google.com by neum...@gmail.com on 2 Jun 2013 at 7:25

GoogleCodeExporter commented 8 years ago
To emphasize this is important, here are other issues that are essentially the 
same as this one -- fixing the documentation would have prevented these issues 
from being filed.

Issues 335, 401, 555, 340, 493, 381
Also related: 266, 179

Original comment by neum...@gmail.com on 2 Jun 2013 at 8:17

GoogleCodeExporter commented 8 years ago
Hi, this is two years late, but I'm working on mitigating confusion on this 
issue. 

The thing to note here is that it's not always necessary to include deps.js in 
your compilation. It's only necessary when you happen to be using a Closure 
library that references a type that is not goog.require'd in the file. This can 
happen when a file references a particular type in annotations in comments 
(e.g., @type {Foo}), but never actually uses the type directly (e.g., invoking 
via "new" or referencing its statics). For an explanation on why we do this see 
the thread you referenced: 
https://code.google.com/p/closure-library/issues/detail?id=401. 

Anyway, I'm going to work on documenting this issue better as I do think it's 
quite confusing, but I'm moving this issue to 
https://github.com/google/closure-library/issues/54 as the canonical version. 
Feel free to comment there.

Original comment by joelt...@google.com on 7 Aug 2015 at 6:09