mirror of
https://github.com/moodle/moodle.git
synced 2025-04-22 08:55:15 +02:00
MDL-40995 simplify minify integration and fix all known issues
This commit is contained in:
parent
7c3943ad0c
commit
6b32d6bc93
149
lib/classes/minify.php
Normal file
149
lib/classes/minify.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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.
|
||||
@ -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
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -83,7 +83,7 @@ if ($mimetype === 'application/x-javascript' && $allowcache) {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ define('NO_DEBUG_DISPLAY', true);
|
||||
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, '/');
|
||||
@ -90,7 +91,7 @@ if ($rev > 0 and $rev < (time() + 60*60)) {
|
||||
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)) {
|
||||
|
@ -23,7 +23,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();
|
||||
|
||||
/**
|
||||
* Send javascript file content with as much caching as possible
|
||||
@ -93,76 +93,6 @@ function js_send_unmodified($lastmodified, $etag) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minify javascript files
|
||||
* @param array $files
|
||||
* @return string
|
||||
*/
|
||||
function js_minify($files) {
|
||||
global $CFG;
|
||||
|
||||
if (empty($files)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
require_once("$CFG->libdir/minify/lib/Minify/Loader.php");
|
||||
Minify_Loader::register();
|
||||
|
||||
// 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']);
|
||||
|
||||
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' => 1800,
|
||||
// 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
|
||||
$js = <<<EOD
|
||||
try {console.log('Error: Minimisation of javascript failed!');} catch (e) {}
|
||||
|
||||
// Error: $error
|
||||
// Problem detected during javascript minimisation, please review the following code
|
||||
// =================================================================================
|
||||
|
||||
|
||||
EOD;
|
||||
foreach ($files as $jsfile) {
|
||||
$js .= file_get_contents($jsfile)."\n";
|
||||
}
|
||||
return $js;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache file for JS content
|
||||
* @param string $file full file path to cache file
|
||||
|
@ -1,11 +1,9 @@
|
||||
Description of Minify 2.1.7 import into Moodle
|
||||
|
||||
Notes:
|
||||
* Do not use things within minify/lib/*
|
||||
|
||||
Usage:
|
||||
* js_minify() from /lib/jslib.php
|
||||
* css_minify_css() from /lib/csslib.php
|
||||
* Do not use anything from /lib/minify/ directly, always use core_minify::*() methods.
|
||||
* In 2.7dev we will import only the minimal number of files required by new core_minify class
|
||||
and delete deprecated js_minify() and css_minify_css().
|
||||
|
||||
Changes:
|
||||
* Removed index.php - Is an unused entry point program and could potentially
|
||||
|
@ -1571,7 +1571,7 @@ class YUI_config {
|
||||
$configfn = $cache->get($keyname);
|
||||
if ($configfn === false) {
|
||||
require_once($CFG->libdir . '/jslib.php');
|
||||
$configfn = js_minify($fullpath);
|
||||
$configfn = core_minify::js_files(array($fullpath));
|
||||
$cache->set($keyname, $configfn);
|
||||
}
|
||||
}
|
||||
|
122
lib/tests/minify_test.php
Normal file
122
lib/tests/minify_test.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_minify related tests.
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @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();
|
||||
|
||||
|
||||
/**
|
||||
* Class core_minify_testcase.
|
||||
*/
|
||||
class core_minify_testcase extends advanced_testcase {
|
||||
public function test_css() {
|
||||
$css = "
|
||||
body {
|
||||
background: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #281f18;
|
||||
}";
|
||||
|
||||
$this->assertSame("body{background:#fff;margin:0;padding:0;color:#281f18}", core_minify::css($css));
|
||||
}
|
||||
|
||||
public function test_css_files() {
|
||||
global $CFG;
|
||||
|
||||
$testfile1 = "$CFG->tempdir/test1.css";
|
||||
$testfile2 = "$CFG->tempdir/test2.css";
|
||||
$testfile3 = "$CFG->tempdir/test3.css";
|
||||
|
||||
$css1 = "
|
||||
body {
|
||||
background: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #281f18;
|
||||
}";
|
||||
|
||||
$css2 = "body{}";
|
||||
|
||||
file_put_contents($testfile1, $css1);
|
||||
file_put_contents($testfile2, $css2);
|
||||
|
||||
$files = array($testfile1, $testfile2);
|
||||
|
||||
$this->assertSame("body{background:#fff;margin:0;padding:0;color:#281f18}\nbody{}", core_minify::css_files($files));
|
||||
|
||||
|
||||
$files = array($testfile1, $testfile2, $testfile3);
|
||||
|
||||
$this->assertStringStartsWith("body{background:#fff;margin:0;padding:0;color:#281f18}\nbody{}\n\n\n/* Cannot read CSS file ", @core_minify::css_files($files));
|
||||
|
||||
unlink($testfile1);
|
||||
unlink($testfile2);
|
||||
}
|
||||
|
||||
public function test_js() {
|
||||
$js = "
|
||||
function hm()
|
||||
{
|
||||
}
|
||||
";
|
||||
|
||||
$this->assertSame("function hm(){}", core_minify::js($js));
|
||||
|
||||
$js = "function hm{}";
|
||||
$result = core_minify::js($js);
|
||||
$this->assertStringStartsWith("\ntry {console.log('Error: Minimisation of JavaScript failed!');} catch (e) {}", $result);
|
||||
$this->assertContains($js, $result);
|
||||
}
|
||||
|
||||
public function test_js_files() {
|
||||
global $CFG;
|
||||
|
||||
$testfile1 = "$CFG->tempdir/test1.js";
|
||||
$testfile2 = "$CFG->tempdir/test2.js";
|
||||
$testfile3 = "$CFG->tempdir/test3.js";
|
||||
|
||||
$js1 = "
|
||||
function hm()
|
||||
{
|
||||
}
|
||||
";
|
||||
|
||||
$js2 = "function oh(){}";
|
||||
|
||||
file_put_contents($testfile1, $js1);
|
||||
file_put_contents($testfile2, $js2);
|
||||
|
||||
$files = array($testfile1, $testfile2);
|
||||
|
||||
$this->assertSame("function hm(){}\nfunction oh(){}", core_minify::js_files($files));
|
||||
|
||||
$files = array($testfile1, $testfile2, $testfile3);
|
||||
|
||||
$this->assertStringStartsWith("function hm(){}\nfunction oh(){}\n\n\n// Cannot read JS file ", @core_minify::js_files($files));
|
||||
|
||||
unlink($testfile1);
|
||||
unlink($testfile2);
|
||||
}
|
||||
}
|
@ -82,6 +82,8 @@ Misc:
|
||||
* httpsrequired() -> $PAGE->https_required()
|
||||
* detect_munged_arguments() -> clean_param([...], PARAM_FILE)
|
||||
* mygroupid() -> groups_get_all_groups()
|
||||
* js_minify() -> core_minify::js_files()
|
||||
* css_minify_css() -> core_minify::css_files()
|
||||
|
||||
YUI:
|
||||
* moodle-core-notification has been deprecated with a recommendation of
|
||||
|
@ -95,7 +95,7 @@ if ($themerev <= 0 or $rev != $themerev) {
|
||||
|
||||
make_localcache_directory('theme', false);
|
||||
|
||||
js_write_cache_file_content($candidate, js_minify($theme->javascript_files($type)));
|
||||
js_write_cache_file_content($candidate, core_minify::js_files($theme->javascript_files($type)));
|
||||
// Verify nothing failed in cache file creation.
|
||||
clearstatcache();
|
||||
if (file_exists($candidate)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user