ParenscriptWithApachePHP
This page describes one technique for seamlessly integrating ParenScript with Apache using PHP, mod_rewrite, and GNU make. It assumes a Un*x-like environment. These instructions should work on most Common Lisp implementations with minimal modifications, though they are written with CLisp in mind.

Installing ParenScript

Make a directory off of your web root. For this example, I'll call it "lisp". Inside of "lisp", copy "asdf.lisp" or "asdf.fas" from the ASDF package. Extract the ParenScript archive in this folder and make a symbolic link to "parenscript.asd":

ln -s parenscript-20060914/parenscript.asd .

Creating the wrapper Lisp code

Create two files, header.inc.lisp and footer.inc.lisp. In header.inc.lisp, write this:

(load "asdf")
(asdf:operate 'asdf:load-op :parenscript :verbose nil)
(shadow :!)
(use-package :js)

(princ
 (js

And in footer.inc.lisp, write this:

))

Creating the Makefile

Create a file called "Makefile" with the following contents:

%.js: %.lisp header.inc.lisp footer.inc.lisp
    cat header.inc.lisp $< footer.inc.lisp | /usr/local/bin/clisp -q -q -modern - > $@

Make sure you use a tab character to indent the line starting with "cat" or this will not work. Also, make sure the path and arguments to your Lisp binary are correct. The "-q -q" options to CLisp keep extraneous output to a minimum; "-modern" is not necessary but I like lowercase symbols.

Creating the PHP Wrapper

Create a file called "makejs.php", and write the following PHP code:

<?php
error_reporting(E_ALL);
header('Content-type: text/plain');
isset($_GET['file']) or die('no file specified');
$file = $_GET['file'];
preg_match('/^[\w-]+$/', $file) or die('invalid file: ' . $file);
file_exists("$file.lisp") or die('file not found: ' . $file);
exec("make $file.js 2>&1", $output);
foreach ($output as $line) {
    if ($line) {
        $line = addslashes($line);
        echo "if (window.console) console.log('$line');\n";
    }
}
echo file_get_contents("$file.js");
?>

Adding the mod_rewrite rule

Create a file called ".htaccess" and write the following two directives. For this to work, you will need to have "AllowOverride all" or similar in your Apache configuration and the "mod_rewrite" Apache module enabled.

RewriteEngine On
RewriteRule (.*)\.js makejs.php?file=$1 [L]

Putting it Together

Create a test HTML page, and in the "head" block, write a script tag like this:

<script type="text/javascript" src="/lisp/test.js"></script>

Create a Lisp source file in the "lisp" directory called "test.lisp" with the following contents:

(alert "Hello, world!")

Now, when you pull up your test page in a web browser, the script tag will cause it to request "/lisp/test.js". This will be intercepted by the mod_rewrite rule, causing "makejs.php?file=test" to be requested. "makejs.php" will call "make test.js", after ensuring the file exists and does not contain any dangerous characters. The header, Lisp source, and footer will be concatenated together, and their output will be sent to "test.js". The result will be sent to the browser, as if "test.js" had been there all along. If "test.lisp" has not been modified, "test.js" will not be recreated.

If all goes well, you should see an alert dialog that says "Hello, world!" when you load the page.

FireBug Support

I recommend installing the FireBug extension for FireFox. The "makejs.php" script will output its error messages using "console.log", which is a function that FireBug exposes to allow writing to the FireBug Console tab. If you do not have FireBug installed, no errors will occur because "makejs.php" checks to make sure "console.log" actually exists. The console messages can be a helpful aid in debugging. You can also view the JavaScript output on the filesystem to see what is being generated.


This document was originally written by Dave Benjamin.