Added a HOWTO for using Google Closure’s Template files with your own code.
The difference between dojo.require and goog.require
(skip if you don’t care about Dojo)
Coming from the world of Dojo to the Google Closure Library I thought I could use goog.require and goog.provide the way I am used to with Dojo. Nope, it’s done differently.
Another difference is that goog.require doesn’t request your code if it doesn’t already know where to find it. You tell Closure where to find it by using goog.addDependency, an extra step not required in Dojo. The best way to do this is to use a python script included with the framework.
There’s also a difference between Dojo’s custom builds and the Google Closure Compiler. Google Closure Compiler is a separate tool but the best means to use this tool if you’re already using the Google Closure Library is to use the provided python script.
Having explained the differences there are also similarities: directory structure is just as important when using goog.require as it is with dojo.require. If your goog.provide is “myapp.subapp.view” you should have a directory structure as you would for dojo (more below).
The three options
Before I explain the means by which you can use goog.require and goog.provide for your own code you need to know about the three options available when you use the calcdeps.py python script provided by the framework:
- deps – generate a dependance file – If you use this option, when your site is loaded in the browser many script tags are added, one for each file.
Most of the details of these three main options (there’s also a list option useful for information purposes only) can be read about on the documentation page for the calcdeps.py script. What the docs are not clear about is how to point the script to your code. I will explain this to save you a period of trial and error and also show an example.
My directory structure is as such where / is web root (not / on the computer):
/media/js/goog/ is a symlink to what in the Google Closure docs would be described as closure-library-read-only/closure/goog/. This is on my dev machine where I have the Google Closure library. I don’t have the Google Closure Library on the production machine because when I create a build I don’t need it.
Let’s say I have a sub application with two files:
At the top of the file in in /media/js/myapp/subapp/controller.js I will put:
goog.provide( "myapp.subapp.controller" );
and in the other file I’ll put:
goog.provide( "myapp.subapp.view" );
Whatever code these files have go below these lines.
Next I create a file that will have all my goog.require statements:
The contents of this file will be:
goog.require( "goog.events" ); goog.require( "goog.dom" ); goog.require( "myapp.subapp.controller" ); goog.require( "myapp.subapp.view" );
I have added require statements for goog.dom and goog.events because I will be using those parts of Google Closure Library in my own code.
What is in my index.html file varies depending on if I am using it for development or production. In development I’ll have:
Note the deps.js, this is a generated file. In production I’ll simply have:
I create different files for every subapp because each subapp in my architecture exists on a separate page. This might be different for you. This would require a different require.js for every subapp, and during compilation additional compilations for every compiled file.
Using calcdeps.py to create a dependency file
This section explains how to use the calcdeps.py script included in the Google Closure Library. I recommend reading the documentation carefully. Even so, what I describe below, with regard to the difference between creating a dependency file and a compiled file and the paths is not included in the documentation.
I call the calcdeps.py as such (closure-library-read-only is the path to Google Closure Library on your system):
closure-library-read-only/closure/bin/calcdeps.py -i ./require.js -p .. -o deps > deps.js
// This file was autogenerated by calcdeps.py goog.addDependency('../utils.js', , ); goog.addDependency('../myapp/deps.js', , ); goog.addDependency('../myapp/require.js', , ['goog.events', 'goog.dom', 'myapp subapp.controller', 'myapp subapp.view']); goog.addDependency('../myapp/subapp/controller.js', ['myapp.subapp.controller'], ); goog.addDependency('../myapp/subapp/model.js', ['myapp.subapp.Model'], ); goog.addDependency('../myapp/subapp/view.js', ['myapp.subapp.view'], );
Couple of things of note:
Notice utils.js and model.js. I didn’t talk about these files or add them to require.js because I’m not using them but look the script found them anyway. calcdeps.py uses the path given via -p option and traveres all its subdirectories recursively looking for files. It searches the files for goog.require and goog.provide statements and uses those to calculate what goog.addDependency statements it needs to create.
The first argument to goog.addDepedency is the file name, the second is the goog.provide statements found in the file, and the third is the goog.require statements in the file.
The .. path is relative to /media/js/goog/base.js. Very important.
If you now request index.html and look in Firebug’s net tab you’ll see requests for all of the necessary dependencies for goog.events and goog.dom, as well as
You wont see:
because you haven’t requested them with goog.require. You can simply add another goog.require statement for /media/js/myapp/subapp/model.js to /media/js/myapp/require.js without calling calcdeps.py again and it will request the file! utils.js doesn’t provide a goog.provide statement so you have to create a separate script tag for it.
Using calcdeps.py to create a compiled file
Remember: You need to download compile.jar separately, it’s not included in the library!
For the purpose of creating a dependency file we used relative paths which created relative paths in your deps.js file. For creating a compiled file we will use absolute paths and we have to add the path to the Google Closure Library in addition to the path to our own code.
I changed my current working directory to /media/js/release and call this in my terminal:
closure-library-read-only/closure/bin/calcdeps.py -i /Users/Bjorn/projects/site/media/js/myapp/require.js -p closure-library-read-only/ -p /Users/Bjorn/projects/site/media/js/myapp/ -c /Users/Bjorn/closure/compiler/compiler.jar -o compiled > subapp-compiled.js
/Users/Bjorn/projects/site is where my website is in my file system.
/Users/Bjorn/closure/compiler/compiler.jar is where I have put the compiler.jar file for the purpose of this example on my file system.
Running this statement creates: