You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by George Sexton <ge...@mhsoftware.com> on 2011/04/11 23:47:53 UTC

OT: Versioning in Javascript Files

I'm looking for ideas on how other people are doing versioning in Javascript
files. I'm hitting issues if I change my files in an incompatible way, or I
upgrade files.

For example, if I upgrade from DOJO 1.5 to DOJO 1.6, the user's browsers are
not always refreshing the DOJO files, and things don't work.

Similarly, if I update a javascript function to take additional arguments,
then the browser using the old version throws an error.

I've spent a lot of time in the past few days telling users to click on the
refresh button of their browser and I'm pretty sick of it.

I've thought of versioning my whole "scripts" directory. IOW, if my app
version is 3.4.9, make the scripts directory scripts-3.4.9 to force the
browser to get files from the new location. This is kind of a pain for
version control reasons but otherwise it's OK.

I'm really looking for ideas on how other web developers are handling this
problem.

--
George Sexton
MH Software, Inc.
303 438-9585
www.mhsoftware.com




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


RE: OT: Versioning in Javascript Files

Posted by George Sexton <ge...@mhsoftware.com>.
Thanks to everyone that responded.

I'll make a few comments.

DOJO tends to make a million calls for images/scripts/css files. The ETag solution isn't going to optimize well because there will still be a ton of 304 requests which all take time to make happen. Also, I'm not using Apache in front of tomcat. I'm using Tomcat bare. Besides, let's face it. If the browser were doing the right thing then they would pick up that the script file changed using the last_modified header that tomcat presents. The problem is that the browsers are just using the cached version rather than making an if-modified-since request.

The .js?arg=someval option is a pretty reasonable idea. It offers the advantage that I don't have to do hocus-pocus with my scripts path name. The problem I'm seeing here though is that with something like the dojo library which makes its own internal calls to load child javascript files it won't work. For example, dojo loads the dijit files including dijit/_Dialog.js. There's no way to attach the argument to the dojo request into the dijit directory. So, I think this is a fragile solution.


My previous best plan was to rename my scripts directory to scripts-x.x.x. The downside of the scripts-x.x.x is that when I upgrade my customers, I've got to make the old scripts-x.x.x directory go away. I'll also have to do some hocus pocus to make CVS, the version control system OK with it. Perhaps I can just make scripts a symlink to scripts-x.x.x and keep it happy that way. The other big problem I see is that if I make the dir name change on every build, then even the tiniest of changes will force me to rename the directory. I run a hosted application and this would have to be done across hundreds of deployments.

The rewrite solution is OK. It solves the problems but adds another component to my request cycle, and to my distribution load. On the other hand, it doesn't have the icky problem of needing to rename the directory every time I push out a trivial change. The other advantage I see is that using this, I can set arbitrarily long expires headers on my responses so that the browser "should" only request files when the program version changes. This is probably the solution I should go with.

Again, thanks to everyone who responded.


George Sexton
MH Software, Inc.
303 438-9585
www.mhsoftware.com


> -----Original Message-----
> From: Ognjen Blagojevic [mailto:ognjen.d.blagojevic@gmail.com]
> Sent: Tuesday, April 12, 2011 1:06 PM
> To: users@tomcat.apache.org
> Subject: Re: OT: Versioning in Javascript Files
> 
> Chris,
> 
> >>    href="some.css?v=${parameter}"
> >
> > Some clients and proxies will refuse to cache resources with a query
> > string. In those cases, caching (obviously) won't work and there
> might
> > be a significant loss in performance of the web site.
> 
> Exactly. I tested on one usecase (no proxy, limited number of web
> browsers), which is not representative. Now I see that it should not be
> used as a general solution.
> 
> -Ognjen
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Ognjen Blagojevic <og...@gmail.com>.
Chris,

>>    href="some.css?v=${parameter}"
>
> Some clients and proxies will refuse to cache resources with a query
> string. In those cases, caching (obviously) won't work and there might
> be a significant loss in performance of the web site.

Exactly. I tested on one usecase (no proxy, limited number of web 
browsers), which is not representative. Now I see that it should not be 
used as a general solution.

-Ognjen




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ognjen,

On 4/12/2011 5:37 AM, Ognjen Blagojevic wrote:
> For all static resources (css, images, js) you might add artificial
> parameter that will trigger reload, like this:
> 
>   href="some.css?v=${parameter}"

Some clients and proxies will refuse to cache resources with a query
string. In those cases, caching (obviously) won't work and there might
be a significant loss in performance of the web site.

Changing the path is safer and more effective.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk2kXlcACgkQ9CaO5/Lv0PDWtACfQI42BqpvM+Lus3YKKOwWbjXe
SfcAnR3zITZa0muhZcQYj/NzO3qMa1eD
=zmBL
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Ognjen Blagojevic <og...@gmail.com>.
On 11.4.2011 23:47, George Sexton wrote:
> I'm looking for ideas on how other people are doing versioning in Javascript
> files. I'm hitting issues if I change my files in an incompatible way, or I
> upgrade files.
>
> For example, if I upgrade from DOJO 1.5 to DOJO 1.6, the user's browsers are
> not always refreshing the DOJO files, and things don't work.
>
> Similarly, if I update a javascript function to take additional arguments,
> then the browser using the old version throws an error.
>
> I've spent a lot of time in the past few days telling users to click on the
> refresh button of their browser and I'm pretty sick of it.
>
> I've thought of versioning my whole "scripts" directory. IOW, if my app
> version is 3.4.9, make the scripts directory scripts-3.4.9 to force the
> browser to get files from the new location. This is kind of a pain for
> version control reasons but otherwise it's OK.
>
> I'm really looking for ideas on how other web developers are handling this
> problem.

For all static resources (css, images, js) you might add artificial 
parameter that will trigger reload, like this:

   href="some.css?v=${parameter}"

Where 'parameter' might be:

1. Static resource last modification time. This will trigger reload 
every time resource is changed.

2. Static resource hash, this will trigger reload every time static 
resource is changed (except for the insignificant number of cases)

3. Application version (1.3.1, 1.3.2...). This will trigger reload every 
time new version of application is released. This requires proper 
release process, and triggers some extra reloads even when there is no 
need for that.

4. Current system time. This will trigger reload of resource every time.


We use no. 3, since Maven packaging makes it really easy to implement 
(${pom.version}}.

Regards,
Ognjen

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tim,

On 4/12/2011 7:31 AM, Tim Funk wrote:
> The second is trickier. Relying on random query string is not fun since
> it may cause some browsers/proxies to be less prone to caching which can
> really affect performance. Especially if the the query string is
> dynamic. An easier solution is to use place your scripts is a "special"
> directory - then use a rewrite (or similar) rule to access them. So that
> the path is dynamic (and somewhat bogus). For example:
> /scripts/2011-04-11-072730/dojo.js - and in this case - you can have a
> rewrite rule look for a pattern and remove it from the path and forward
> to the script and let the default servlet handle things.

This is exactly what we've done in a particular case, mostly for
testing: we have a service provider that handles IVR telephone calls and
we have to provide the audio files for them to use via HTTP. They cache
all audio files so, ideally, the file is only obtained from us once (at
least once per server in the cluster, I suppose). Unfortunately, they
don't have an automated way to EXPIRE a particular cache entry, so we
invented a bogus path element that we can change to force a cache miss
and a reload. Something like this:

http://www.oursite.com/audio/version/1.wav

We have mapped /audio/*/ mapped to /audio so the "version" is just a
random string that gets ignored by the web server -- but it's important
for clients so they can properly cache.

Whenever we have to update an audio clip, we just change the version
number in the URL and the new file gets used.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk2kXzsACgkQ9CaO5/Lv0PD/nACgjCDevK8RBSG+sHkUTC/dN1DE
qFMAn13KseQKN5Qw0dLPDAKRedutYcz9
=sIHp
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Francis GALIEGUE <fg...@one2team.com>.
On Tue, Apr 12, 2011 at 13:31, Tim Funk <fu...@apache.org> wrote:
[...]
>
> The second is trickier. Relying on random query string is not fun since it
> may cause some browsers/proxies to be less prone to caching which can really
> affect performance. Especially if the the query string is dynamic. An easier
> solution is to use place your scripts is a "special" directory - then use a
> rewrite (or similar) rule to access them. So that the path is dynamic (and
> somewhat bogus). For example:
> /scripts/2011-04-11-072730/dojo.js - and in this case - you can have a
> rewrite rule look for a pattern and remove it from the path and forward to
> the script and let the default servlet handle things.
>
> Then to populate "2011-04-11-072730" - you can do that one of 3 ways:
> - At build time - calculate the timestamp and replace it
> - At run time - use a configuration parameter in context.xml
> - A combo of both  - I like this one best since a build can trigger a new
> name, but sometimes you may run into situations where you don't need a build
> but you need it refreshed - so a server parameter tweak makes this easy too
> (and if savvy enough can be done via JMX to save a restart from occurring)
>

No need... Just have the server part calculate an appropriate ETag for
this case. It is no replacement for the first solution (which is, and
always will be, the best one), but it allows the client to query the
server with an If-None-Match header.

Apache does this by default with a combination of mtime and inode
number IIRC. I don't know, I never use ETags but only adapted
Cache-Control directives.

-- 
Francis Galiegue
ONE2TEAM
Ingénieur système
Mob : +33 (0) 683 877 875
Tel : +33 (0) 178 945 552
fge@one2team.com
40 avenue Raymond Poincaré
75116 Paris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Tim Funk <fu...@apache.org>.
I've loathed this issue too. There are 2 major cases to deal with
- Libraries changing (like dojo, prototype, etc)
- Your external files changing

The first is "easy" to change .. in that you create a /scripts/ dir and 
all 3rd party libraries go into their own directory with version number. 
New version - new directory (and hope the file names remain the same). 
Then *hopefully* you have a common include file that you just need to 
change once to point to the new directory. (Of course a global 
find/replace in this case is easy)

The second is trickier. Relying on random query string is not fun since 
it may cause some browsers/proxies to be less prone to caching which can 
really affect performance. Especially if the the query string is 
dynamic. An easier solution is to use place your scripts is a "special" 
directory - then use a rewrite (or similar) rule to access them. So that 
the path is dynamic (and somewhat bogus). For example:
/scripts/2011-04-11-072730/dojo.js - and in this case - you can have a 
rewrite rule look for a pattern and remove it from the path and forward 
to the script and let the default servlet handle things.

Then to populate "2011-04-11-072730" - you can do that one of 3 ways:
- At build time - calculate the timestamp and replace it
- At run time - use a configuration parameter in context.xml
- A combo of both  - I like this one best since a build can trigger a 
new name, but sometimes you may run into situations where you don't need 
a build but you need it refreshed - so a server parameter tweak makes 
this easy too (and if savvy enough can be done via JMX to save a restart 
from occurring)

Good luck ...

-Tim

On 4/11/2011 5:47 PM, George Sexton wrote:
> I'm looking for ideas on how other people are doing versioning in Javascript
> files. I'm hitting issues if I change my files in an incompatible way, or I
> upgrade files.
>
> For example, if I upgrade from DOJO 1.5 to DOJO 1.6, the user's browsers are
> not always refreshing the DOJO files, and things don't work.
>
> Similarly, if I update a javascript function to take additional arguments,
> then the browser using the old version throws an error.
>
> I've spent a lot of time in the past few days telling users to click on the
> refresh button of their browser and I'm pretty sick of it.
>
> I've thought of versioning my whole "scripts" directory. IOW, if my app
> version is 3.4.9, make the scripts directory scripts-3.4.9 to force the
> browser to get files from the new location. This is kind of a pain for
> version control reasons but otherwise it's OK.
>
> I'm really looking for ideas on how other web developers are handling this
> problem.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: OT: Versioning in Javascript Files

Posted by Francis GALIEGUE <fg...@one2team.com>.
On Mon, Apr 11, 2011 at 23:47, George Sexton <ge...@mhsoftware.com> wrote:
> I'm looking for ideas on how other people are doing versioning in Javascript
> files. I'm hitting issues if I change my files in an incompatible way, or I
> upgrade files.
>
> For example, if I upgrade from DOJO 1.5 to DOJO 1.6, the user's browsers are
> not always refreshing the DOJO files, and things don't work.
>
> Similarly, if I update a javascript function to take additional arguments,
> then the browser using the old version throws an error.
>
> I've spent a lot of time in the past few days telling users to click on the
> refresh button of their browser and I'm pretty sick of it.
>
> I've thought of versioning my whole "scripts" directory. IOW, if my app
> version is 3.4.9, make the scripts directory scripts-3.4.9 to force the
> browser to get files from the new location. This is kind of a pain for
> version control reasons but otherwise it's OK.
>
> I'm really looking for ideas on how other web developers are handling this
> problem.
>

Simple solution: change paths if you change versions!

1.5 would be /static/dojo-1.5.js, 1.6 would be /static/dojo-1.6.js, etc.

I don't know your setup exactly, but it is highly probable that the
server sends back cache control headers saying that this file at this
URL expires some time in the future. If the URL doesn't change, the
browser won't even bother reloading. It is only if the path changes
that you can be sure that the new version will be reloaded.

-- 
Francis Galiegue
ONE2TEAM
Ingénieur système
Mob : +33 (0) 683 877 875
Tel : +33 (0) 178 945 552
fge@one2team.com
40 avenue Raymond Poincaré
75116 Paris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org