Author: chabotc
Date: Thu May 15 05:39:15 2008
New Revision: 656630

URL: http://svn.apache.org/viewvc?rev=656630&view=rev
Log:
Take 2 of javascript compression.

This time we're using a php port of jsmin.c, it has a slightly lower compression
ratio then yuicompressort, but the overhead of starting a java app in the 
background
was way to high. This way it's actually quite functional and speedy.

All the compressed js is cached, so the first time a feature lib is called it 
will
have a slight delay compared to normal (0.5 seconds on my box), but all 
subsiquent
calls will be just as fast as before.

Using this method we save nearly 50% on the gadget html size


Added:
    incubator/shindig/trunk/php/src/common/JsMin.php
Modified:
    incubator/shindig/trunk/php/config.php
    incubator/shindig/trunk/php/src/common/HttpServlet.php
    incubator/shindig/trunk/php/src/common/RemoteContentRequest.php
    incubator/shindig/trunk/php/src/gadgets/GadgetContext.php
    incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
    incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php
    incubator/shindig/trunk/php/src/gadgets/JsLibrary.php
    incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php

Modified: incubator/shindig/trunk/php/config.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/config.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/config.php (original)
+++ incubator/shindig/trunk/php/config.php Thu May 15 05:39:15 2008
@@ -1,5 +1,24 @@
 <?
 /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ * 
+ */
+
+/*
  * I really detest such config files to be honest, why put configuration in a 
web document! 
  * But since PHP lacks a propper way to set application configurations, and 
any other method 
  * would be horribly slow (db, xml, ini files etc), so ... here's our 
config.php
@@ -20,10 +39,14 @@
        'token_cipher_key' => 'INSECURE_DEFAULT_KEY',
        'token_hmac_key' => 'INSECURE_DEFAULT_KEY',
 
+       // Compresses features javascript? can save upto 50% page size
+       'compress_javascript' => true,
+
        // Configurable CSS rules that are injected to the gadget page, 
        // be careful when adjusting these not to break most gadget's layouts :)
        'gadget_css' => 'body,td,div,span,p{font-family:arial,sans-serif;} a 
{color:#0000cc;}a:visited {color:#551a8b;}a:active {color:#ff0000;}body{margin: 
0px;padding: 0px;background-color:white;}',
-
+       // 'gadget_css' => 'body,td,div,span,p{font-family:arial,sans-serif;} 
body {background-color:#ffffff; font-family: arial, sans-serif; padding: 0px; 
margin: 0px;  font-size: 12px; color: #000000;}a, a:visited {color: 
#3366CC;text-decoration: none; }a:hover {color: #3366CC; text-decoration: 
underline;} input, select { border: 1px solid #bdc7d8;font-size: 11px;padding: 
3px;}',
+       
        // The html / javascript samples use a plain text demo token,
        // set this to false on anything resembling a real site
        'allow_plaintext_token' => true,
@@ -43,7 +66,7 @@
 
        // The data handlers for the social data, this is a list of class names
        // seperated by a , For example:
-       // 'handlers' => 'PartuzaHandler',
+       //'handlers' => 'PartuzaHandler',
        // if the value is empty, the defaults used in the example above will 
be used.
        'handlers' => '',
 
@@ -82,8 +105,7 @@
 
 /**
  * Abstracts how to retrieve configuration values so we can replace the
- * not so pretty $config array some day.
- *
+ * not so pretty $shindigConfig array some day.
  */
 class Config {
        static function get($key)

Modified: incubator/shindig/trunk/php/src/common/HttpServlet.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/HttpServlet.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/common/HttpServlet.php (original)
+++ incubator/shindig/trunk/php/src/common/HttpServlet.php Thu May 15 05:39:15 
2008
@@ -68,8 +68,8 @@
                                header("Expires: " . gmdate("D, d M Y H:i:s", 
time() + $this->cacheTime) . " GMT");
                                // Obey browsers (or proxy's) request to send a 
fresh copy if we recieve a no-cache pragma or cache-control request
                                if (! isset($_SERVER['HTTP_PRAGMA']) || ! 
strstr(strtolower($_SERVER['HTTP_PRAGMA']), 'no-cache') && (! 
isset($_SERVER['HTTP_CACHE_CONTROL']) || ! 
strstr(strtolower($_SERVER['HTTP_CACHE_CONTROL']), 'no-cache'))) {
-                                       // If the browser send us a E-TAG check 
if it matches (sha1 sum of content), if so send a not modified header instead 
of content
-                                       $etag = sha1($content);
+                                       // If the browser send us a E-TAG check 
if it matches (md5 sum of content), if so send a not modified header instead of 
content
+                                       $etag = md5($content);
                                        if 
(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == 
$etag) {
                                                header("ETag: \"$etag\"");
                                                if ($this->lastModified) {

Added: incubator/shindig/trunk/php/src/common/JsMin.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/JsMin.php?rev=656630&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/common/JsMin.php (added)
+++ incubator/shindig/trunk/php/src/common/JsMin.php Thu May 15 05:39:15 2008
@@ -0,0 +1,290 @@
+<?php
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns 
another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy of
+ * this software and associated documentation files (the "Software"), to deal 
in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies
+ * of the Software, and to permit persons to whom the Software is furnished to 
do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in 
all
+ * copies or substantial portions of the Software.
+ *
+ * The Software shall be used for Good, not Evil.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <[EMAIL PROTECTED]>
+ * @copyright 2002 Douglas Crockford <[EMAIL PROTECTED]> (jsmin.c)
+ * @copyright 2008 Ryan Grove <[EMAIL PROTECTED]> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JsMinException extends Exception {}
+
+class JsMin {
+  const ORD_LF    = 10;
+  const ORD_SPACE = 32;
+
+  protected $a           = '';
+  protected $b           = '';
+  protected $input       = '';
+  protected $inputIndex  = 0;
+  protected $inputLength = 0;
+  protected $lookAhead   = null;
+  protected $output      = '';
+
+  // -- Public Static Methods 
--------------------------------------------------
+
+  public static function minify($js) {
+    $jsmin = new JsMin($js);
+    return $jsmin->min();
+  }
+
+  // -- Public Instance Methods 
------------------------------------------------
+
+  public function __construct($input) {
+    $this->input       = str_replace("\r\n", "\n", $input);
+    $this->inputLength = strlen($this->input);
+  }
+
+  // -- Protected Instance Methods 
---------------------------------------------
+
+  protected function action($d) {
+    switch($d) {
+      case 1:
+        $this->output .= $this->a;
+
+      case 2:
+        $this->a = $this->b;
+
+        if ($this->a === "'" || $this->a === '"') {
+          for (;;) {
+            $this->output .= $this->a;
+            $this->a       = $this->get();
+
+            if ($this->a === $this->b) {
+              break;
+            }
+
+            if (ord($this->a) <= self::ORD_LF) {
+              throw new JsMinException('Unterminated string literal.');
+            }
+
+            if ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            }
+          }
+        }
+
+      case 3:
+        $this->b = $this->next();
+
+        if ($this->b === '/' && (
+            $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+            $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+            $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+          $this->output .= $this->a . $this->b;
+
+          for (;;) {
+            $this->a = $this->get();
+
+            if ($this->a === '/') {
+              break;
+            } elseif ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            } elseif (ord($this->a) <= self::ORD_LF) {
+              throw new JsMinException('Unterminated regular expression '.
+                  'literal.');
+            }
+
+            $this->output .= $this->a;
+          }
+
+          $this->b = $this->next();
+        }
+    }
+  }
+
+  protected function get() {
+    $c = $this->lookAhead;
+    $this->lookAhead = null;
+
+    if ($c === null) {
+      if ($this->inputIndex < $this->inputLength) {
+        $c = $this->input[$this->inputIndex];
+        $this->inputIndex += 1;
+      } else {
+        $c = null;
+      }
+    }
+
+    if ($c === "\r") {
+      return "\n";
+    }
+
+    if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+      return $c;
+    }
+
+    return ' ';
+  }
+
+  protected function isAlphaNum($c) {
+    return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+  }
+
+  protected function min() {
+    $this->a = "\n";
+    $this->action(3);
+
+    while ($this->a !== null) {
+      switch ($this->a) {
+        case ' ':
+          if ($this->isAlphaNum($this->b)) {
+            $this->action(1);
+          } else {
+            $this->action(2);
+          }
+          break;
+
+        case "\n":
+          switch ($this->b) {
+            case '{':
+            case '[':
+            case '(':
+            case '+':
+            case '-':
+              $this->action(1);
+              break;
+
+            case ' ':
+              $this->action(3);
+              break;
+
+            default:
+              if ($this->isAlphaNum($this->b)) {
+                $this->action(1);
+              }
+              else {
+                $this->action(2);
+              }
+          }
+          break;
+
+        default:
+          switch ($this->b) {
+            case ' ':
+              if ($this->isAlphaNum($this->a)) {
+                $this->action(1);
+                break;
+              }
+
+              $this->action(3);
+              break;
+
+            case "\n":
+              switch ($this->a) {
+                case '}':
+                case ']':
+                case ')':
+                case '+':
+                case '-':
+                case '"':
+                case "'":
+                  $this->action(1);
+                  break;
+
+                default:
+                  if ($this->isAlphaNum($this->a)) {
+                    $this->action(1);
+                  }
+                  else {
+                    $this->action(3);
+                  }
+              }
+              break;
+
+            default:
+              $this->action(1);
+              break;
+          }
+      }
+    }
+
+    return $this->output;
+  }
+
+  protected function next() {
+    $c = $this->get();
+
+    if ($c === '/') {
+      switch($this->peek()) {
+        case '/':
+          for (;;) {
+            $c = $this->get();
+
+            if (ord($c) <= self::ORD_LF) {
+              return $c;
+            }
+          }
+
+        case '*':
+          $this->get();
+
+          for (;;) {
+            switch($this->get()) {
+              case '*':
+                if ($this->peek() === '/') {
+                  $this->get();
+                  return ' ';
+                }
+                break;
+
+              case null:
+                throw new JsMinException('Unterminated comment.');
+            }
+          }
+
+        default:
+          return $c;
+      }
+    }
+
+    return $c;
+  }
+
+  protected function peek() {
+    $this->lookAhead = $this->get();
+    return $this->lookAhead;
+  }
+}
+

Modified: incubator/shindig/trunk/php/src/common/RemoteContentRequest.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/RemoteContentRequest.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/common/RemoteContentRequest.php (original)
+++ incubator/shindig/trunk/php/src/common/RemoteContentRequest.php Thu May 15 
05:39:15 2008
@@ -39,10 +39,10 @@
        }
 
        // returns a hash code which identifies this request, used for caching
-       // takes url and postbody into account for constructing the sha1 
checksum
+       // takes url and postbody into account for constructing the md5 checksum
        public function toHash()
        {
-               return sha1($this->url . $this->postBody);
+               return md5($this->url . $this->postBody);
        }
 
        public function getContentType()

Modified: incubator/shindig/trunk/php/src/gadgets/GadgetContext.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/GadgetContext.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/GadgetContext.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/GadgetContext.php Thu May 15 
05:39:15 2008
@@ -149,9 +149,9 @@
        {
                // Profiling showed 40% of the processing time was spend in the 
feature registry
                // So by caching this and making it a one time initialization, 
we almost double the performance  
-               if (! ($registry = 
$this->getCache()->get(sha1(Config::get('features_path'))))) {
+               if (! ($registry = 
$this->getCache()->get(md5(Config::get('features_path'))))) {
                        $registry = new 
GadgetFeatureRegistry(Config::get('features_path'));
-                       
$this->getCache()->set(sha1(Config::get('features_path')), $registry);
+                       
$this->getCache()->set(md5(Config::get('features_path')), $registry);
                }
                return $registry;
        }

Modified: incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php Thu May 
15 05:39:15 2008
@@ -22,11 +22,9 @@
        private $features = array();
        private $core = array();
        private $coreDone = false;
-       private $debug;
 
-       public function __construct($featurePath, $debug = false)
+       public function __construct($featurePath)
        {
-               $this->debug = $debug;
                $this->registerFeatures($featurePath);
        }
 
@@ -36,7 +34,7 @@
                        return;
                }
                $coreDeps = array();
-               $loader = new JsFeatureLoader($this->debug);
+               $loader = new JsFeatureLoader();
                $jsFeatures = $loader->loadFeatures($featurePath, $this);
                if (! $this->coreDone) {
                        foreach ($jsFeatures as $entry) {

Modified: incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php Thu May 15 
05:39:15 2008
@@ -19,12 +19,6 @@
  */
 
 class JsFeatureLoader {
-       private $debug;
-
-       public function __construct($debug)
-       {
-               $this->debug = $debug;
-       }
 
        public function loadFeatures($path, $registry)
        {

Modified: incubator/shindig/trunk/php/src/gadgets/JsLibrary.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/JsLibrary.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/JsLibrary.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/JsLibrary.php Thu May 15 05:39:15 
2008
@@ -36,23 +36,23 @@
        {
                return $this->type;
        }
-       
-       public function readfile()
-       {
-               // hack to bypass having the script in memory and dump it 
directly to stdout
-               if (!$this->loaded && $this->type == 'FILE') {
-                       readfile($this->content);
-                       echo "\n";
-               } else {
-                       // a call to getContent was already made so we have it 
in memory, just echo it then
-                       echo $this->content;
-               }
-       }
 
        public function getContent()
        {
                if (!$this->loaded && $this->type == 'FILE') {
-                       $this->content = JsLibrary::loadData($this->content, 
$this->type);
+                       if (Config::get('compress_javascript')) {
+                               $dataCache = Config::get('data_cache');
+                               $dataCache = new $dataCache();
+                               if (!($content = 
$dataCache->get(md5($this->content)))) {
+                                       $content = 
JSMin::minify(JsLibrary::loadData($this->content, $this->type));
+                                       $dataCache->set(md5($this->content), 
$content);
+                                       $this->content = $content;
+                               } else {
+                                       $this->content = $content;
+                               }
+                       } else {
+                               $this->content = 
JsLibrary::loadData($this->content, $this->type);
+                       }
                        $this->loaded = true;
                }
                return $this->content;

Modified: 
incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php 
(original)
+++ incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php Thu 
May 15 05:39:15 2008
@@ -160,11 +160,11 @@
                                // servlet. We should probably inline external 
JS as well.
                                $externJs .= sprintf($externFmt, 
$library->getContent()) . "\n";
                        } else if ($type == 'INLINE') {
-                               $library->readfile();
+                               echo $library->getContent();
                        } else {
                                // FILE or RESOURCE
                                if ($forcedLibs == null) {
-                                       $library->readfile();
+                                       echo $library->getContent();
                                }
                                // otherwise it was already included by 
config.forceJsLibs.
                        }


Reply via email to