Skip to content
This repository has been archived by the owner on Apr 8, 2022. It is now read-only.

Commit

Permalink
MDL-40995 simplify minify integration and fix all known issues
Browse files Browse the repository at this point in the history
  • Loading branch information
skodak committed Aug 3, 2013
1 parent 7c3943a commit 6b32d6b
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 160 deletions.
149 changes: 149 additions & 0 deletions lib/classes/minify.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* JS and CSS compression.
*
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

/**
* Collection of JS and CSS compression methods.
*/
class core_minify {
/**
* Minify JS code.
*
* @param string $content
* @return string minified JS code
*/
public static function js($content) {
global $CFG;
require_once("$CFG->libdir/minify/lib/JSMinPlus.php");

try {
ob_start(); // JSMinPlus just echos errors, weird...
$compressed = JSMinPlus::minify($content);
if ($compressed !== false) {
ob_end_clean();
return $compressed;
}
$error = ob_get_clean();

} catch (Exception $e) {
ob_end_clean();
$error = $e->getMessage();
}

$return = <<<EOD
try {console.log('Error: Minimisation of JavaScript failed!');} catch (e) {}
// Error: $error
// Problem detected during JavaScript minimisation, please review the following code
// =================================================================================
EOD;

return $return.$content;
}

/**
* Minify JS files.
*
* @param array $files
* @return string minified JS code
*/
public static function js_files(array $files) {
if (empty($files)) {
return '';
}

$compressed = array();
foreach ($files as $file) {
$content = file_get_contents($file);
if ($content === false) {
$compressed[] = "\n\n// Cannot read JS file ".basename(dirname(dirname($file))).'/'.basename(dirname($file)).'/'.basename($file)."\n\n";
continue;
}
$compressed[] = self::js($content);
}

return implode("\n", $compressed);
}

/**
* Minify CSS code.
*
* @param string $content
* @return string minified CSS
*/
public static function css($content) {
global $CFG;
require_once("$CFG->libdir/minify/lib/Minify/CSS/Compressor.php");

$error = 'unknown';
try {
$compressed = Minify_CSS_Compressor::process($content);
if ($compressed !== false) {
return $compressed;
}

} catch (Exception $e) {
$error = $e->getMessage();
}

$return = <<<EOD
/* Error: $error */
/* Problem detected during CSS minimisation, please review the following code */
/* ========================================================================== */
EOD;

return $return.$content;
}

/**
* Minify CSS files.
*
* @param array $files
* @return string minified CSS code
*/
public static function css_files(array $files) {
if (empty($files)) {
return '';
}

$compressed = array();
foreach ($files as $file) {
$content = file_get_contents($file);
if ($content === false) {
$compressed[] = "\n\n/* Cannot read CSS file ".basename(dirname(dirname($file))).'/'.basename(dirname($file)).'/'.basename($file)."*/\n\n";
continue;
}
$compressed[] = self::css($content);
}

return implode("\n", $compressed);
}
}
88 changes: 8 additions & 80 deletions lib/csslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

// NOTE: do not verify MOODLE_INTERNAL here, this is used from themes too
defined('MOODLE_INTERNAL') || die();

/**
* Stores CSS in a file at the given path.
Expand All @@ -43,6 +43,11 @@
function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk = false, $chunkurl = null) {
global $CFG;

$css = '';
foreach ($cssfiles as $file) {
$css .= file_get_contents($file)."\n";
}

// Check if both the CSS optimiser is enabled and the theme supports it.
if (!empty($CFG->enablecssoptimiser) && $theme->supportscssoptimisation) {
// This is an experimental feature introduced in Moodle 2.3
Expand All @@ -51,10 +56,6 @@ function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk =
// the CSS before it is cached removing excess styles and rules and stripping
// out any extraneous content such as comments and empty rules.
$optimiser = new css_optimiser;
$css = '';
foreach ($cssfiles as $file) {
$css .= file_get_contents($file)."\n";
}
$css = $theme->post_process($css);
$css = $optimiser->process($css);

Expand All @@ -73,7 +74,8 @@ function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk =
// However it has the distinct disadvantage of having to minify the CSS
// before running the post process functions. Potentially things may break
// here if theme designers try to push things with CSS post processing.
$css = $theme->post_process(css_minify_css($cssfiles));
$css = $theme->post_process($css);
$css = core_minify::css($css);
}

clearstatcache();
Expand Down Expand Up @@ -294,80 +296,6 @@ function css_send_css_not_found() {
die('CSS was not found, sorry.');
}

/**
* Uses the minify library to compress CSS.
*
* This is used if $CFG->enablecssoptimiser has been turned off. This was
* the original CSS optimisation library.
* It removes whitespace and shrinks things but does no apparent optimisation.
* Note the minify library is still being used for JavaScript.
*
* @param array $files An array of files to minify
* @return string The minified CSS
*/
function css_minify_css($files) {
global $CFG;

if (empty($files)) {
return '';
}

// We do not really want any 304 here!
// There does not seem to be any better way to prevent them here.
unset($_SERVER['HTTP_IF_NONE_MATCH']);
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);

require_once("$CFG->libdir/minify/lib/Minify/Loader.php");
Minify_Loader::register();

if (0 === stripos(PHP_OS, 'win')) {
Minify::setDocRoot(); // IIS may need help
}
// disable all caching, we do it in moodle
Minify::setCache(null, false);

$options = array(
// JSMin is not GNU GPL compatible, use the plus version instead.
'minifiers' => array(Minify::TYPE_JS => array('JSMinPlus', 'minify')),
'bubbleCssImports' => false,
// Don't gzip content we just want text for storage
'encodeOutput' => false,
// Maximum age to cache, not used but required
'maxAge' => (60*60*24*20),
// The files to minify
'files' => $files,
// Turn orr URI rewriting
'rewriteCssUris' => false,
// This returns the CSS rather than echoing it for display
'quiet' => true
);

$error = 'unknown';
try {
$result = Minify::serve('Files', $options);
if ($result['success'] and $result['statusCode'] == 200) {
return $result['content'];
}
} catch (Exception $e) {
$error = $e->getMessage();
$error = str_replace("\r", ' ', $error);
$error = str_replace("\n", ' ', $error);
}

// minification failed - try to inform the theme developer and include the non-minified version
$css = <<<EOD
/* Error: $error */
/* Problem detected during theme CSS minimisation, please review the following code */
/* ================================================================================ */
EOD;
foreach ($files as $cssfile) {
$css .= file_get_contents($cssfile)."\n";
}
return $css;
}

/**
* Determines if the given value is a valid CSS colour.
*
Expand Down
26 changes: 26 additions & 0 deletions lib/deprecatedlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,32 @@

defined('MOODLE_INTERNAL') || die();

/**
* Minify JavaScript files.
*
* @deprecated since 2.6
*
* @param array $files
* @return string
*/
function js_minify($files) {
debugging('js_minify() is deprecated, use core_minify::js_files() or core_minify::js() instead.');
return core_minify::js_files($files);
}

/**
* Minify CSS files.
*
* @deprecated since 2.6
*
* @param array $files
* @return string
*/
function css_minify_css($files) {
debugging('css_minify_css() is deprecated, use core_minify::css_files() or core_minify::css() instead.');
return core_minify::css_files($files);
}

/**
* List all core subsystems and their location
*
Expand Down
2 changes: 1 addition & 1 deletion lib/editor/tinymce/plugins/loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@

// If it doesn't exist, minify it and save to that location.
if (!file_exists($cachefile)) {
$content = js_minify(array($file));
$content = core_minify::js_files(array($file));
js_write_cache_file_content($cachefile, $content);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/javascript.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
define('ABORT_AFTER_CONFIG', true);
require('../config.php'); // this stops immediately at the beginning of lib/setup.php
require_once("$CFG->dirroot/lib/jslib.php");
require_once("$CFG->dirroot/lib/classes/minify.php");

if ($slashargument = min_get_slash_argument()) {
$slashargument = ltrim($slashargument, '/');
Expand Down Expand Up @@ -90,7 +91,7 @@
js_send_cached($candidate, $etag);

} else {
js_write_cache_file_content($candidate, js_minify($jsfiles));
js_write_cache_file_content($candidate, core_minify::js_files($jsfiles));
// verify nothing failed in cache file creation
clearstatcache();
if (file_exists($candidate)) {
Expand Down
Loading

0 comments on commit 6b32d6b

Please sign in to comment.