diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index 9ed7a0753..6496646a3 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -794,6 +794,27 @@ form: validate: type: bool + assets.precompress: + type: toggle + label: PLUGIN_ADMIN.PRECOMPRESS_ASSET + help: PLUGIN_ADMIN.PRECOMPRESS_ASSET_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + assets.precompress_level: + type: text + size: x-small + label: PLUGIN_ADMIN.PRECOMPRESS_ASSET_LEVEL + help: PLUGIN_ADMIN.PRECOMPRESS_ASSET_LEVEL_HELP + validate: + type: number + min: 1 + max: 9 + assets.enable_asset_timestamp: type: toggle label: PLUGIN_ADMIN.ENABLED_TIMESTAMPS_ON_ASSETS diff --git a/system/config/system.yaml b/system/config/system.yaml index a6110c4a8..b3f1a4c95 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -102,6 +102,8 @@ assets: # Configuration for Assets Mana js_pipeline_include_externals: true # Include external URLs in the pipeline by default js_pipeline_before_excludes: true # Render the pipeline before any excluded files js_minify: true # Minify the JS during pipelining + precompress: false # Precompress assets with GZip + precompress_level: 9 # Compression level to use (1 = fastest, 9 = highest) enable_asset_timestamp: false # Enable asset timestamps collections: jquery: system://assets/jquery/jquery-2.x.min.js diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index a329cd618..79d4bdbf4 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -90,6 +90,10 @@ class Assets protected $css_no_pipeline = []; protected $js_no_pipeline = []; + // Default values for asset precompression. + protected $precompress = false; + protected $precompress_level = 9; + /** * Assets constructor. * @@ -170,6 +174,15 @@ public function config(array $config) $this->js_minify = $config['js_minify']; } + // Asset precompression + if (isset($config['precompress'])) { + $this->precompress = $config['precompress']; + } + + if (isset($config['precompress_level'])) { + $this->precompress_level = $config['precompress_level']; + } + // Set collections if (isset($config['collections']) && is_array($config['collections'])) { $this->collections = $config['collections']; @@ -750,6 +763,10 @@ protected function pipelineCss($group = 'head', $returnURL = true) // Write non-pipeline files out if (!empty($this->css_no_pipeline)) { file_put_contents($this->assets_dir . $inline_file, json_encode($this->css_no_pipeline)); + + if ($this->precompress) { + $this->compressFile($this->assets_dir . $inline_file); + } } @@ -774,6 +791,10 @@ protected function pipelineCss($group = 'head', $returnURL = true) if (strlen(trim($buffer)) > 0) { file_put_contents($this->assets_dir . $file, $buffer); + if ($this->precompress) { + $this->compressFile($this->assets_dir . $file); + } + if ($returnURL) { return $relative_path . $this->getTimestamp(); } @@ -843,6 +864,10 @@ protected function pipelineJs($group = 'head', $returnURL = true) // Write non-pipeline files out if (!empty($this->js_no_pipeline)) { file_put_contents($this->assets_dir . $inline_file, json_encode($this->js_no_pipeline)); + + if ($this->precompress) { + $this->compressFile($this->assets_dir . $inline_file); + } } // Concatenate files @@ -857,6 +882,10 @@ protected function pipelineJs($group = 'head', $returnURL = true) if (strlen(trim($buffer)) > 0) { file_put_contents($this->assets_dir . $file, $buffer); + if ($this->precompress) { + $this->compressFile($this->assets_dir . $file); + } + if ($returnURL) { return $relative_path . $this->getTimestamp(); } @@ -868,6 +897,49 @@ protected function pipelineJs($group = 'head', $returnURL = true) } } + /** + * Compresses the given file. + * + * @param string $filename File to compress + * @return bool true if succesful, false if not. + */ + protected function compressFile($filename = null) + { + // Test if we have gzencode() + if (!function_exists('gzencode')) { + return false; + } + + // Test if $filename is set + if (!empty($filename)) { + + // Test if the source file exists and can be read + if (!is_readable($filename)) { + return false; + } + + // Test if we can write to the target file + $fp = fopen($filename . ".gz", "w"); + if (!$fp) { + return false; + } + + // Load source file, gzencode it, and write it out + $written = fwrite($fp, gzencode(file_get_contents($filename), $this->precompress_level)); + fclose($fp); + + if ($written === false) { + return false; + } + + // Make the file modification time identical to that of the source file + touch($filename . ".gz", filemtime($filename)); + + return true; + } + return false; + } + /** * Return the array of all the registered CSS assets * If a $key is provided, it will try to return only that asset