Browse DevX
Sign up for e-mail newsletters from DevX


A Server-Side Assist for Loading Client-Side JavaScript Code : Page 4

JavaScript lacks a function for loading and executing a library file while it's executing a main program file. Implementing an include directive on the server side is a simple technique for getting around this limitation.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

The Server-Side Script

The following listing shows jsload.cgi, which is really a stub program—it determines which script is being loaded and then calls JSInclude::load():

#!/usr/bin/perl use CGI; use JSInclude; print "Content-type: text/html\n\n"; # What script are we loading? $cgi = new CGI(); $file = $cgi->param( "file" ); $file = "main.js"; # Load the script. JSInclude::load( $file );

Security Warning: The jsload.cgi script, as shown above, is not secure. Since it takes a filename as a parameter, it might be possible (on some servers) to load files that shouldn't be loaded, potentially providing a backdoor vulnerability. Please make sure your permissions are set in such a way that this cannot happen.

JSInclude.pm is where the real action is. JSInclude::load() starts the process by calling include()—that's the Perl include, not the JavaScript include. Before and after this, however, it prints a preamble and postamble (respectively). These are normally empty, but if you set the '$verbose' variable at the top, the preamble and postamble will time the entire loading process on the client side and display the total loading time.

The following listing shows JSInclude::include():

package JSInclude; my $verbose = 0; sub get_includes( $ ) { my ($filename) = @_; my @includes = (); if (open( SRC, $filename )) { while (<SRC>) { if (/^\s*include\s*\(\s*"(.*)"\s*\)\s*;\s*$/) { my $filename = $1; push @includes, $filename; } } close( SRC ); } return \@includes; } sub include( $$ ); sub include( $$ ) { my ($filename,$already) = @_; if ($already->{$filename}) { return; } $already->{$filename} = 1; my $includes = get_includes( $filename ); foreach my $include (@$includes) { include( $include, $already ); } if (!open( SRC, $filename )) { print "Can't open '$filename': $!\n"; die; } print qq(<script language="javascript">\n); while (<SRC>) { print if (!/^\s*include\s*\(\s*"(.*)"\s*\)\s*;\s*$/); } print qq(</script>\n); close( SRC ); } sub preamble { print <<EOF if ($verbose); <script language="javascript"> var ___tt = new Date().getTime(); </script> EOF } sub postamble { print <<EOF if ($verbose); <script language="javascript"> ___tt = new Date().getTime() - ___tt; alert( "Loading: "+(___tt/1000)+" seconds" ); </script> EOF } sub load( $ ) { my ($startfile) = @_; preamble(); include( $startfile, {} ); postamble(); } 1;

This function is responsible for reading the contents of the file, scanning it for include(...) statements, and doing the include itself. The actual scanning is done by the get_includes() function.

Note that the include(...) statement in the JavaScript is never executed; instead, it is replaced (here on the server side) by the contents of the included file. Also note that include() maintains a variable called $already, which is a hash containing the names of all the files that have already been included. Including a file multiple times isn't necessary, and it in fact can lead to infinite loops.

A Cross-Platform include Hack

In the end, the technique described here is as much a hack as any other technique for JavaScript include. However, it relies only on CGI and Perl—two mature and predictable technologies, so you can expect your includes to work across all server and client platforms.

It's also a lot faster.

Greg Travis is a Java programmer and technology writer, living in New York City. After spending three years in the world of high-end PC games, he joined EarthWeb, where he developed new technologies with the then-new Java programming language. Since 1997, he has been a consultant in a variety of Web technologies.
Thanks for your registration, follow us on our social networks to keep up-to-date