diff --git a/framework/base/ViewContent.php b/framework/base/ViewContent.php index e5a1a06..c7a3bc4 100644 --- a/framework/base/ViewContent.php +++ b/framework/base/ViewContent.php @@ -39,6 +39,7 @@ class ViewContent extends Component public function reset() { + $this->assetBundles = null; $this->title = null; $this->metaTags = null; $this->linkTags = null; diff --git a/framework/web/AssetBundle.php b/framework/web/AssetBundle.php index 124f5e6..f82173b 100644 --- a/framework/web/AssetBundle.php +++ b/framework/web/AssetBundle.php @@ -122,11 +122,13 @@ class AssetBundle extends Object list ($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions); } + $converter = $am->getConverter(); + foreach ($this->js as $js => $options) { $js = is_string($options) ? $options : $js; if (strpos($js, '/') !== 0 && strpos($js, '://') === false) { if (isset($this->basePath, $this->baseUrl)) { - $js = $am->processAsset(ltrim($js, '/'), $this->basePath, $this->baseUrl); + $js = $converter->convert(ltrim($js, '/'), $this->basePath, $this->baseUrl); } else { throw new InvalidConfigException('Both of the "baseUrl" and "basePath" properties must be set.'); } @@ -137,7 +139,7 @@ class AssetBundle extends Object $css = is_string($options) ? $options : $css; if (strpos($css, '//') !== 0 && strpos($css, '://') === false) { if (isset($this->basePath, $this->baseUrl)) { - $css = $am->processAsset(ltrim($css, '/'), $this->basePath, $this->baseUrl); + $css = $converter->convert(ltrim($css, '/'), $this->basePath, $this->baseUrl); } else { throw new InvalidConfigException('Both of the "baseUrl" and "basePath" properties must be set.'); } diff --git a/framework/web/AssetConverter.php b/framework/web/AssetConverter.php new file mode 100644 index 0000000..26cc59b --- /dev/null +++ b/framework/web/AssetConverter.php @@ -0,0 +1,45 @@ + + * @since 2.0 + */ +class AssetConverter extends Component implements IAssetConverter +{ + public $commands = array( + 'less' => array('css', 'lessc %s %s'), + 'scss' => array('css', 'sass %s %s'), + 'sass' => array('css', 'sass %s %s'), + 'styl' => array('js', 'stylus < %s > %s'), + ); + + public function convert($asset, $basePath, $baseUrl) + { + $pos = strrpos($asset, '.'); + if ($pos !== false) { + $ext = substr($asset, $pos + 1); + if (isset($this->commands[$ext])) { + list ($ext, $command) = $this->commands[$ext]; + $result = substr($asset, 0, $pos + 1) . $ext; + if (@filemtime("$basePath/$result") < filemtime("$basePath/$asset")) { + $output = array(); + $command = sprintf($command, "$basePath/$asset", "$basePath/$result"); + exec($command, $output); + Yii::info("Converted $asset into $result: " . implode("\n", $output), __METHOD__); + return "$baseUrl/$result"; + } + } + } + return "$baseUrl/$asset"; + } +} \ No newline at end of file diff --git a/framework/web/AssetManager.php b/framework/web/AssetManager.php index 72dd06b..c4ad385 100644 --- a/framework/web/AssetManager.php +++ b/framework/web/AssetManager.php @@ -26,13 +26,6 @@ class AssetManager extends Component */ public $bundles; /** - * @var array list of asset processors. An asset processor will convert a special type of asset files - * (e.g. LESS, Sass, TypeScript) into JS or CSS files. The array keys are the file extension names - * (e.g. "less", "sass", "ts"), and the array values are the corresponding configuration arrays - * for creating the processor objects. - */ - public $processors; - /** * @return string the root directory storing the published asset files. */ public $basePath = '@wwwroot/assets'; @@ -139,26 +132,26 @@ class AssetManager extends Component return $this->bundles[$name]; } + private $_converter; + /** - * Processes the given asset file and returns a URL to the processed one. - * This method can be overwritten to support various types of asset files, such as LESS, Sass, TypeScript. - * @param string $asset the asset file path to be processed. The file path is relative - * to $basePath, and it may contain forward slashes to indicate sub-directories (e.g. "js/main.js"). - * @param string $basePath the directory that contains the asset file. - * @param string $baseUrl the corresponding URL of $basePath. - * @return string the processed asset file path. + * @return IAssetConverter */ - public function processAsset($asset, $basePath, $baseUrl) + public function getConverter() { - $ext = pathinfo($asset, PATHINFO_EXTENSION); - if (isset($this->processors[$ext])) { - if (is_array($this->processors[$ext])) { - $this->processors[$ext] = Yii::createObject($this->processors[$ext]); - } - return $this->processors[$ext]->process($asset, $basePath, $baseUrl); - } else { - return $baseUrl . '/' . $asset; + if ($this->_converter === null) { + $this->_converter = Yii::createObject(array( + 'class' => 'yii\\web\\AssetConverter', + )); + } elseif (is_array($this->_converter) || is_string($this->_converter)) { + $this->_converter = Yii::createObject($this->_converter); } + return $this->_converter; + } + + public function setConverter($value) + { + $this->_converter = $value; } /** diff --git a/framework/web/IAssetConverter.php b/framework/web/IAssetConverter.php new file mode 100644 index 0000000..994cb2f --- /dev/null +++ b/framework/web/IAssetConverter.php @@ -0,0 +1,17 @@ + + * @since 2.0 + */ +interface IAssetConverter +{ + public function convert($asset, $basePath, $baseUrl); +} \ No newline at end of file