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 1/6] 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); From b5a0ed3e3a989964e0b255870d5a9af18c2035fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Oct 2016 16:52:58 +0300 Subject: [PATCH 2/6] ci: bump php version so deps could be installed on travis for php 5.3 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e1a2519..bb067ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,8 @@ cache: - vendor install: + # set low version, so deps can be installed on 5.3 + - composer config platform.php 5.4 - composer update --no-interaction --prefer-source script: From ae1fdf4a30608e111454d2f99d7243b213116dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Thu, 13 Oct 2016 12:18:52 +0300 Subject: [PATCH 3/6] use lower scssphp version for php 5.3 compatibility the functionality we are using is present --- .travis.yml | 2 -- composer.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb067ae..e1a2519 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,6 @@ cache: - vendor install: - # set low version, so deps can be installed on 5.3 - - composer config platform.php 5.4 - composer update --no-interaction --prefer-source script: diff --git a/composer.json b/composer.json index 04c54ee..478bb6b 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ }, "require-dev": { "leafo/lessphp": "~0.4.0", - "leafo/scssphp": "^0.6.6", + "leafo/scssphp": "^0.3.0", "meenie/javascript-packer": "~1.1", "phpunit/phpunit": "4.8.*", "tedivm/jshrink": "~1.1.0" From 3014900cd4e4089a82d8db0eaa6de78724ca70c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Thu, 13 Oct 2016 12:20:50 +0300 Subject: [PATCH 4/6] add base directory of input file to import path this is needed for @import to be able to resolve included files --- lib/Minify/ScssCssSource.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Minify/ScssCssSource.php b/lib/Minify/ScssCssSource.php index cf40bc1..7da4a23 100644 --- a/lib/Minify/ScssCssSource.php +++ b/lib/Minify/ScssCssSource.php @@ -145,7 +145,13 @@ class Minify_ScssCssSource extends Minify_Source { { $start = microtime(true); $scss = new Compiler(); - $css = $scss->compile(file_get_contents($filename), $filename); + + // set import path directory the input filename resides + // otherwise @import statements will not find the files + // and will treat the @import line as css import + $scss->setImportPaths(dirname($filename)); + + $css = $scss->compile(file_get_contents($filename), $filename); $elapsed = round((microtime(true) - $start), 4); $v = Version::VERSION; From 2bd69ca5b1138a6561945789abb4d03af2701127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Thu, 13 Oct 2016 12:21:09 +0300 Subject: [PATCH 5/6] test scssphp functionality tested cache dependencies --- tests/ScssSourceTest.php | 40 +++++++++++++++++++ tests/_test_files/_included.scss | 8 ++++ tests/_test_files/htmlHelper_groupsConfig.php | 4 ++ tests/_test_files/main.scss | 29 ++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 tests/ScssSourceTest.php create mode 100644 tests/_test_files/_included.scss create mode 100644 tests/_test_files/main.scss diff --git a/tests/ScssSourceTest.php b/tests/ScssSourceTest.php new file mode 100644 index 0000000..a1581ef --- /dev/null +++ b/tests/ScssSourceTest.php @@ -0,0 +1,40 @@ +realDocRoot = $_SERVER['DOCUMENT_ROOT']; + $_SERVER['DOCUMENT_ROOT'] = self::$document_root; + } + + /** + * @link https://github.com/mrclay/minify/issues/500 + */ + public function testTimestamp() + { + $baseDir = self::$test_files; + + $mainLess = "$baseDir/main.scss"; + $includedLess = "$baseDir/_included.scss"; + + // touch timestamp with 1s difference + touch($mainLess); + sleep(1); + touch($includedLess); + + $mtime1 = filemtime($mainLess); + var_dump($mtime1); + $mtime2 = filemtime($includedLess); + var_dump($mtime2); + + $max = max($mtime1, $mtime2); + + $options = array( + 'groupsConfigFile' => "$baseDir/htmlHelper_groupsConfig.php", + ); + $res = Minify_HTML_Helper::getUri('scss', $options); + + $this->assertEquals("/min/g=scss&{$max}", $res); + } +} \ No newline at end of file diff --git a/tests/_test_files/_included.scss b/tests/_test_files/_included.scss new file mode 100644 index 0000000..df8d371 --- /dev/null +++ b/tests/_test_files/_included.scss @@ -0,0 +1,8 @@ +/* lesstest2.scss */ + + +a.included { + color: $primary-color; + font-size: 13px; + text-decoration: none; +} diff --git a/tests/_test_files/htmlHelper_groupsConfig.php b/tests/_test_files/htmlHelper_groupsConfig.php index cf67275..cbf8a9d 100644 --- a/tests/_test_files/htmlHelper_groupsConfig.php +++ b/tests/_test_files/htmlHelper_groupsConfig.php @@ -9,4 +9,8 @@ return array( 'less' => array( '//_test_files/main.less', ), + + 'scss' => array( + '//_test_files/main.scss', + ), ); diff --git a/tests/_test_files/main.scss b/tests/_test_files/main.scss new file mode 100644 index 0000000..80bc0ea --- /dev/null +++ b/tests/_test_files/main.scss @@ -0,0 +1,29 @@ +/*! preserving comment */ + +// Variable +$primary-color: hotpink; + +// Mixin +@mixin border-radius($radius) { + -webkit-border-radius: $radius; + -moz-border-radius: $radius; + border-radius: $radius; +} + +.my-element { + color: $primary-color; + width: 100%; + overflow: hidden; +} + +.my-other-element { + @include border-radius(6px); +} + +/* import include -> */ +@import "_included"; +/* <- import included */ + +/* + a normal comment. +*/ \ No newline at end of file From 035183b2b8a2d6453960fa9cba85b7ae86fa4fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Thu, 13 Oct 2016 14:40:21 +0300 Subject: [PATCH 6/6] cacheIsStale is not public --- lib/Minify/ScssCssSource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Minify/ScssCssSource.php b/lib/Minify/ScssCssSource.php index 7da4a23..038a03f 100644 --- a/lib/Minify/ScssCssSource.php +++ b/lib/Minify/ScssCssSource.php @@ -115,7 +115,7 @@ class Minify_ScssCssSource extends Minify_Source { * * @return boolean True if compile required. */ - public function cacheIsStale($cache) + private function cacheIsStale($cache) { if (!$cache) { return true;