Skip to content
Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ For more general information, view the [readme](README.md).
Releases are added to the
[github release page](https://github.com/ezhome/django-webpack-loader/releases).

## [3.0.1] -- 2023-12-29

Added `skip_common_chunks` option to the `get_files()` template tag.

## [3.0.0] -- 2023-12-19

- Fix support for `publicPath: auto` in Webpack config, check updated examples at https://github.com/django-webpack/django-webpack-loader/tree/master/examples
Expand Down
36 changes: 18 additions & 18 deletions tests/app/tests/test_webpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,9 @@ def test_emits_warning_on_no_request_in_djangoengine(self):
) # type: Template
request = self.factory.get(path='/')
output = nodups_template.render(context=Context({'request': request}))
used_tags = getattr(request, '_webpack_loader_used_tags', None)
self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
used_urls = getattr(request, '_webpack_loader_used_urls', None)
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))
self.assertEqual(output.count(asset_app1), 1)
self.assertEqual(output.count(asset_app2), 1)
self.assertEqual(output.count(asset_vendor), 1)
Expand Down Expand Up @@ -518,9 +518,9 @@ def test_emits_warning_on_no_request_in_jinja2engine(self):
template_name='home-deduplicated.jinja'
) # type: Jinja2Template
output = nodups_template.render(request=request)
used_tags = getattr(request, '_webpack_loader_used_tags', None)
self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
used_urls = getattr(request, '_webpack_loader_used_urls', None)
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))
self.assertEqual(output.count(asset_app1), 1)
self.assertEqual(output.count(asset_app2), 1)
self.assertEqual(output.count(asset_vendor), 1)
Expand All @@ -546,10 +546,10 @@ def _assert_common_chunks_duplicated_djangoengine(self, template):
'</script>')
rendered_template = template.render(
context=None, request=request)
used_tags = getattr(request, '_webpack_loader_used_tags', None)
used_urls = getattr(request, '_webpack_loader_used_urls', None)

self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))
self.assertEqual(rendered_template.count(asset_app1), 1)
self.assertEqual(rendered_template.count(asset_app2), 1)
self.assertEqual(rendered_template.count(asset_vendor), 2)
Expand All @@ -573,10 +573,10 @@ def _assert_common_chunks_not_duplicated_djangoengine(self, template):
'</script>')
rendered_template = template.render(
context=None, request=request)
used_tags = getattr(request, '_webpack_loader_used_tags', None)
used_urls = getattr(request, '_webpack_loader_used_urls', None)

self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))
self.assertEqual(rendered_template.count(asset_app1), 1)
self.assertEqual(rendered_template.count(asset_app2), 1)
self.assertEqual(rendered_template.count(asset_vendor), 1)
Expand Down Expand Up @@ -620,9 +620,9 @@ def _assert_common_chunks_duplicated_jinja2engine(self, view):
self.assertEqual(content.count(asset_vendor), 4)
self.assertEqual(content.count(asset_app1), 2)
self.assertEqual(content.count(asset_app2), 2)
used_tags = getattr(request, '_webpack_loader_used_tags', None)
self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
used_urls = getattr(request, '_webpack_loader_used_urls', None)
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))

def _assert_common_chunks_not_duplicated_jinja2engine(self, view):
"""
Expand Down Expand Up @@ -663,9 +663,9 @@ def _assert_common_chunks_not_duplicated_jinja2engine(self, view):
self.assertEqual(content.count(asset_vendor), 1)
self.assertEqual(content.count(asset_app1), 1)
self.assertEqual(content.count(asset_app2), 1)
used_tags = getattr(request, '_webpack_loader_used_tags', None)
self.assertIsNotNone(used_tags, msg=(
'_webpack_loader_used_tags should be a property of request!'))
used_urls = getattr(request, '_webpack_loader_used_urls', None)
self.assertIsNotNone(used_urls, msg=(
'_webpack_loader_used_urls should be a property of request!'))

def test_skip_common_chunks_templatetag_djangoengine(self):
"""Test case for deduplication of modules with the django engine via the render_bundle template tag."""
Expand Down
2 changes: 1 addition & 1 deletion webpack_loader/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__author__ = "Vinta Software"
__version__ = "3.0.0"
__version__ = "3.0.1"

import django

Expand Down
8 changes: 7 additions & 1 deletion webpack_loader/contrib/jinja2ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
from jinja2.runtime import Context
from jinja2.utils import pass_context

from ..templatetags.webpack_loader import render_bundle
from ..templatetags.webpack_loader import get_files, render_bundle


@pass_context
def _render_bundle(context: Context, *args, **kwargs):
return render_bundle(context, *args, **kwargs)


@pass_context
def _get_files(context: Context, *args, **kwargs):
return get_files(context=context, *args, **kwargs)


class WebpackExtension(Extension):
def __init__(self, environment):
super(WebpackExtension, self).__init__(environment)
environment.globals["render_bundle"] = _render_bundle
environment.globals["webpack_get_files"] = _get_files
40 changes: 29 additions & 11 deletions webpack_loader/templatetags/webpack_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'You have specified skip_common_chunks=True but the passed context '
'doesn\'t have a request. django_webpack_loader needs a request object to '
'filter out duplicate chunks. Please see https://github.com/django-webpack'
'/django-webpack-loader#skipping-the-generation-of-multiple-common-chunks')
'/django-webpack-loader#use-skip_common_chunks-on-render_bundle')


@register.simple_tag(takes_context=True)
Expand All @@ -26,33 +26,51 @@ def render_bundle(
if request is None:
if skip_common_chunks:
warn(message=_WARNING_MESSAGE, category=RuntimeWarning)
return mark_safe('\n'.join(tags))
used_tags = getattr(request, '_webpack_loader_used_tags', None)
if not used_tags:
used_tags = request._webpack_loader_used_tags = set()
return mark_safe('\n'.join(tags.values()))
used_urls = getattr(request, '_webpack_loader_used_urls', None)
if not used_urls:
used_urls = request._webpack_loader_used_urls = set()
if skip_common_chunks:
tags = [tag for tag in tags if tag not in used_tags]
used_tags.update(tags)
return mark_safe('\n'.join(tags))
tags = {url: tag for url, tag in tags.items() if url not in used_urls}
used_urls.update(tags)
return mark_safe('\n'.join(tags.values()))


@register.simple_tag
def webpack_static(asset_name, config='DEFAULT'):
return utils.get_static(asset_name, config=config)


@register.simple_tag
def get_files(bundle_name, extension=None, config='DEFAULT'):
@register.simple_tag(takes_context=True)
def get_files(
context, bundle_name, extension=None, config='DEFAULT',
skip_common_chunks=None):
"""
Returns all chunks in the given bundle.
Example usage::

{% get_files 'editor' 'css' as editor_css_chunks %}
CKEDITOR.config.contentsCss = '{{ editor_css_chunks.0.url }}';

:param context: The request, if you want to use `skip_common_chunks`
:param bundle_name: The name of the bundle
:param extension: (optional) filter by extension
:param config: (optional) the name of the configuration
:param skip_common_chunks: (optional) `True` if you want to skip returning already rendered common chunks
:return: a list of matching chunks
"""
return utils.get_files(bundle_name, extension=extension, config=config)
if skip_common_chunks is None:
skip_common_chunks = utils.get_skip_common_chunks(config)
if not skip_common_chunks:
return utils.get_files(bundle_name, extension=extension, config=config)
request = context.get('request')
result = utils.get_files(bundle_name, extension=extension, config=config)
if not skip_common_chunks:
return result
if request is None:
warn(message=_WARNING_MESSAGE, category=RuntimeWarning)
return result
used_urls = getattr(request, '_webpack_loader_used_urls', None)
if not used_urls:
used_urls = request._webpack_loader_used_urls = set()
return [x for x in result if x['url'] not in used_urls]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's more code here, we need to test this. Can you add tests that covers all conditions here?

17 changes: 9 additions & 8 deletions webpack_loader/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import OrderedDict
from importlib import import_module
from django.conf import settings
from .config import load_config
Expand Down Expand Up @@ -69,32 +70,32 @@ def get_as_tags(bundle_name, extension=None, config='DEFAULT', suffix='', attrs=

loader = get_loader(config)
bundle = _get_bundle(loader, bundle_name, extension)
tags = []
result = OrderedDict()

for chunk in bundle:
if chunk['name'].endswith(('.js', '.js.gz')):
if is_preload:
tags.append((
result[chunk['url']] = (
'<link rel="preload" as="script" href="{0}" {1}/>'
).format(''.join([chunk['url'], suffix]), attrs))
).format(''.join([chunk['url'], suffix]), attrs)
else:
tags.append((
result[chunk['url']] = (
'<script src="{0}"{2}{1}></script>'
).format(
''.join([chunk['url'], suffix]),
attrs,
loader.get_integrity_attr(chunk),
))
)
elif chunk['name'].endswith(('.css', '.css.gz')):
tags.append((
result[chunk['url']] = (
'<link href="{0}" rel={2}{3}{1}/>'
).format(
''.join([chunk['url'], suffix]),
attrs,
'"stylesheet"' if not is_preload else '"preload" as="style"',
loader.get_integrity_attr(chunk),
))
return tags
)
return result


def get_static(asset_name, config='DEFAULT'):
Expand Down