Design question: how to make it easier to build jQuery-based JS apps with plovr?

125 views
Skip to first unread message

Michael Bolin

unread,
Jan 8, 2011, 11:36:36 AM1/8/11
to plovr
This week, I gave a talk at the Boston JS Meetup. It was a full room
and the majority of the people in it were using jQuery, so I think a
lot of those folks could benefit from plovr -- they just didn't know
it yet!

I don't expect most jQuery developers to have a lot of interest in the
Closure Library, but both the Compiler and Templates can be a big
help. The way I see it, there are primarily two ways they can use the
Compiler:

* Use the jQuery externs file (thanks Chad Killingsworth!!!) and
compile new JS code against it in Advanced mode (or Simple or
Whitespace).
* Don't bother with externs and just compile in Simple mode.

Even for those who are not planning to use the Closure Library with
plovr, I would still force the tool to include base.js for
goog.provide(), goog.require(), and ironically, goog.getCssName(). I
think the first two can potentially help jQuery developers manage
dependencies, and the latter is necessary as we recently changed plovr
so that the JS it generates from Soy uses goog.getCssName(). (It
turned out to be difficult to do this on a per-config basis because
then every call to JsInput.getCode() would have to take a Config,
which would be annoying, and we want this to be default so we can
enable CSS class renaming in the near future.)

Under the above assumptions, jQuery users who use Closure Templates
would end up generating JS that includes the statement
"goog.require('soy')" which would in turn include the 20 transitive
dependencies that soyutils_usegoog.js results in pulling in. For
jQuery users who are compiling in Advanced mode, this should not be an
issue, but I am concerned about those who use Simple mode, as the
unused functions from those 20 dependencies will not be removed by the
Compiler in that case. Arguably, the right thing to do in that case is
to make it possible to include soyutils.js instead of
soyutils_usegoog.js, but there needs to be an elegant way to express
this in the plovr config file.

Currently, it is easy enough to use plovr with jQuery if you know what
you're doing:
(1) Download http://closure-compiler.googlecode.com/svn-history/r678/trunk/contrib/externs/jquery-1.4.4.externs.js
or whatever the appropriate file is for the version of jQuery you're
using.
(2) Add it to the list of "externs" in the plovr config.
(3) Write code!

Although that sounds pretty simple, I'd argue that it isn't simple
enough. It might be easier to have explicit jQuery options in the
config, like:

"jQuery": {
"version": "1.4.4"
}

In turn, that would include https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js
as an input and the appropriate externs file. (Though this external
dependency would not make it possible to develop offline.)

It seems like it should be possible to override where jquery.min.js
comes from so (1) you can develop offline, and (2) you can use your
own version which possibly contains your own edits or the "debugger;"
keyword at key places.

Perhaps you should also be able to choose between
https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js and
https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js with a
boolean. Maybe the unobfuscated one should actually be the default for
debugging?

Again, I am not a jQuery developer myself, so I would like to hear
from those who are about what would be the most helpful thing that
could be done to use jQuery with plovr. Examples of new config options
to support this feature would be most illustrative.

Thanks!
Michael

Steven Hall

unread,
Jan 10, 2011, 7:52:50 AM1/10/11
to plovr
I've used jQuery alongside the Compiler for a while, and usually just
included the appropriate extern as you mentioned.

I like the idea of being able to specify a jQuery version in plovr and
having the correct extern file brought in, but I don't think it's
plovr's job to include the script tag to the jQuery file. I would say
it's the user's responsibility to determine where the jQuery library
comes from, and it seems like unnecessary work for plovr to do.
> (1) Downloadhttp://closure-compiler.googlecode.com/svn-history/r678/trunk/contrib...
> or whatever the appropriate file is for the version of jQuery you're
> using.
> (2) Add it to the list of "externs" in the plovr config.
> (3) Write code!
>
> Although that sounds pretty simple, I'd argue that it isn't simple
> enough. It might be easier to have explicit jQuery options in the
> config, like:
>
> "jQuery": {
>   "version": "1.4.4"
>
> }
>
> In turn, that would includehttps://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js
> as an input and the appropriate externs file. (Though this external
> dependency would not make it possible to develop offline.)
>
> It seems like it should be possible to override where jquery.min.js
> comes from so (1) you can develop offline, and (2) you can use your
> own version which possibly contains your own edits or the "debugger;"
> keyword at key places.
>
> Perhaps you should also be able to choose betweenhttps://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.jsandhttps://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.jswith a

Dallan

unread,
Jan 10, 2011, 10:53:59 AM1/10/11
to plovr
When I use jQuery it's in a mode where I include different javascript
files in different pages of my application. On a search page I'll
include autocomplete functionality; on an edit page I'll include
validation functionality. I end up including jQuery, 2-3 jQuery
plugins, and my own javascript file on the page. I also don't think
it's plovr's job to include the script tags for the jQuery file. But
since I have multiple javascript files, it would be nice if I didn't
have to create multiple config files. Instead it might be nice to run
plovr with a generic config file, where I specified the input in the
url rather than in the config file (e.g.,
http://localhost:9810/compile?id=sample&filename=javascript-file-for-this-page),
and plovr would compile the specified file according to the parameters
in the specified config file.

David Turnbull

unread,
Jan 15, 2011, 7:47:57 PM1/15/11
to pl...@googlegroups.com
The last project I was working on started with jQuery + compiler.jar + base.js.  It broke down long before the need for a dependency system.  There wasn't any practical way we found to marry jQuery and Library.  Dependencies looked like they were going to be all flat and circular.  Advanced compilation was getting silly with all the stringification.

There are plenty of asset packaging tools that support compiler.jar and this is what I recommend for folks who use jQuery.  An asset packager is specially designed to deal with combinations like jQuery + compiler.jar.  You don't need a build tool until you want to use Library.

If you want to attract the jQuery audience, consider what they work with.  It's generally a variety of libraries from various authors using widely different programming styles.  Combined with custom code and the main library, of course.  Some libraries, like jquery-ui, will need another externs if you want to use from advanced compilation.  Some code may be so incompatible that only simple optimizations will work or it may only work with yahoo's compiler.  Dallon mentioned that he includes different files on different pages.

Using plovr in the jQuery environment only adds to the complexity.  It does not appear to simplify anything unless you add asset packager features to replace the other tools that must be used.  This isn't a criticism of plovr; my own build tool, googlyscript, does not attempt to solve these problems either.  We put the externs for jquery and jquery-ui on the wiki and left it at that.

Michael Bolin

unread,
Jan 20, 2011, 6:36:23 PM1/20/11
to plovr
Hi David, thanks for the thorough response! It seems that I need to
take a deeper look at how developers use jQuery before taking any
serious action (like a special "jQuery" option in plovr).

For now, I think one of the first things will be to make it easier to
expose the externs in the contrib directory (http://code.google.com/p/
closure-compiler/source/browse/#svn%2Ftrunk%2Fcontrib%2Fexterns),
which includes:

jquery-1.4.4.externs.js
chrome_extensions.js
google_maps_api_v3_3.js

among others. I'm working on updating my Chrome extension right now
myself, so I'm fairly motivated to fix this.

One option would be to prefix them with "//" so they could be included
in the existing "externs" option:

"externs": [
"my_externs1.js",
"my_externs2.js",
"//chrome_extensions.js",
"//google_maps_api_v3_3.js"
]

Note that this would "flatten" the contrib/externs directory, as it
would be "//google_maps_api_v3_3.js" rather than "//maps/
google_maps_api_v3_3.js" because I think the latter is (hopefully) an
insignificant detail and is subject to change.

Once this is done, the simple answer for using plovr and jQuery is to
use:

"externs": "//jquery-1.4.4.externs.js",

and then whichever compilation mode/warning level is appropriate for
your project.

Does this seem like a reasonable first step whose backward
compatibility should be easy to maintain?
Michael

Chris Price

unread,
Jan 21, 2011, 3:52:39 AM1/21/11
to pl...@googlegroups.com

> One option would be to prefix them with "//" so they could be included
> in the existing "externs" option:

> "externs": [
> "my_externs1.js",
> "my_externs2.js",
> "//chrome_extensions.js",
> "//google_maps_api_v3_3.js"
> ]

> Note that this would "flatten" the contrib/externs directory, as it
> would be "//google_maps_api_v3_3.js" rather than "//maps/
> google_maps_api_v3_3.js" because I think the latter is (hopefully) an
> insignificant detail and is subject to change.

> Once this is done, the simple answer for using plovr and jQuery is to
> use:

> "externs": "//jquery-1.4.4.externs.js",

> and then whichever compilation mode/warning level is appropriate for
> your project.

> Does this seem like a reasonable first step whose backward
> compatibility should be easy to maintain?

Maybe you could use a token that isn't a commonly legal file name character to identify the contrib folder e.g. $. It might make it less confusing for people who accidentally type // expecting it to be treated as a legal file path.

Chris


Chris Price

unread,
Jan 21, 2011, 3:55:32 AM1/21/11
to pl...@googlegroups.com
Sorry my bad I forgot almost every character is legal on *nix (it's
early and I haven't had my coffee yet!) . I think I'm right in saying
that tilde (~) isn't though so maybe that could be used.

Chris Price

unread,
Jan 21, 2011, 4:00:14 AM1/21/11
to pl...@googlegroups.com
Scratch that, I like your idea :)

David Turnbull

unread,
Jan 21, 2011, 11:56:59 PM1/21/11
to plovr
I propose adding the externs for jquery-ui as well. Yeah, it's only
one line, but I think it'll help developers new to Closure. We made
one that you can use:

https://github.com/dturnbull/googlyscript/wiki/jquery.ui.widget.externs

Here's a crazy idea. What if externs files supported
goog.provides('vendor.jQuery') and the build tools scanned for this in
*.externs files? Any time someone goog.requires('vendor.jQuery') the
matching externs will be used for compilation as well as the .js
file. It would not fail if only a .externs file was found, for this
is when the .js should not be in the compiled output.

-david

David Turnbull

unread,
Jan 22, 2011, 3:36:42 AM1/22/11
to plovr
Crazy idea works. I just added it to Googlyscript. The diff is quite
small. The new files are just test code.

https://github.com/dturnbull/googlyscript/commit/6027f36d840f6b77f30b1d7a85ddac22c16f5586

I found you can't use a namespace already provided. So
goog.provide('jQuery') is not acceptable. But you can
goog.provide('externs.jQuery').

Imagine a whole folder of externs files that vend out 'externs.jQuery.
1_4_4', 'externs.pluginX' et al. One file could even provide
'externs.jQuery' and require the latest version. Someone wanting to
use these externs need only goog.require what they want to use in
their app.

The only weird thing is that the compiler doesn't like seeing
goog.provide in the externs. I had to bracket the goog.provide in a
comment -- since Googlyscript parses like calcdeps instead of an AST
this was easy to fake out. If an exception can be made in
compiler.jar this looks to be a very clean approach.

I see no reason why this wouldn't work in calcdeps and plover as
well. I'm happy to offer any assistance with understanding how I got
this working.

-david

Michael Bolin

unread,
Feb 7, 2011, 10:03:36 PM2/7/11
to plovr
I just added support for this in this change:
http://code.google.com/p/plovr/source/detail?r=b242c3a1bfb6ad6eaead91ee695c7b2a0c714f96

You can see an example of this being used in a config file that is
part of a regression test:
http://plovr.googlecode.com/hg/testdata/chrome_extension/config.js?r=b242c3a1bfb6ad6eaead91ee695c7b2a0c714f96

If I get some quick feedback in the affirmative that this will help
people, I'll cut a release.

--Michael

On Jan 21, 4:00 am, Chris Price <pric...@gmail.com> wrote:
> Scratch that, I like your idea :)
>
> On Fri, Jan 21, 2011 at 8:55 AM, Chris Price <pric...@gmail.com> wrote:
> > Sorry my bad I forgot almost every character is legal on *nix (it's
> > early and I haven't had my coffee yet!) . I think I'm right in saying
> > that tilde (~) isn't though so maybe that could be used.
>
Reply all
Reply to author
Forward
0 new messages