├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json └── src └── voku └── twig ├── MinifyHtmlExtension.php ├── MinifyHtmlNode.php └── MinifyHtmlTokenParser.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased] 6 | 7 | ## [4.0.2] - 2021-01-05 8 | ### Added 9 | - add support for Twig 3.* 10 | 11 | 12 | ## [4.0.1] - 2020-03-26 13 | ### Changed 14 | - removed support for Twig 1.* 15 | ### Added 16 | - add support for Twig 2.* 17 | 18 | 19 | ## [4.0.0] - 2019-11-24 20 | ### Changed 21 | - update "HtmlMin" from v3 -> v4 22 | ### Added 23 | - use caching for compressed results 24 | 25 | 26 | ## [3.0.0] - 2017-12-23 27 | ### Changed 28 | - update "HtmlMin" from v2 -> v3 29 | 30 | -> this is a breaking change without API-changes - but the requirement 31 | from HtmlMin has been changes (it no longer requires "Portable UTF8") 32 | 33 | 34 | ## [2.0.0] - 2017-12-03 35 | ### Changed 36 | - drop support for PHP < 7.0 37 | - use "strict_types" 38 | 39 | 40 | ## [1.0.2] - 2017-03-18 41 | ### Changed 42 | - remove tests-directory ".gitattributes" when installing via composer 43 | - fix compatibility with PHP 5.3 / 5.4 44 | 45 | 46 | ## [1.0.1] - 2017-03-18 47 | ### Changed 48 | - use dependency injection 49 | 50 | 51 | ## [1.0.0] - 2017-03-18 52 | ### Changed 53 | - init (fork from https://github.com/nochso/html-compress-twig/) 54 | 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Marcel Voigt 2 | Copyright (c) 2017, Lars Moelleken 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted, provided that the above 6 | copyright notice and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/voku/html-compress-twig.svg?branch=master)](https://travis-ci.org/voku/html-compress-twig) 2 | [![Coverage Status](https://coveralls.io/repos/github/voku/html-compress-twig/badge.svg?branch=master)](https://coveralls.io/github/voku/html-compress-twig?branch=master) 3 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/voku/html-compress-twig/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/voku/html-compress-twig/?branch=master) 4 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/0497e1f5be2d43a08c0a108dc7192287)](https://www.codacy.com/app/voku/html-compress-twig?utm_source=github.com&utm_medium=referral&utm_content=voku/html-compress-twig&utm_campaign=Badge_Grade) 5 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/40d6318a-64fc-4927-8438-c57b0f546949/mini.png)](https://insight.sensiolabs.com/projects/40d6318a-64fc-4927-8438-c57b0f546949) 6 | [![Latest Stable Version](https://poser.pugx.org/voku/html-compress-twig/v/stable)](https://packagist.org/packages/voku/html-compress-twig) 7 | [![Total Downloads](https://poser.pugx.org/voku/html-compress-twig/downloads)](https://packagist.org/packages/voku/html-compress-twig) 8 | [![Latest Unstable Version](https://poser.pugx.org/voku/html-compress-twig/v/unstable)](https://packagist.org/packages/voku/html-compress-twig) 9 | [![License](https://poser.pugx.org/voku/html-compress-twig/license)](https://packagist.org/packages/voku/html-compress-twig) 10 | 11 | # :clamp: HtmlMin for Twig: HTML Compressor and Minifier 12 | 13 | ## Description 14 | 15 | A [Twig](http://twig.sensiolabs.org/) extension for [voku/HtmlMin](https://github.com/voku/HtmlMin). 16 | 17 | Currently supported Twig features are: 18 | 19 | * Tag 20 | * `{% htmlcompress %} bar {% endhtmlcompress %}` 21 | * Function 22 | * `{{ htmlcompress(' bar') }}` 23 | * Filter 24 | * `{{ ' bar' | htmlcompress }}` 25 | 26 | * [Installation](#installation) 27 | * [Usage](#usage) 28 | * [History](#history) 29 | * [License](#license) 30 | 31 | ## Installation 32 | 33 | 1. Install and use [composer](https://getcomposer.org/doc/00-intro.md) in your project. 34 | 2. Require this package via composer: 35 | 36 | ```sh 37 | composer require voku/html-compress-twig 38 | ``` 39 | 40 | ## Usage 41 | 42 | First register the extension with Twig: 43 | 44 | ```php 45 | use voku\helper\HtmlMin; 46 | use voku\twig\MinifyHtmlExtension; 47 | 48 | $twig = new \Twig\Environment($loader); 49 | $minifier = new HtmlMin(); 50 | $twig->addExtension(new MinifyHtmlExtension($minifier)); 51 | ``` 52 | 53 | ### Register extension in symfony 4 54 | Specifying HtmlMin is needed for the autowiring. 55 | 56 | ```yaml 57 | voku\helper\HtmlMin: 58 | tags: 59 | - { name: HtmlMin } 60 | 61 | voku\twig\MinifyHtmlExtension: 62 | arguments: 63 | $forceCompression: false 64 | tags: 65 | - { name: twig.extension } 66 | ``` 67 | 68 | Then use it in your templates: 69 | 70 | ``` 71 | {% htmlcompress %} bar {% endhtmlcompress %} 72 | {{ htmlcompress(' bar') }} 73 | {{ ' bar' | htmlcompress }} 74 | ``` 75 | 76 | **Compression is disabled by Twig's `debug` setting.** This is to make development easier, however you can always 77 | override it. 78 | 79 | The constructor of this extension takes a boolean as second parameter `$forceCompression`. When true, this will 80 | force compression regardless of Twig's `debug` setting. It defaults to false when omitted. 81 | 82 | ```php 83 | $twig->addExtension(new MinifyHtmlExtension($minifier, true)); 84 | ``` 85 | 86 | ## History 87 | See [CHANGELOG](CHANGELOG.md) for the full history of changes. 88 | 89 | ## License 90 | This project is licensed under the ISC license which is MIT/GPL compatible and FSF/OSI approved. 91 | See the [LICENSE](LICENSE) file for the full license text. 92 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voku/html-compress-twig", 3 | "type": "library", 4 | "description": "Twig extension for compressing HTML", 5 | "keywords": [ 6 | "html", 7 | "compress", 8 | "twig", 9 | "extension", 10 | "minify" 11 | ], 12 | "license": "ISC", 13 | "authors": [ 14 | { 15 | "name": "Marcel Voigt", 16 | "email": "mv@noch.so" 17 | }, 18 | { 19 | "name": "Lars Moelleken", 20 | "homepage": "http://www.moelleken.org/" 21 | } 22 | ], 23 | "require": { 24 | "php": ">=7.0.0", 25 | "twig/twig": "~2.7 || ^3", 26 | "voku/html-min": "~4.4", 27 | "voku/simple-cache": "~4.0" 28 | }, 29 | "require-dev": { 30 | "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "voku\\": "src/voku/" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/voku/twig/MinifyHtmlExtension.php: -------------------------------------------------------------------------------- 1 | ['html'], 21 | 'needs_environment' => true, 22 | ]; 23 | 24 | /** 25 | * @var callable 26 | */ 27 | private $callable; 28 | 29 | /** 30 | * @var HtmlMin 31 | */ 32 | private $minifier; 33 | 34 | /** 35 | * @var bool 36 | */ 37 | private $forceCompression = false; 38 | 39 | /** 40 | * MinifyHtmlExtension constructor. 41 | * 42 | * @param HtmlMin $htmlMin 43 | * @param bool $forceCompression Default: false. Forces compression regardless of Twig's debug setting. 44 | */ 45 | public function __construct(HtmlMin $htmlMin, bool $forceCompression = false) 46 | { 47 | $this->forceCompression = $forceCompression; 48 | $this->minifier = $htmlMin; 49 | $this->callable = [$this, 'compress']; 50 | } 51 | 52 | /** 53 | * @param Environment $twig 54 | * @param string $html 55 | * 56 | * @return string 57 | */ 58 | public function compress(Environment $twig, $html) 59 | { 60 | if ($this->isCompressionActive($twig)) { 61 | static $cache = null; 62 | if ($cache === null) { 63 | $cache = new Cache(null, null, false); 64 | } 65 | $cacheKey = 'HtmlMin::hash' . \md5($html); 66 | 67 | if ( 68 | $cache->getCacheIsReady() === true 69 | && 70 | $cache->existsItem($cacheKey) === true 71 | ) { 72 | return $cache->getItem($cacheKey); 73 | } 74 | 75 | $html = $this->minifier->minify($html); 76 | 77 | if ($cache->getCacheIsReady() === true) { 78 | $cache->setItem($cacheKey, $html, 3600); 79 | } 80 | 81 | return $html; 82 | } 83 | 84 | return $html; 85 | } 86 | 87 | /** @noinspection PhpMissingParentCallCommonInspection */ 88 | 89 | /** 90 | * @return array 91 | */ 92 | public function getFilters(): array 93 | { 94 | return [ 95 | new TwigFilter('htmlcompress', $this->callable, $this->options), 96 | ]; 97 | } 98 | 99 | /** @noinspection PhpMissingParentCallCommonInspection */ 100 | public function getFunctions(): array 101 | { 102 | return [ 103 | new TwigFunction('htmlcompress', $this->callable, $this->options), 104 | ]; 105 | } 106 | 107 | /** @noinspection PhpMissingParentCallCommonInspection */ 108 | public function getTokenParsers(): array 109 | { 110 | return [ 111 | new MinifyHtmlTokenParser(), 112 | ]; 113 | } 114 | 115 | /** 116 | * @param Environment $twig 117 | * 118 | * @return bool 119 | */ 120 | public function isCompressionActive(Environment $twig): bool 121 | { 122 | return $this->forceCompression 123 | || 124 | !$twig->isDebug(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/voku/twig/MinifyHtmlNode.php: -------------------------------------------------------------------------------- 1 | addDebugInfo($this) 30 | ->write("ob_start();\n") 31 | ->subcompile($this->getNode('body')) 32 | ->write('$extension = $this->env->getExtension(\'\\voku\\twig\\MinifyHtmlExtension\');' . "\n") 33 | ->write('echo $extension->compress($this->env, ob_get_clean());' . "\n"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/voku/twig/MinifyHtmlTokenParser.php: -------------------------------------------------------------------------------- 1 | test('endhtmlcompress'); 20 | } 21 | 22 | /** @noinspection PhpMissingParentCallCommonInspection */ 23 | public function getTag(): string 24 | { 25 | return 'htmlcompress'; 26 | } 27 | 28 | /** 29 | * @param Token $token 30 | * 31 | * @return MinifyHtmlNode 32 | */ 33 | public function parse(Token $token): MinifyHtmlNode 34 | { 35 | $lineNumber = $token->getLine(); 36 | $stream = $this->parser->getStream(); 37 | $stream->expect(Token::BLOCK_END_TYPE); 38 | $body = $this->parser->subparse([$this, 'decideHtmlCompressEnd'], true); 39 | $stream->expect(Token::BLOCK_END_TYPE); 40 | $nodes = ['body' => $body]; 41 | 42 | return new MinifyHtmlNode($nodes, [], $lineNumber, $this->getTag()); 43 | } 44 | } 45 | --------------------------------------------------------------------------------