Changelog
=========

v4.4 (2023-06-28)
-------------------

`Full list of changes from v4.3.1 <https://github.com/django-compressor/django-compressor/compare/4.3.1...4.4>`_

- Officially support Django 4.2


v4.3.1 (2023-01-22)
-------------------

`Full list of changes from v4.3 <https://github.com/django-compressor/django-compressor/compare/4.3...4.3.1>`_

- Documentation fixes only


v4.3 (2023-01-06)
-----------------

`Full list of changes from v4.2 <https://github.com/django-compressor/django-compressor/compare/4.2...4.3>`_

- Officially support Python 3.11

v4.2 (2023-01-06)
-----------------

`Full list of changes from v4.1 <https://github.com/django-compressor/django-compressor/compare/4.1...4.2>`_

- Drop Python 3.6 and 3.7 support
- Drop Django 2.2 and 3.1 support
- Drop SlimItFilter
- Update the `CachedS3Boto3Storage` example storage subclass in "Remote Storages"
  to work properly after the v4.0 change to how duplicate file names are handled
  by `CompressorFileStorage`
- Update rsmin and jsmin versions
  

v4.1 (2022-08-03)
-----------------

`Full list of changes from v4.0 <https://github.com/django-compressor/django-compressor/compare/4.0...4.1>`_

- Add Django 4.1 compatibility

- New setting ``COMPRESS_OFFLINE_MANIFEST_STORAGE`` to customize the offline manifest's file storage (#1112)

  With this change the function ``compressor.cache.get_offline_manifest_filename()`` has been removed.
  You can now use the new file storage ``compressor.storage.default_offline_manifest_storage`` to access the
  location of the manifest.


v4.0 (2022-03-23)
-----------------

`Full list of changes from v3.1 <https://github.com/django-compressor/django-compressor/compare/3.1...4.0>`_

- Fix intermittent No such file or directory errors by changing strategy to
  deal with duplicate filenames in CompressorFileStorage
  
  Note: if your project has a custom storage backend following the example of 
  `CachedS3Boto3Storage` from the "Remote Storages" documentation, it will need
  to be updated to call `save` instead of `_save` to work properly after this
  change to `CompressorFileStorage`.
  
- Deprecate SlimItFilter, stop testing it with Python 3.7 or higher


v3.1 (2021-12-18)
-----------------

`Full list of changes from v3.0 <https://github.com/django-compressor/django-compressor/compare/3.0...3.1>`_

- Fix error with verbose offline compression when COMPRESS_OFFLINE_CONTEXT is a generator


v3.0 (2021-12-12)
-----------------

`Full list of changes from v2.4.1 <https://github.com/django-compressor/django-compressor/compare/2.4.1...3.0>`_

- Officially support Python 3.9 and 3.10 as well as Django 3.1, 3.2 and 4.0
- Drop support for Django 1.11, 2.1 and 3.0
- Drop support for Python 2.x and 3.4
- Fix compatibility with Jinja 3.x
- Require django-sekizai 2.0 for django-sekizai extension
- Make template compression in compress command threaded to improve performance
- Correctly handle relative paths in ``extends`` tags (#979)
- Enable ``rCSSMinFilter`` by default (#888)
- Fix various deprecation warnings
- Add ability to pass a logger to various classes & methods
- Removed deprecated ``COMPRESS_JS_FILTERS`` and ``COMPRESS_CSS_FILTERS`` settings
- Fix offline compression race condition, which could result in incomplete manifest

v2.4.1 (2021-04-17)
-------------------

`Full list of changes from v2.4 <https://github.com/django-compressor/django-compressor/compare/2.4...2.4.1>`_

- Raise proper ``DeprecationWarning`` for ``COMPRESS_JS_FILTERS`` and ``COMPRESS_CSS_FILTERS``


v2.4 (2019-12-31)
-----------------

`Full list of changes from v2.3 <https://github.com/django-compressor/django-compressor/compare/2.3...2.4>`_

- Add support for Django 3.0 (#950, #967)
- Officially support Python 3.8 (#967)
- Add better support for JS strict mode and validation (#952)
- Add support for rel=preload (#951)
- Add support for Calmjs (#957)

Note: in 2.3, a new setting ``COMPRESS_FILTERS`` has been introduced that combines the existing ``COMPRESS_CSS_FILTERS`` and ``COMPRESS_JS_FILTERS``. The latter are now deprecated. See `the docs <https://django-compressor.readthedocs.io/en/stable/settings/#django.conf.settings.COMPRESS_FILTERS>`_ on how to use the new setting, the conversion is straightforward.

v2.3 (2019-05-31)
-----------------

`Full list of changes from v2.2 <https://github.com/django-compressor/django-compressor/compare/2.2...2.3>`_

- Drop support for Django 1.8, 1.9 and 1.10
- Add support for Django 2.1 and 2.2, as well as Python 3.7
- Update all dependencies. This required minor code changes, you might need to update some optional dependencies if you use any
- Allow the mixed use of JS/CSS in Sekizai's templatetags ``{% addtoblock "js" %}`` and ``{% addtoblock "css" %}`` (#891)
- Allow the implementation of new types other than css and js. (#900)
- Update jinja2 extension to behave similar to the django tag (#899)
- Fix crash in offline compression when child nodelist is None, again (#605)
- Support STATIC_URL and COMPRESS_URL being string-like objects
- Improve compress command memory usage (#870)
- Ensure generated file always contains a base name (#775)
- Add BrotliCompressorFileStorage (#867)

v2.2 (2017-08-16)
-----------------

`Full list of changes from v2.1.1 <https://github.com/django-compressor/django-compressor/compare/2.1.1...2.2>`_

- Switch from MD5 to SHA256 for hashes generation.

- Add Django 1.11 compatibility

- Various compatibility fixes for Python 3.6 and Django 1.8

- Made OfflineGenerationError easier to debug

- Drop support for Python 3.2

- Add new CssRelativeFilter which works like CssAbsoluteFilter but outputs relative URLs.

- Fix URL CssAbsoluteFilter URL detection

v2.1.1 (2017-02-02)
-------------------

`Full list of changes from v2.1 <https://github.com/django-compressor/django-compressor/compare/2.1...2.1.1>`_

- Fix to file permissions issue with packaging.


v2.1 (2016-08-09)
-----------------

`Full list of changes from v2.0 <https://github.com/django-compressor/django-compressor/compare/2.0...2.1>`_

- Add Django 1.10 compatibility

- Add support for inheritance using a variable in offline compression

- Fix recursion error with offline compression when extending templates with the same name

- Fix UnicodeDecodeError when using CompilerFilter and caching

- Fix CssAbsoluteFilter changing double quotes to single quotes, breaking SVG


v2.0 (2016-01-07)
-----------------

`Full list of changes from v1.6 <https://github.com/django-compressor/django-compressor/compare/1.6...2.0>`_

- Add Django 1.9 compatibility

- Remove official support for Django 1.4 and 1.7

- Add official support for Python 3.5

- Remove official support for Python 2.6

- Remove support for coffin and jingo

- Fix Jinja2 compatibility for Django 1.8+

- Stop bundling vendored versions of rcssmin and rjsmin, make them proper dependencies

- Remove support for CSSTidy

- Remove support for beautifulsoup 3.

- Replace cssmin by csscompressor (cssmin is still available for backwards-compatibility but points to rcssmin)


v1.6 (2015-11-19)
-----------------

`Full list of changes from v1.5 <https://github.com/django-compressor/django-compressor/compare/1.5...1.6>`_

- Upgrade rcssmin and rjsmin

- Apply CssAbsoluteFilter to precompiled css even when compression is disabled

- Add optional caching to CompilerFilter to avoid re-compiling unchanged files

- Fix various deprecation warnings on Django 1.7 / 1.8

- Fix TemplateFilter

- Fix double-rendering bug with sekizai extension

- Fix debug mode using destination directory instead of staticfiles finders first

- Removed some silent exception catching in compress command


v1.5 (2015-03-27)
-----------------

`Full list of changes from v1.4 <https://github.com/django-compressor/django-compressor/compare/1.4...1.5>`_

- Fix compress command and run automated tests for Django 1.8

- Fix Django 1.8 warnings

- Handle TypeError from import_module

- Fix reading UTF-8 files which have BOM

- Fix incompatibility with Windows (shell_quote is not supported)

- Run automated tests on Django 1.7

- Ignore non-existent {{ block.super }} in offline compression instead of raising AttributeError

- Support for clean-css

- Fix link markup

- Add support for COMPRESS_CSS_HASHING_METHOD = None

- Remove compatibility with old 'staticfiles' app

- In compress command, use get_template() instead of opening template files manually, fixing compatibility issues with custom template loaders

- Fix FilterBase so that does not override self.type for subclasses if filter_type is not specified at init

- Remove unnecessary filename and existence checks in CssAbsoluteFilter


v1.4 (2014-06-20)
-----------------

- Added Python 3 compatibility.

- Added compatibility with Django 1.6.x and dropped support for Django 1.3.X.

- Fixed compatibility with html5lib 1.0.

- Added offline compression for Jinja2 with Jingo and Coffin integration.

- Improved support for template inheritance in offline compression.

- Made offline compression avoid compressing the same block multiple times.

- Added a ``testenv`` target in the Makefile to make it easier to set up the
  test environment.

- Allowed data-uri filter to handle external/protocol-relative references.

- Made ``CssCompressor`` class easier to extend.

- Added support for explicitly stating the block being ended.

- Added rcssmin and updated rjsmin.

- Removed implicit requirement on BeautifulSoup.

- Made GzipCompressorFileStorage set access and modified times to the same time
  as the corresponding base file.

- Defaulted to using django's simplejson, if present.

- Fixed CompilerFilter to always output Unicode strings.

- Fixed windows line endings in offline compression.

v1.3 (2013-03-18)
-----------------

- *Backward incompatible changes*

  -  Dropped support for Python 2.5. Removed ``any`` and ``walk`` compatibility
     functions in ``compressor.utils``.

  - Removed compatibility with some old django setttings:

    - :attr:`~COMPRESS_ROOT` no longer uses ``MEDIA_ROOT`` if ``STATIC_ROOT`` is
      not defined. It expects ``STATIC_ROOT`` to be defined instead.

    - :attr:`~COMPRESS_URL` no longer uses ``MEDIA_URL`` if ``STATIC_URL`` is
      not defined. It expects ``STATIC_URL`` to be defined instead.

    - :attr:`~COMPRESS_CACHE_BACKEND` no longer uses ``CACHE_BACKEND`` and simply
      defaults to ``default``.

- Added precompiler class support. This enables you to write custom precompilers
  with Python logic in them instead of just relying on executables.

- Made CssAbsoluteFilter smarter: it now handles URLs with hash fragments or
  querystring correctly. In addition, it now leaves alone fragment-only URLs.

- Removed a ``fsync()`` call in ``CompilerFilter`` to improve performance.
  We already called ``self.infile.flush()`` so that call was not necessary.

- Added an extension to provide django-sekizai support.
  See :ref:`django-sekizai Support <django-sekizai_support>` for more
  information.

- Fixed a ``DeprecationWarning`` regarding the use of ``django.utils.hashcompat``

- Updated bundled ``rjsmin.py`` to fix some JavaScript compression errors.

v1.2
----

- Added compatibility with Django 1.4 and dropped support for Django 1.2.X.

- Added contributing docs. Be sure to check them out and start contributing!

- Moved CI to Travis: http://travis-ci.org/django-compressor/django-compressor

- Introduced a new ``compressed`` context dictionary that is passed to
  the templates that are responsible for rendering the compressed snippets.

  This is a **backwards-incompatible change** if you've overridden any of
  the included templates:

  - ``compressor/css_file.html``
  - ``compressor/css_inline.html``
  - ``compressor/js_file.html``
  - ``compressor/js_inline.html``

  The variables passed to those templates have been namespaced in a
  dictionary, so it's easy to fix your own templates.

  For example, the old ``compressor/js_file.html``::

    <script type="text/javascript" src="{{ url }}"></script>

  The new ``compressor/js_file.html``::

    <script type="text/javascript" src="{{ compressed.url }}"></script>

- Removed old templates named ``compressor/css.html`` and
  ``compressor/js.html`` that were originally left for backwards
  compatibility. If you've overridden them, just rename them to
  ``compressor/css_file.html`` or ``compressor/js_file.html`` and
  make sure you've accounted for the backwards incompatible change
  of the template context mentioned above.

- Reverted an unfortunate change to the YUI filter that prepended
  ``'java -jar'`` to the binary name, which doesn't alway work, e.g.
  if the YUI compressor is shipped as a script like
  ``/usr/bin/yui-compressor``.

- Changed the sender parameter of the :func:`~compressor.signals.post_compress`
  signal to be either :class:`compressor.css.CssCompressor` or
  :class:`compressor.js.JsCompressor` for easier customization.

- Correctly handle offline compressing files that are found in ``{% if %}``
  template blocks.

- Renamed the second option for the ``COMPRESS_CSS_HASHING_METHOD`` setting
  from ``'hash'`` to ``'content'`` to better describe what it does. The old
  name is also supported, as well as the default being ``'mtime'``.

- Fixed CssAbsoluteFilter, ``src`` attributes in includes now get transformed.

- Added a new hook to allow developers to completely bypass offline
  compression in CompressorNode subclasses: ``is_offline_compression_enabled``.

- Dropped versiontools from required dependencies again.

v1.1.2
------

- Fixed an installation issue related to versiontools.

v1.1.1
------

- Fixed a stupid ImportError bug introduced in 1.1.

- Fixed Jinja2 docs of since ``JINJA2_EXTENSIONS`` expects
  a class, not a module.

- Fixed a Windows bug with regard to file resolving with
  staticfiles finders.

- Stopped a potential memory leak when memoizing the rendered
  output.

- Fixed the integration between staticfiles (e.g. in Django <= 1.3.1)
  and compressor which prevents the collectstatic management command
  to work.

  .. warning::

     Make sure to **remove** the ``path`` method of your custom
     :ref:`remote storage <remote_storages>` class!

v1.1
----

- Made offline compression completely independent from cache (by writing a
  manifest.json file).

  You can now easily run the ``compress`` management command locally and
  transfer the :attr:`~django.conf.settings.COMPRESS_ROOT` dir to your server.

- Updated installation instructions to properly mention all dependencies,
  even those internally used.

- Fixed a bug introduced in 1.0 which would prevent the proper deactivation
  of the compression in production.

- Added a Jinja2_ :doc:`contrib extension </jinja2>`.

- Made sure the rel attribute of link tags can be mixed case.

- Avoid overwriting context variables needed for compressor to work.

- Stopped the compress management command to require model validation.

- Added missing imports and fixed a few :pep:`8` issues.

.. _Jinja2: http://jinja.pocoo.org/2/

v1.0.1
------

- Fixed regression in ``compressor.utils.staticfiles`` compatibility
  module.

v1.0
----

- **BACKWARDS-INCOMPATIBLE** Stopped swallowing exceptions raised by
  rendering the template tag in production (``DEBUG = False``). This
  has the potential to breaking lots of apps but on the other hand
  will help find bugs.

- **BACKWARDS-INCOMPATIBLE** The default function to create the cache
  key stopped containing the server hostname. Instead the cache key
  now only has the form ``'django_compressor.<KEY>'``.

  To revert to the previous way simply set the ``COMPRESS_CACHE_KEY_FUNCTION``
  to ``'compressor.cache.socket_cachekey'``.

- **BACKWARDS-INCOMPATIBLE** Renamed ambigously named
  ``COMPRESS_DATA_URI_MAX_SIZE`` setting to ``COMPRESS_DATA_URI_MAX_SIZE``.
  It's the maximum size the ``compressor.filters.datauri.DataUriFilter``
  filter will embed files as data: URIs.

- Added ``COMPRESS_CSS_HASHING_METHOD`` setting with the options ``'mtime'``
  (default) and ``'hash'`` for the ``CssAbsoluteFilter`` filter. The latter
  uses the content of the file to calculate the cache-busting hash.

- Added support for ``{{ block.super }}`` to ``compress`` management command.

- Dropped Django 1.1.X support.

- Fixed compiler filters on Windows.

- Handle new-style cached template loaders in the compress management command.

- Documented included filters.

- Added `Slim It`_ filter.

- Added new CallbackOutputFilter to ease the implementation of Python-based
  callback filters that only need to pass the content to a callable.

- Make use of `django-appconf`_ for settings handling and `versiontools`_
  for versions.

- Uses the current context when rendering the render templates.

- Added :func:`post_compress<compressor.signals.post_compress>` signal.

.. _`Slim It`: http://slimit.org/
.. _`django-appconf`: https://django-appconf.readthedocs.io/
.. _`versiontools`: http://pypi.python.org/pypi/versiontools

v0.9.2
------

- Fixed stdin handling of precompiler filter.

v0.9.1
------

- Fixed encoding related issue.

- Minor cleanups.

v0.9
----

- Fixed the precompiler support to also use the full file path instead of a
  temporarily created file.

- Enabled test coverage.

- Refactored caching and other utility code.

- Switched from SHA1 to MD5 for hash generation to lower the computational impact.

v0.8
----

- Replace naive jsmin.py with rJSmin (http://opensource.perlig.de/rjsmin/)
  and fixed a few problems with JavaScript comments.

- Fixed converting relative URLs in CSS files when running in debug mode.

.. note::

    If you relied on the ``split_contents`` method of ``Compressor`` classes,
    please make sure a fourth item is returned in the iterable that denotes
    the base name of the file that is compressed.

v0.7.1
------

- Fixed import error when using the standalone django-staticfiles app.

v0.7
----

- Created new parser, HtmlParser, based on the stdlib HTMLParser module.

- Added a new default AutoSelectParser, which picks the LxmlParser if lxml
  is available and falls back to HtmlParser.

- Use unittest2 for testing goodness.

- Fixed YUI JavaScript filter argument handling.

- Updated bundled jsmin to use version by Dave St.Germain that was refactored for speed.

v0.6.4
------

- Fixed Closure filter argument handling.

v0.6.3
------

- Fixed options mangling in CompilerFilter initialization.

- Fixed tox configuration.

- Extended documentation and README.

- In the compress command ignore hidden files when looking for templates.

- Restructured utilities and added staticfiles compat layer.

- Restructered parsers and added a html5lib based parser.

v0.6.2
------

- Minor bugfixes that caused the compression not working reliably in
  development mode (e.g. updated files didn't trigger a new compression).

v0.6.1
------

- Fixed staticfiles support to also use its finder API to find files during
  development -- when the static files haven't been collected in
  ``STATIC_ROOT``.

- Fixed regression with the ``COMPRESS`` setting, pre-compilation and
  staticfiles.

v0.6
----

Major improvements and a lot of bugfixes, some of which are:

- New precompilation support, which allows compilation of files and
  hunks with easily configurable compilers before calling the actual
  output filters. See the
  :attr:`~django.conf.settings.COMPRESS_PRECOMPILERS` for more details.

- New staticfiles support. With the introduction of the staticfiles app
  to Django 1.3, compressor officially supports finding the files to
  compress using the app's finder API. Have a look at the documentation
  about :ref:`remote storages <remote_storages>` in case you want to use
  those together with compressor.

- New ``compress`` management command which allows pre-running of what the
  compress template tag does.

- Various performance improvements by better caching and mtime cheking.

- Deprecated ``COMPRESS_LESSC_BINARY`` setting because it's now
  superseded by the :attr:`~django.conf.settings.COMPRESS_PRECOMPILERS`
  setting. Just make sure to use the correct mimetype when linking to less
  files or adding inline code and add the following to your settings::

      COMPRESS_PRECOMPILERS = (
          ('text/less', 'lessc {infile} {outfile}'),
      )

- Added cssmin_ filter (``compressor.filters.CSSMinFilter``) based on
  Zachary Voase's Python port of the YUI CSS compression algorithm.

- Reimplemented the dog-piling prevention.

- Make sure the CssAbsoluteFilter works for relative paths.

- Added inline render mode. See :ref:`usage <usage>` docs.

- Added ``mtime_cache`` management command to add and/or remove all mtimes
  from the cache.

- Moved docs to Read The Docs: https://django-compressor.readthedocs.io/en/latest/

- Added optional ``compressor.storage.GzipCompressorFileStorage`` storage
  backend that gzips of the saved files automatically for easier deployment.

- Reimplemented a few filters on top of the new
  ``compressor.filters.base.CompilerFilter`` to be a bit more DRY.

- Added tox based test configuration, testing on Django 1.1-1.3 and Python
  2.5-2.7.

.. _cssmin: http://pypi.python.org/pypi/cssmin/

