From 16069cc0c05b4afeb5e8a78a7ff6eea881249766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 27 Sep 2014 16:18:23 +0300 Subject: [PATCH] lesscss integration. #112 --- composer.json | 14 +++- min/index.php | 2 +- min/lib/Minify/Controller/MinApp.php | 2 +- min/lib/Minify/LessCssSource.php | 107 +++++++++++++++++++++++++++ min/lib/Minify/Source.php | 1 + min/lib/Minify/Source/Factory.php | 8 +- min/quick-test.less | 12 +++ min/quick-testinc.less | 20 +++++ 8 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 min/lib/Minify/LessCssSource.php create mode 100644 min/quick-test.less create mode 100644 min/quick-testinc.less diff --git a/composer.json b/composer.json index 701894f..3bfb17d 100644 --- a/composer.json +++ b/composer.json @@ -16,11 +16,21 @@ "issues": "http://code.google.com/p/minify/issues/list", "wiki": "http://code.google.com/p/minify/w/list" }, + "autoload": { + "classmap": ["min/lib/"] + }, "require": { "php": ">=5.2.1", "ext-pcre": "*" }, - "autoload": { - "classmap": ["min/lib/"] + "require-dev": { + "leafo/lessphp": "~0.4.0", + "meenie/javascript-packer": "~1.1", + "tubalmartin/cssmin": "~2.4.8" + }, + "suggest": { + "leafo/lessphp": "LESS support", + "meenie/javascript-packer": "Keep track of the Packer PHP port using Composer", + "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" } } diff --git a/min/index.php b/min/index.php index 783bbea..f23d508 100644 --- a/min/index.php +++ b/min/index.php @@ -94,7 +94,7 @@ if ($env->get('f') || null !== $env->get('g')) { if (isset($min_serveOptions['minApp']['noMinPattern'])) { $sourceFactoryOptions['noMinPattern'] = $min_serveOptions['minApp']['noMinPattern']; } - $sourceFactory = new Minify_Source_Factory($env, $sourceFactoryOptions); + $sourceFactory = new Minify_Source_Factory($env, $sourceFactoryOptions, $cache); $min_serveController = new Minify_Controller_MinApp($env, $sourceFactory); } diff --git a/min/lib/Minify/Controller/MinApp.php b/min/lib/Minify/Controller/MinApp.php index 9321fe2..e2f4b72 100644 --- a/min/lib/Minify/Controller/MinApp.php +++ b/min/lib/Minify/Controller/MinApp.php @@ -93,7 +93,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { // respond to. if (// verify at least one file, files are single comma separated, // and are all same extension - ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $get['f'], $m) + ! preg_match('/^[^,]+\\.(css|less|js)(?:,[^,]+\\.\\1)*$/', $get['f'], $m) // no "//" || strpos($get['f'], '//') !== false // no "\" diff --git a/min/lib/Minify/LessCssSource.php b/min/lib/Minify/LessCssSource.php new file mode 100644 index 0000000..e887706 --- /dev/null +++ b/min/lib/Minify/LessCssSource.php @@ -0,0 +1,107 @@ +cache = $cache; + } + + /** + * Get last modified of all parsed files + * + * @return int + */ + public function getLastModified() { + $cache = $this->getCache(); + + $lastModified = 0; + foreach ($cache['files'] as $mtime) { + $lastModified = max($lastModified, $mtime); + + } + return $lastModified; + } + + /** + * Get content + * + * @return string + */ + public function getContent() { + $cache = $this->getCache(); + + return $cache['compiled']; + } + + /** + * Get lessphp cache object + * + * @return array + */ + private function getCache() { + // cache for single run + // so that getLastModified and getContent in single request do not add additional cache roundtrips (i.e memcache) + if (isset($this->parsed)) { + return $this->parsed; + } + + // check from cache first + $cache = null; + $cacheId = $this->getCacheId(); + if ($this->cache->isValid($cacheId, 0)) { + if ($cache = $this->cache->fetch($cacheId)) { + $cache = unserialize($cache); + } + } + + $less = $this->getCompiler(); + $input = $cache ? $cache : $this->filepath; + $cache = $less->cachedCompile($input); + + if (!is_array($input) || $cache['updated'] > $input['updated']) { + $this->cache->store($cacheId, serialize($cache)); + } + + return $this->parsed = $cache; + } + + /** + * Make a unique cache id for for this source. + * + * @param string $prefix + * + * @return string + */ + private function getCacheId($prefix = 'minify') { + $md5 = md5($this->filepath); + return "{$prefix}_less_{$md5}"; + } + + /** + * Get instance of less compiler + * + * @return lessc + */ + private function getCompiler() { + $less = new lessc(); + // do not spend CPU time letting less doing minify + $less->setPreserveComments(true); + return $less; + } +} diff --git a/min/lib/Minify/Source.php b/min/lib/Minify/Source.php index 86091a0..34eff47 100644 --- a/min/lib/Minify/Source.php +++ b/min/lib/Minify/Source.php @@ -72,6 +72,7 @@ class Minify_Source implements Minify_SourceInterface { switch ($ext) { case 'js' : $this->contentType = Minify::TYPE_JS; break; + case 'less' : // fallthrough case 'css' : $this->contentType = Minify::TYPE_CSS; break; case 'htm' : // fallthrough diff --git a/min/lib/Minify/Source/Factory.php b/min/lib/Minify/Source/Factory.php index 22cfcb1..4f926ae 100644 --- a/min/lib/Minify/Source/Factory.php +++ b/min/lib/Minify/Source/Factory.php @@ -41,7 +41,7 @@ class Minify_Source_Factory { * moves back, this should not be needed. * */ - public function __construct(Minify_Env $env, array $options = array()) + public function __construct(Minify_Env $env, array $options = array(), Minify_CacheInterface $cache = null) { $this->env = $env; $this->options = array_merge(array( @@ -63,6 +63,10 @@ class Minify_Source_Factory { throw new InvalidArgumentException("fileChecker option is not callable"); } + $this->setHandler('~\.less$~i', function ($spec) use ($cache) { + return new Minify_LessCssSource($spec, $cache); + }); + $this->setHandler('~\.(js|css)$~i', function ($spec) { return new Minify_Source($spec); }); @@ -142,7 +146,7 @@ class Minify_Source_Factory { $basename = basename($spec['filepath']); if ($this->options['noMinPattern'] && preg_match($this->options['noMinPattern'], $basename)) { - if (preg_match('~\.css$~i', $basename)) { + if (preg_match('~\.(css|less)$~i', $basename)) { $spec['minifyOptions']['compress'] = false; // we still want URI rewriting to work for CSS } else { diff --git a/min/quick-test.less b/min/quick-test.less new file mode 100644 index 0000000..0704552 --- /dev/null +++ b/min/quick-test.less @@ -0,0 +1,12 @@ +/*! This file exists only for testing a Minify installation. It's content is not used. + * + * http://example.org/min/f=min/quick-test.less + */ + +// LESS import statement shares syntax with the CSS import statement. +// If the file being imported ends in a .less extension, or no extension, then it is treated as a LESS +// import. Otherwise it is left alone and outputted directly. +// http://leafo.net/lessphp/docs/#import +@import "quick-test.css"; + +@import "quick-testinc.less"; \ No newline at end of file diff --git a/min/quick-testinc.less b/min/quick-testinc.less new file mode 100644 index 0000000..c1c33bc --- /dev/null +++ b/min/quick-testinc.less @@ -0,0 +1,20 @@ +@base: 24px; +@border-color: #B2B; + +.underline { border-bottom: 1px solid green } + +#header { + color: black; + border: 1px solid @border-color + #222222; + + .navigation { + font-size: @base / 2; + a { + .underline; + } + } + .logo { + width: 300px; + :hover { text-decoration: none } + } +} \ No newline at end of file