├── tests ├── project │ ├── content │ │ ├── contents.lr │ │ └── filter.html │ │ │ └── contents.lr │ ├── packages │ │ └── lektor-minify │ ├── models │ │ └── page.ini │ ├── assets │ │ └── static │ │ │ ├── style.css │ │ │ └── script.js │ ├── test_project.lektorproject │ └── templates │ │ ├── page.html │ │ └── filter.html └── test.sh ├── setup.cfg ├── .gitignore ├── .pypirc ├── CHANGELOG.md ├── .travis.yml ├── LICENSE ├── Makefile ├── setup.py ├── README.md └── lektor_minify └── __init__.py /tests/project/content/contents.lr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | -------------------------------------------------------------------------------- /tests/project/packages/lektor-minify: -------------------------------------------------------------------------------- 1 | ../../.. -------------------------------------------------------------------------------- /tests/project/models/page.ini: -------------------------------------------------------------------------------- 1 | [model] 2 | name = Page 3 | -------------------------------------------------------------------------------- /tests/project/assets/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /tests/project/test_project.lektorproject: -------------------------------------------------------------------------------- 1 | [project] 2 | name = test_project 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /build 3 | /tests/tmp 4 | 5 | *.py[co] 6 | *.egg-info 7 | -------------------------------------------------------------------------------- /tests/project/templates/page.html: -------------------------------------------------------------------------------- 1 |
2 | This is a test ✅ 3 |
4 | -------------------------------------------------------------------------------- /tests/project/assets/static/script.js: -------------------------------------------------------------------------------- 1 | function test() { 2 | console.log("test"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/project/content/filter.html/contents.lr: -------------------------------------------------------------------------------- 1 | _model: none 2 | --- 3 | _template: filter.html 4 | -------------------------------------------------------------------------------- /.pypirc: -------------------------------------------------------------------------------- 1 | [distutils] 2 | index-servers = 3 | upload 4 | 5 | [upload] 6 | repository = https://upload.pypi.org/legacy/ 7 | -------------------------------------------------------------------------------- /tests/project/templates/filter.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # lektor-minify changelog 2 | 3 | ## lektor-minify 1.2 4 | 5 | _Released on February 27th, 2017_ 6 | 7 | * Add the `minify()` filter to Jinja2 templates 8 | * Fix plugin crashing sometimes on the development server 9 | 10 | ## lektor-minify 1.1 11 | 12 | _Released on February 21th, 2017_ 13 | 14 | * Fix wheel for Python 2 not being built 15 | * Fix unicode files not properly handled 16 | 17 | ## lektor-minify 1.0 18 | 19 | _Released on February 21th, 2017_ 20 | 21 | * Initial release 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | cache: pip 3 | 4 | python: 5 | - 2.7 6 | - 3.6 7 | env: 8 | - LEKTOR=2.3 9 | - LEKTOR=3.0 10 | - LEKTOR=3.1 11 | - LEKTOR=master 12 | 13 | matrix: 14 | exclude: 15 | - python: 3.6 16 | env: LEKTOR=2.3 17 | 18 | install: 19 | - pip install -U virtualenv setuptools 20 | - if [[ "${LEKTOR}" = "master" ]]; then pip install "git+https://github.com/lektor/lektor.git"; else pip install "lektor==${LEKTOR}"; fi 21 | 22 | script: 23 | - tests/test.sh 24 | 25 | notifications: 26 | email: false 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Pietro Albini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-2017 Pietro Albini 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # Configuration 22 | SOURCE = lektor_minify 23 | PACKAGES_OUT = build/packages 24 | 25 | # Uploading configuration 26 | RELEASES_SERVER = files@winter.net.pietroalbini.org 27 | RELEASES_DIR = public/releases/lektor-minify/$(shell $(PYTHON) setup.py --version) 28 | 29 | # Executables 30 | PYTHON = python3 31 | GPG = gpg 32 | TWINE = twine 33 | 34 | .PHONY: build sign _pre-sign upload test clean 35 | 36 | 37 | # Basic packages building 38 | 39 | build: $(PACKAGES_OUT)/*.tar.gz $(PACKAGES_OUT)/*.whl 40 | 41 | $(PACKAGES_OUT): 42 | @mkdir -p $(PACKAGES_OUT) 43 | 44 | $(PACKAGES_OUT)/*.tar.gz: $(PACKAGES_OUT) setup.py $(wildcard $(SOURCE)/*) 45 | @$(PYTHON) setup.py sdist -d $(PACKAGES_OUT) 46 | 47 | build/packages/*.whl: $(PACKAGES_OUT) setup.py $(wildcard $(SOURCE)/*) 48 | @$(PYTHON) setup.py bdist_wheel -d $(PACKAGES_OUT) 49 | 50 | 51 | # Packages signing 52 | 53 | sign: _pre-sign $(addsuffix .asc,$(filter-out $(wildcard $(PACKAGES_OUT)/*.asc),$(wildcard $(PACKAGES_OUT)/*))) 54 | 55 | _pre-sign: 56 | @rm -f $(PACKAGES_OUT)/*.asc 57 | 58 | $(PACKAGES_OUT)/%.asc: 59 | @$(GPG) --detach --armor --sign $(PACKAGES_OUT)/$* 60 | 61 | 62 | # Packages uploading 63 | 64 | upload: build sign 65 | @ssh $(RELEASES_SERVER) -- mkdir -p $(RELEASES_DIR) 66 | @scp $(PACKAGES_OUT)/* $(RELEASES_SERVER):$(RELEASES_DIR) 67 | @$(TWINE) upload --config-file .pypirc -r upload --skip-existing $(PACKAGES_OUT)/* 68 | 69 | 70 | # Testing 71 | 72 | test: 73 | @tests/test.sh 74 | 75 | 76 | # Cleanup 77 | 78 | clean: 79 | @rm -rf build 80 | @rm -rf tests/tmp 81 | @find -name "*.pyc" -delete 82 | @rm -rf $(SOURCE).egg-info 83 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Pietro Albini 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | ''' 22 | ============= 23 | lektor-minify 24 | ============= 25 | 26 | This plugin allows you to minify the build artifacts of your `Lektor`_ project 27 | during the build process, without any additional tool. It currently supports 28 | minifying HTML, CSS and JS files. 29 | 30 | The plugin only minifies the files changed during the last build, avoiding 31 | slowing down the build if your project consists of a lot of files. Internally 32 | it uses the rcssmin and rjsmin libraries, and it's released under the MIT 33 | license. 34 | 35 | `Learn more about the plugin`_ 36 | 37 | .. _Lektor: https://www.getlektor.com 38 | .. _Learn more about the plugin: https://github.com/pietroalbini/lektor-minify 39 | ''' 40 | 41 | # -*- coding: utf-8 -*- 42 | 43 | import setuptools 44 | 45 | 46 | setuptools.setup( 47 | name = "lektor-minify", 48 | version = "1.3.dev0", 49 | license = "MIT", 50 | 51 | author = "Pietro Albini", 52 | author_email = "pietro@pietroalbini.org", 53 | 54 | description = "Minify build artifacts during the Lektor build process", 55 | long_description = __doc__, 56 | 57 | packages = [ 58 | "lektor_minify", 59 | ], 60 | 61 | install_requires = [ 62 | "rcssmin", 63 | "rjsmin", 64 | "django_htmlmin", 65 | ], 66 | 67 | entry_points = { 68 | "lektor.plugins": [ 69 | "minify = lektor_minify:MinifyPlugin", 70 | ] 71 | }, 72 | 73 | classifiers = [ 74 | "Development Status :: 5 - Production/Stable", 75 | "Environment :: Plugins", 76 | "Intended Audience :: Developers", 77 | "License :: OSI Approved :: MIT License", 78 | "Programming Language :: Python :: 2", 79 | "Programming Language :: Python :: 3", 80 | ], 81 | ) 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lektor-minify 2 | 3 | [![Build Status](https://travis-ci.org/pietroalbini/lektor-minify.svg?branch=master)](https://travis-ci.org/pietroalbini/lektor-minify) 4 | 5 | This plugin allows you to minify the build artifacts of your [Lektor][lektor] 6 | project during the build process, without any additional tool. It currently 7 | supports minifying HTML, CSS and JS files. 8 | 9 | The plugin only minifies the files changed during the last build, avoiding 10 | slowing down the build if your project consists of a lot of files. Internally 11 | it uses the [django_htmlmin][htmlmin], [rcssmin][rcssmin] and [rjsmin][rjsmin] 12 | libraries, and it's released under the MIT license. 13 | 14 | **Supported Lektor releases:** 2.3, 3.0 15 | 16 | ## Installation 17 | 18 | If you want to use lektor-minify in your project, you can to execute the 19 | following command in your Lektor project folder: 20 | 21 | ``` 22 | $ lektor plugins add lektor-minify 23 | ``` 24 | 25 | After you did that, it's good to clear the build cache: the plugin only 26 | minifies changed files, so clearing the cache ensures all the assets are 27 | minified: 28 | 29 | ``` 30 | $ lektor clean --yes 31 | ``` 32 | 33 | ## Usage 34 | 35 | This plugin isn't enabled by default: you need to provide the `minify` flag to 36 | the `build` (or `server`) command if you want to minify the build artifacts: 37 | 38 | ``` 39 | $ lektor build -f minify 40 | $ lektor server -f minify 41 | ``` 42 | 43 | If you need to minify only some kind of artifacts, you can tell which ones you 44 | want to minify by providing their kinds as a comma-separated list in the flag: 45 | 46 | ``` 47 | $ lektor build -f minify:html 48 | $ lektor build -f minify:html,css,js 49 | ``` 50 | 51 | Keep in mind only artifacts built with the flag will be minified: if you 52 | execute other builds without the flag there might be some unminified files! 53 | 54 | ## Jinja2 filter 55 | 56 | The plugin also provides the `minify` filter, ready to be used in your 57 | templates. The filter is useful, for example, if you need to include in the 58 | page external assets, and you want them to be minified as well. 59 | 60 | You can use the filter by piping the content into it, and providing the type of 61 | the content as argument: 62 | 63 | ``` 64 | {{ this.extra_style | minify("css") }} 65 | ``` 66 | 67 | If you need to apply the filter to a block of code, you can also use the filter 68 | block Jinja2 provides: 69 | 70 | ``` 71 | 78 | ``` 79 | 80 | The filter will work even if the `minify` flag is not provided during the 81 | build. 82 | 83 | ## Testing 84 | 85 | Some basic tests are available for the project. If you want to run them clone 86 | the repository, install Lektor and run: 87 | 88 | ``` 89 | make test 90 | ``` 91 | 92 | [lektor]: https://www.getlektor.com/ 93 | [rcssmin]: http://opensource.perlig.de/rcssmin/ 94 | [rjsmin]: http://opensource.perlig.de/rjsmin/ 95 | [htmlmin]: https://github.com/cobrateam/django-htmlmin 96 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2017 Pietro Albini 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | 22 | set -euo pipefail 23 | 24 | EXPECTED_CSS='body{color:#fff}' 25 | EXPECTED_JS='function test(){console.log("test");}' 26 | EXPECTED_HTML='
This is a test ✅
' 27 | EXPECTED_FILTER_MIN='' 28 | EXPECTED_FILTER_NO_MIN='' 31 | 32 | # Detect source directory 33 | # Thanks to http://stackoverflow.com/a/246128/2204144 34 | source="$0" 35 | while [ -h "${source}" ]; do 36 | dir="$( cd -P "$( dirname "${source}" )" && pwd )" 37 | source="$(readlink "${source}")" 38 | done 39 | BASE="$( cd "$( dirname "${source}" )" && pwd )" 40 | 41 | TEST_PROJECT="${BASE}/project" 42 | TMP_DIRECTORY="${BASE}/tmp" 43 | 44 | 45 | build() { 46 | cd "${TEST_PROJECT}" 47 | rm -rf "${TMP_DIRECTORY}" 48 | lektor build -O "${TMP_DIRECTORY}" $@ 49 | } 50 | 51 | assert() { 52 | name="$1" 53 | file="$2" 54 | expected="$3" 55 | outcome="$4" 56 | 57 | content="`cat "${TMP_DIRECTORY}/${file}"`" 58 | if [[ "${content}" == "${expected}" ]]; then 59 | [[ "${outcome}" = "true" ]] || fail "${name}" 60 | else 61 | [[ "${outcome}" = "false" ]] || fail "${name}" 62 | fi 63 | } 64 | 65 | assert_html() { assert html index.html "${EXPECTED_HTML}" "$1"; } 66 | assert_style() { assert css static/style.css "${EXPECTED_CSS}" "$1"; } 67 | assert_script() { assert js static/script.js "${EXPECTED_JS}" "$1"; } 68 | assert_filter_min() { assert filter filter.html "${EXPECTED_FILTER_MIN}" "$1"; } 69 | assert_filter_no_min() { assert filter filter.html "${EXPECTED_FILTER_NO_MIN}" "$1"; } 70 | 71 | fail() { 72 | echo "Failed $@" 73 | exit 1 74 | } 75 | 76 | 77 | echo "Testing with no flags..." 78 | build 79 | assert_html false 80 | assert_style false 81 | assert_script false 82 | assert_filter_no_min true 83 | 84 | echo "Testing with the minify flag..." 85 | build -f minify 86 | assert_html true 87 | assert_style true 88 | assert_script true 89 | assert_filter_min true 90 | 91 | echo "Testing with the minify:css flag..." 92 | build -f minify:css 93 | assert_html false 94 | assert_style true 95 | assert_script false 96 | assert_filter_no_min true 97 | 98 | echo "Testing with the minify:js flag..." 99 | build -f minify:js 100 | assert_html false 101 | assert_style false 102 | assert_script true 103 | assert_filter_no_min true 104 | 105 | echo "Testing with the minify:html flag..." 106 | build -f minify:html 107 | assert_html true 108 | assert_style false 109 | assert_script false 110 | assert_filter_min true 111 | 112 | echo "Testing with the minify:css,js,html flag..." 113 | build -f minify:css,js,html 114 | assert_html true 115 | assert_style true 116 | assert_script true 117 | assert_filter_min true 118 | 119 | echo "Test successful!" 120 | rm -rf "${TMP_DIRECTORY}" 121 | -------------------------------------------------------------------------------- /lektor_minify/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Pietro Albini 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # -*- coding: utf-8 -*- 22 | 23 | from __future__ import unicode_literals 24 | 25 | import codecs 26 | 27 | import rcssmin 28 | import rjsmin 29 | import htmlmin.minify as htmlmin 30 | 31 | from lektor.pluginsystem import Plugin 32 | from lektor.reporter import reporter 33 | 34 | 35 | MINIFY_FLAG = "minify" 36 | FILTER_NAME = "minify" 37 | 38 | # To add new minifiers, you need to add a new matcher and the corresponding 39 | # minifier -- no other code change is needed 40 | MATCHERS = { 41 | "html": lambda name: name.endswith(".html"), 42 | "css": lambda name: name.endswith(".css"), 43 | "js": lambda name: name.endswith(".js"), 44 | } 45 | MINIFIERS = { 46 | "html": htmlmin.html_minify, 47 | "css": rcssmin.cssmin, 48 | "js": rjsmin.jsmin, 49 | } 50 | 51 | 52 | class MinifyPlugin(Plugin): 53 | name = u"minify" 54 | description = u"Minify your build artifacts during the build process" 55 | 56 | def __init__(self, *args, **kwargs): 57 | Plugin.__init__(self, *args, **kwargs) 58 | 59 | def can_minify(self, builder, type): 60 | """Check if a file type can be minified""" 61 | try: 62 | types = builder.__can_minify 63 | except AttributeError: 64 | types = self.parse_flags(builder) 65 | 66 | return type in types 67 | 68 | def parse_flags(self, builder): 69 | """Parse the flags of the provided builder""" 70 | try: # Lektor 3+ 71 | flags = builder.extra_flags 72 | except AttributeError: # Lektor 2 73 | flags = builder.build_flags 74 | 75 | types = set() 76 | 77 | allowed_kinds = set(MATCHERS.keys()) 78 | if MINIFY_FLAG in flags: 79 | if flags[MINIFY_FLAG] == MINIFY_FLAG: 80 | types = allowed_kinds 81 | else: 82 | kinds = set(flags[MINIFY_FLAG].split(",")) 83 | 84 | diff = kinds - allowed_kinds 85 | for kind in diff: 86 | reporter.report_generic( 87 | "\033[33mUnknown param for flag %s:\033[37m %s" 88 | % (MINIFY_FLAG, kind) 89 | ) 90 | 91 | types = kinds & allowed_kinds 92 | 93 | builder.__can_minify = types 94 | return types 95 | 96 | def jinja_filter(self, content, type): 97 | """Minify a part of a template""" 98 | if type not in MINIFIERS: 99 | raise NameError("Unknown minifier: %s" % type) 100 | return MINIFIERS[type](content) 101 | 102 | def on_setup_env(self, **extra): 103 | self.env.jinja_env.filters[FILTER_NAME] = self.jinja_filter 104 | 105 | def on_after_build(self, builder, build_state, **extra): 106 | # Get the new artifacts built in this state 107 | try: 108 | seen = build_state.__seen_artifacts 109 | except AttributeError: 110 | build_state.__seen_artifacts = set() 111 | artifacts = set(build_state.updated_artifacts) 112 | else: 113 | updated = set(build_state.updated_artifacts) 114 | artifacts = updated - seen 115 | 116 | # This keeps track of the artifacts already built in this build_state, 117 | # so those files aren't minified multiple times 118 | build_state.__seen_artifacts |= artifacts 119 | 120 | for artifact in artifacts: 121 | name = artifact.dst_filename 122 | 123 | for type, matcher in MATCHERS.items(): 124 | if matcher(name) and self.can_minify(builder, type): 125 | minifier = MINIFIERS[type] 126 | break 127 | else: 128 | continue 129 | 130 | with artifact.update(): 131 | with artifact.open("rb+") as f: 132 | content = codecs.decode(f.read(), "utf-8") 133 | 134 | f.seek(0) 135 | f.write(codecs.encode(minifier(content), "utf-8")) 136 | f.truncate() 137 | --------------------------------------------------------------------------------