From fdc69a369e28e477d98c92b7692570435b6df740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Oct 2016 16:32:11 +0300 Subject: [PATCH] add scss support via leafo/scssphp --- composer.json | 1 + lib/Minify/ScssCssSource.php | 169 ++++++++++++++++++++++++++++++++++ lib/Minify/Source/Factory.php | 10 +- 3 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 lib/Minify/ScssCssSource.php diff --git a/composer.json b/composer.json index f7e6c2e..04c54ee 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ }, "require-dev": { "leafo/lessphp": "~0.4.0", + "leafo/scssphp": "^0.6.6", "meenie/javascript-packer": "~1.1", "phpunit/phpunit": "4.8.*", "tedivm/jshrink": "~1.1.0" diff --git a/lib/Minify/ScssCssSource.php b/lib/Minify/ScssCssSource.php new file mode 100644 index 0000000..cf40bc1 --- /dev/null +++ b/lib/Minify/ScssCssSource.php @@ -0,0 +1,169 @@ +cache = $cache; + } + + /** + * Get last modified of all parsed files + * + * @return int + */ + public function getLastModified() + { + $cache = $this->getCache(); + + return $cache['updated']; + } + + /** + * Get content + * + * @return string + */ + public function getContent() + { + $cache = $this->getCache(); + + return $cache['content']; + } + + /** + * 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}_scss_{$md5}"; + } + + /** + * Get SCSS cache object + * + * Runs the compilation if needed + * + * Implements Leafo\ScssPhp\Server logic because we need to get parsed files without parsing actual content + * + * @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); + } + } + + $input = $cache ? $cache : $this->filepath; + + if ($this->cacheIsStale($cache)) { + $cache = $this->compile($this->filepath); + } + + if (!is_array($input) || $cache['updated'] > $input['updated']) { + $this->cache->store($cacheId, serialize($cache)); + } + + return $this->parsed = $cache; + } + + /** + * Determine whether .scss file needs to be re-compiled. + * + * @param array $cache Cache object + * + * @return boolean True if compile required. + */ + public function cacheIsStale($cache) + { + if (!$cache) { + return true; + } + + $updated = $cache['updated']; + foreach ($cache['files'] as $import => $mtime) { + $filemtime = filemtime($import); + + if ($filemtime !== $mtime || $filemtime > $updated) { + return true; + } + } + + return false; + } + + /** + * Compile .scss file + * + * @param string $filename Input path (.scss) + * + * @see Server::compile() + * @return array meta data result of the compile + */ + private function compile($filename) + { + $start = microtime(true); + $scss = new Compiler(); + $css = $scss->compile(file_get_contents($filename), $filename); + $elapsed = round((microtime(true) - $start), 4); + + $v = Version::VERSION; + $ts = date('r', $start); + $css = "/* compiled by scssphp $v on $ts (${elapsed}s) */\n\n" . $css; + + $imports = $scss->getParsedFiles(); + + $updated = 0; + foreach ($imports as $mtime) { + $updated = max($updated, $mtime); + } + + return array( + 'elapsed' => $elapsed, // statistic, can be dropped + 'updated' => $updated, + 'content' => $css, + 'files' => $imports, + ); + } +} diff --git a/lib/Minify/Source/Factory.php b/lib/Minify/Source/Factory.php index 7033179..71d7f08 100644 --- a/lib/Minify/Source/Factory.php +++ b/lib/Minify/Source/Factory.php @@ -67,9 +67,13 @@ 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('~\.less$~i', function ($spec) use ($cache) { + return new Minify_LessCssSource($spec, $cache); + }); + + $this->setHandler('~\.scss~i', function ($spec) use ($cache) { + return new Minify_ScssCssSource($spec, $cache); + }); $this->setHandler('~\.(js|css)$~i', function ($spec) { return new Minify_Source($spec);