1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-23 06:02:51 +02:00

Merge pull request #549 from mrclay/scssphp

add scss support via leafo/scssphp
This commit is contained in:
Elan Ruusamäe
2016-10-16 13:50:58 +03:00
committed by GitHub
7 changed files with 264 additions and 3 deletions

View File

@@ -34,6 +34,7 @@
}, },
"require-dev": { "require-dev": {
"leafo/lessphp": "~0.4.0", "leafo/lessphp": "~0.4.0",
"leafo/scssphp": "^0.3.0",
"meenie/javascript-packer": "~1.1", "meenie/javascript-packer": "~1.1",
"phpunit/phpunit": "4.8.*", "phpunit/phpunit": "4.8.*",
"tedivm/jshrink": "~1.1.0" "tedivm/jshrink": "~1.1.0"

View File

@@ -0,0 +1,175 @@
<?php
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Server;
use Leafo\ScssPhp\Version;
/**
* Class for using SCSS files
*
* @link https://github.com/leafo/scssphp/
*/
class Minify_ScssCssSource extends Minify_Source {
/**
* @var Minify_CacheInterface
*/
private $cache;
/**
* Parsed SCSS cache object
*
* @var array
*/
private $parsed;
/**
* @inheritdoc
*/
public function __construct(array $spec, Minify_CacheInterface $cache)
{
parent::__construct($spec);
$this->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.
*/
private 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();
// 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;
$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,
);
}
}

View File

@@ -67,9 +67,13 @@ class Minify_Source_Factory {
throw new InvalidArgumentException("fileChecker option is not callable"); throw new InvalidArgumentException("fileChecker option is not callable");
} }
$this->setHandler('~\.less$~i', function ($spec) use ($cache) { $this->setHandler('~\.less$~i', function ($spec) use ($cache) {
return new Minify_LessCssSource($spec, $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) { $this->setHandler('~\.(js|css)$~i', function ($spec) {
return new Minify_Source($spec); return new Minify_Source($spec);

40
tests/ScssSourceTest.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
class ScssSourceTest extends TestCase
{
public function setUp()
{
$this->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&amp;{$max}", $res);
}
}

View File

@@ -0,0 +1,8 @@
/* lesstest2.scss */
a.included {
color: $primary-color;
font-size: 13px;
text-decoration: none;
}

View File

@@ -9,4 +9,8 @@ return array(
'less' => array( 'less' => array(
'//_test_files/main.less', '//_test_files/main.less',
), ),
'scss' => array(
'//_test_files/main.scss',
),
); );

View File

@@ -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.
*/