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.

The big difference obviously is that with Dojo, dojo.require is magic and happens automatically. Dojo will use an XMLHttpRequest to evaluate your JavaScript on the fly. Google’s system works differently, it creates script tags. Google’s system is better for debugging. Dojo provides some options for also using script tags but because that’s not the intended means of using dojo.require it can lead to problems.

Using script tags makes debugging easier because in debugging tools (such as Firebug, IE’s Developer Tools, or Webkit’s Web Inspector) JavaScript provided with script tags can be located by filename. How evaluated code shows up in debugging tools depends on the tool but it’s never simple or easy and becomes worse the more JavaScript you’ve evaluated.

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.

With Dojo you could dump your dojo.require wherever you wanted, similar to use of #include in C source files. You don’t want to do this with the Google Closure Library as the code is added via a script tag and wont be available until that script tag has been added. Instead create a single place where all your goog.require statements are, probably a separate JavaScript file or in a separate script tag in your markup.

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.

script – generates a single JavaScript file that includes all of your code and parts of the goog namespace you’re using. You will only have one script tag, but your JavaScript will be otherwise unchanged.

compiled – generates a single compiled JavaScript file that includes everything you need. Requires Google Closure Compiler’s compile.jar (available separately). You will only have one script tag of minified JavaScript. Your code will be significantly modified, the degree to which depend on the compiler flags provided.

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.

Initial setup

In this set up I keep goog and my Javascript separate. I don’t like including big external libraries in my source control and Google Closure Library is over 100MB! I used to include JavaScript libraries but as they’ve grown in size and complexity I’ve decided to stop doing this, similar to external python libraries. This is handy if you like to create a lot of releases and branches and don’t want to take up hundreds of megabytes of hard drive space on your subversion server for every branch and release.

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.

/media/js/myapp/ are the checked in files for my JavaScript app. It is the root for my application.

/meda/js/release/ is where my compiled JavaScript files are, I’ll only use this in production.

Let’s say I have a sub application with two files:

/media/js/myapp/subapp/controller.js
/media/js/myapp/subapp/view.js

At the top of the file in in /media/js/myapp/subapp/controller.js I will put:

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.

IMPORTANT: On your development machine find your way to your /media/js/myapp directory. You will want to be here when you call the calcdeps.py script. If you are in any other directory this will fail because of how the script works. There is a CLOSURE_BASE_PATH variable you can set in your JavaScript that can help with any errors you might run into if you do this differently.

I call the calcdeps.py as such (closure-library-read-only is the path to Google Closure Library on your system):

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

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:

/Users/Bjorn/projects/site is where my website is in my file system.
closure-library-read-only is wherever your copy of the ENTIRE Google Closure Library is on your system, not just the JavaScript.
/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:

/media/js/release/subapp-compiled.js

This is a JavaScript files that has all the code I need to run subapp. If I later want to include myapp.subapp.model I have to rerun the statement. That’s why it’s better to use a dependency script for dev and compiled file for production. You don’t want to have to compile your code every time you edit your files during development and debugging obfuscated code created by compilation wont be fun. In production however you don’t need to do any of this and having one file reduces page load times for users.

In conclusion
I hope this has helped you figure out how to use goog.require and goog.provide for your own JavaScript code. I recommend also looking at the compilation flag options and reading the rest of the documentation.

Rate this:

Like this:

LikeLoading...

Related

6 Comments

I try to use calcdeps this way but it fails with “Could not find Closure Library in the specified paths”, if I change the “-p ..” parameter to “-p ../goog” it works but doesn’t include controller.js and view.js in deps.js

-d –dep Directories or files that should be traversed to find required dependencies for the deps file. Does not generate dependency information for names provided by these files. Only useful in deps mode.

-p –path The paths that should be traversed to build the dependencies.