Changed minification engine (closed #4)
This commit is contained in:
parent
6ce7beffd2
commit
a7d4490b4f
7 changed files with 131 additions and 143 deletions
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"require": {
|
||||
"mnapoli/php-di": "~4.0",
|
||||
"linkorb/jsmin-php": "1.*",
|
||||
"natxet/CssMin": "3.*",
|
||||
"phpcheckstyle/phpcheckstyle": "~0.14"
|
||||
}
|
||||
}
|
||||
|
|
103
gruntfile.js
103
gruntfile.js
|
@ -1,16 +1,54 @@
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var ini = require('ini');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
var phpCheckStyleConfigPath = path.join(path.resolve(), 'phpcheckstyle.cfg');
|
||||
var phpSourcesDir = path.join(path.resolve(), 'src');
|
||||
var jsSourcesDir = path.join(path.resolve(), 'public_html/js');
|
||||
var cssSourcesDir = path.join(path.resolve(), 'public_html/css');
|
||||
var templatesDir = path.join(path.resolve(), 'public_html/templates');
|
||||
|
||||
var config = readConfig([
|
||||
path.join(path.resolve(), 'data/config.ini'),
|
||||
path.join(path.resolve(), 'data/local.ini')
|
||||
]);
|
||||
|
||||
function readConfig(configPaths) {
|
||||
var iniContent = '';
|
||||
for (var i = 0; i < configPaths.length; i ++) {
|
||||
var configPath = configPaths[i];
|
||||
if (fs.existsSync(configPath)) {
|
||||
iniContent += fs.readFileSync(configPath, 'utf-8');
|
||||
}
|
||||
}
|
||||
var config = ini.parse(iniContent);
|
||||
return config;
|
||||
}
|
||||
|
||||
function readTemplates() {
|
||||
var templatePaths = grunt.file.expand(templatesDir + '/**/*.tpl');
|
||||
var templates = {};
|
||||
for (var i = 0; i < templatePaths.length; i ++) {
|
||||
var templatePath = templatePaths[i];
|
||||
templates[path.basename(templatePath)] = fs.readFileSync(templatePath);
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
phpCheckStyleConfigPath: path.join(path.resolve(), 'phpcheckstyle.cfg'),
|
||||
phpSourcesDir: path.join(path.resolve(), 'src'),
|
||||
jsSourcesDir: path.join(path.resolve(), 'public_html'),
|
||||
phpCheckStyleConfigPath: phpCheckStyleConfigPath,
|
||||
phpSourcesDir: phpSourcesDir,
|
||||
jsSourcesDir: jsSourcesDir,
|
||||
cssSourcesDir: cssSourcesDir,
|
||||
|
||||
config: config,
|
||||
|
||||
jshint: {
|
||||
files: ['<%= jsSourcesDir %>/**/*.js'],
|
||||
files: [jsSourcesDir + '/**/*.js'],
|
||||
options: {
|
||||
globals: {
|
||||
console: true,
|
||||
|
@ -45,11 +83,66 @@ module.exports = function(grunt) {
|
|||
command: 'phpunit --strict --bootstrap src/AutoLoader.php tests/',
|
||||
},
|
||||
},
|
||||
|
||||
cssmin: {
|
||||
combine: {
|
||||
files: {
|
||||
'public_html/app.min.css': [cssSourcesDir + '/**/*.css'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
uglify: {
|
||||
dist: {
|
||||
options: {
|
||||
mangle: false, //breaks dependency injection
|
||||
sourceMap: true,
|
||||
},
|
||||
files: {
|
||||
'public_html/app.min.js': [].concat(
|
||||
[jsSourcesDir + '/DI.js'],
|
||||
grunt.file.expand({
|
||||
filter: function(src) {
|
||||
return !src.match(/(DI|Bootstrap)\.js/);
|
||||
}
|
||||
}, jsSourcesDir + '/**/*.js'),
|
||||
[jsSourcesDir + '/Bootstrap.js']),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
processhtml: {
|
||||
options: {
|
||||
data: {
|
||||
serviceName: config.basic.serviceName,
|
||||
templates: readTemplates(),
|
||||
timestamp: grunt.template.today('isoDateTime'),
|
||||
}
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
'public_html/app.min.html': ['public_html/index.html']
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-processhtml');
|
||||
grunt.loadNpmTasks('grunt-shell');
|
||||
grunt.registerTask('default', ['jshint', 'shell']);
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-cssmin');
|
||||
|
||||
grunt.registerTask('default', ['checkstyle', 'tests']);
|
||||
grunt.registerTask('checkstyle', ['jshint', 'shell:phpcheckstyle']);
|
||||
grunt.registerTask('tests', ['shell:tests']);
|
||||
|
||||
grunt.registerTask('clean', function() {
|
||||
fs.unlink('public_html/app.min.html');
|
||||
fs.unlink('public_html/app.min.js');
|
||||
fs.unlink('public_html/app.min.js.map');
|
||||
fs.unlink('public_html/app.min.css');
|
||||
});
|
||||
grunt.registerTask('build', ['clean', 'uglify', 'cssmin', 'processhtml']);
|
||||
|
||||
};
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"requirejs": "*",
|
||||
"ini": "*",
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-processhtml": "*",
|
||||
"grunt-contrib-uglify": "*",
|
||||
"grunt-contrib-cssmin": "*",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-shell": "~1.1.1"
|
||||
}
|
||||
|
|
5
public_html/.gitignore
vendored
5
public_html/.gitignore
vendored
|
@ -1 +1,4 @@
|
|||
index-compiled.html
|
||||
app.min.html
|
||||
app.min.js
|
||||
app.min.js.map
|
||||
app.min.css
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DirectoryIndex index-compiled.html
|
||||
DirectoryIndex app.min.html
|
||||
DirectoryIndex index.html
|
||||
|
||||
RewriteEngine On
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
require_once __DIR__ . DS . '..' . DS . 'vendor' . DS . 'autoload.php';
|
||||
|
||||
class Compressor
|
||||
{
|
||||
public static function css($content)
|
||||
{
|
||||
return CssMin::minify($content);
|
||||
}
|
||||
|
||||
public static function js($content)
|
||||
{
|
||||
return JSMin::minify($content);
|
||||
}
|
||||
|
||||
public static function html($html)
|
||||
{
|
||||
$illegalTags = ['script', 'link', 'textarea', 'pre'];
|
||||
$chunks = preg_split( '/(<(' . join('|', $illegalTags) . ')(?:\/|.*?\/\2)>)/ms', $html, -1,
|
||||
PREG_SPLIT_DELIM_CAPTURE);
|
||||
$buffer = '';
|
||||
foreach ($chunks as $chunk)
|
||||
{
|
||||
if (in_array($chunk, $illegalTags))
|
||||
continue;
|
||||
|
||||
if (preg_match('/^<(' . join('|', $illegalTags) . ')/', $chunk))
|
||||
{
|
||||
$buffer .= $chunk;
|
||||
continue;
|
||||
}
|
||||
|
||||
# remove new lines & tabs
|
||||
$chunk = preg_replace( '/[\\n\\r\\t]+/', ' ', $chunk);
|
||||
# remove extra whitespace
|
||||
$chunk = preg_replace( '/\\s{2,}/', ' ', $chunk);
|
||||
# remove inter-tag whitespace
|
||||
$chunk = preg_replace( '/>\\s</', '><', $chunk);
|
||||
# remove CSS & JS comments
|
||||
$chunk = preg_replace( '/\\/\\*.*?\\*\\//i', '', $chunk);
|
||||
$buffer .= $chunk;
|
||||
}
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
|
||||
class IndexBuilder
|
||||
{
|
||||
public static function build()
|
||||
{
|
||||
$html = file_get_contents(__DIR__ . DS . 'index.html');
|
||||
self::includeTemplates($html);
|
||||
self::minifyScripts($html);
|
||||
self::minifyStylesheets($html);
|
||||
return $html;
|
||||
}
|
||||
|
||||
private static function injectBody(&$html, $text)
|
||||
{
|
||||
$html = str_replace('</body>', $text . '</body>', $html);
|
||||
}
|
||||
|
||||
private static function injectHead(&$html, $text)
|
||||
{
|
||||
$html = str_replace('</head>', $text . '</head>', $html);
|
||||
}
|
||||
|
||||
private static function minifyScripts(&$html)
|
||||
{
|
||||
$scriptsToMinify = [];
|
||||
|
||||
$html = preg_replace_callback(
|
||||
'/<script[^>]*src="([^"]+)"[^>]*><\/script>/',
|
||||
function($matches) use (&$scriptsToMinify)
|
||||
{
|
||||
$scriptPath = $matches[1];
|
||||
if (substr($scriptPath, 0, 2) == '//' or strpos($scriptPath, 'http') !== false)
|
||||
return $matches[0];
|
||||
$scriptsToMinify []= __DIR__ . DS . $scriptPath;
|
||||
return '';
|
||||
}, $html);
|
||||
|
||||
$out = '<script type="text/javascript">';
|
||||
foreach ($scriptsToMinify as $scriptPath)
|
||||
$out .= Compressor::js(file_get_contents($scriptPath));
|
||||
$out .= '</script>';
|
||||
self::injectBody($html, $out);
|
||||
}
|
||||
|
||||
private static function minifyStylesheets(&$html)
|
||||
{
|
||||
$html = preg_replace_callback(
|
||||
'/<link[^>]*href="([^"]+)"[^>]*>/',
|
||||
function($matches) use (&$stylesToMinify)
|
||||
{
|
||||
$stylePath = $matches[1];
|
||||
if (substr($stylePath, 0, 2) == '//' or strpos($stylePath, 'http') !== false)
|
||||
return $matches[0];
|
||||
if (strpos($matches[0], 'css') === false)
|
||||
return $matches[0];
|
||||
$stylesToMinify []= __DIR__ . DS . $stylePath;
|
||||
return '';
|
||||
}, $html);
|
||||
|
||||
$out = '<style type="text/css">';
|
||||
foreach ($stylesToMinify as $stylePath)
|
||||
$out .= Compressor::css(file_get_contents($stylePath));
|
||||
$out .= '</style>';
|
||||
self::injectHead($html, $out);
|
||||
}
|
||||
|
||||
private static function includeTemplates(&$html)
|
||||
{
|
||||
$templatesToInclude = [];
|
||||
foreach (glob(__DIR__ . DS . 'templates' . DS . '*.tpl') as $templatePath)
|
||||
$templatesToInclude []= $templatePath;
|
||||
|
||||
$out = '';
|
||||
foreach ($templatesToInclude as $templatePath)
|
||||
{
|
||||
$out .= '<script type="text/template" id="' . str_replace('.tpl', '-template', basename($templatePath)) . '">';
|
||||
$out .= Compressor::html(file_get_contents($templatePath));
|
||||
$out .= '</script>';
|
||||
}
|
||||
self::injectBody($html, $out);
|
||||
}
|
||||
}
|
||||
|
||||
$compiledPath = __DIR__ . DS . 'index-compiled.html';
|
||||
$html = IndexBuilder::build();
|
||||
$html = Compressor::html($html);
|
||||
file_put_contents($compiledPath, $html);
|
|
@ -2,11 +2,20 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>szurubooru</title>
|
||||
<!-- build:remove -->
|
||||
<title>szuru2</title>
|
||||
<!-- /build -->
|
||||
<!-- build:template
|
||||
<title><%= serviceName %></title>
|
||||
/build -->
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/path.js/0.8.4/path.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
|
||||
<!-- build:template
|
||||
<link rel="stylesheet" type="text/css" href="app.min.css?<%= timestamp %>"/>
|
||||
/build -->
|
||||
<!-- build:remove -->
|
||||
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans:400,700"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/core.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/forms.css"/>
|
||||
|
@ -17,6 +26,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="/css/registration-form.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/user-list.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/user.css"/>
|
||||
<!-- /build -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -28,6 +38,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- build:template
|
||||
<% _.each(templates, function(templateString, templateName) { %>
|
||||
<script type="text/template" id="<%= templateName %>-template">
|
||||
<%= templateString %>
|
||||
</script>
|
||||
<% }) %>
|
||||
/build -->
|
||||
|
||||
<!-- build:template
|
||||
<script type="text/javascript" src="app.min.js?<%= timestamp %>"></script>
|
||||
/build -->
|
||||
<!-- build:remove -->
|
||||
<script type="text/javascript" src="/js/DI.js"></script>
|
||||
<script type="text/javascript" src="/js/Promise.js"></script>
|
||||
<script type="text/javascript" src="/js/State.js"></script>
|
||||
|
@ -56,5 +78,6 @@
|
|||
<script type="text/javascript" src="/js/Presenters/UserActivationPresenter.js"></script>
|
||||
<script type="text/javascript" src="/js/Router.js"></script>
|
||||
<script type="text/javascript" src="/js/Bootstrap.js"></script>
|
||||
<!-- /build -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue