Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-django-webpack-loader for
openSUSE:Factory checked in at 2026-07-06 12:31:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-webpack-loader (Old)
and /work/SRC/openSUSE:Factory/.python-django-webpack-loader.new.1982
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-webpack-loader"
Mon Jul 6 12:31:18 2026 rev:16 rq:1363827 version:3.2.4
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-django-webpack-loader/python-django-webpack-loader.changes
2026-03-31 16:26:55.366486177 +0200
+++
/work/SRC/openSUSE:Factory/.python-django-webpack-loader.new.1982/python-django-webpack-loader.changes
2026-07-06 12:33:49.234494688 +0200
@@ -1,0 +2,14 @@
+Sun Jul 5 09:08:52 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 3.2.4:
+ * Refactor `get_as_url_to_tag_dict` when dealing with extra
+ arguments in elements
+ * Fix `skip_common_chunks` usage at `get_files` to add parity
+ with `render_bundle`
+ * Add integrity and CSP nonce to preload script tags
+ * Fix hanging or broken stats file
+ * Handle issue when webpack stats change mid-request
+ * Fix `AttributeError` in config check for non-dict
+ `WEBPACK_LOADER`
+
+-------------------------------------------------------------------
Old:
----
3.2.3.tar.gz
New:
----
3.2.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-django-webpack-loader.spec ++++++
--- /var/tmp/diff_new_pack.HQFlR9/_old 2026-07-06 12:33:49.746512475 +0200
+++ /var/tmp/diff_new_pack.HQFlR9/_new 2026-07-06 12:33:49.750512613 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-django-webpack-loader
-Version: 3.2.3
+Version: 3.2.4
Release: 0
Summary: Django plugin to transparently use webpack
License: MIT
++++++ 3.2.3.tar.gz -> 3.2.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/CHANGELOG.md
new/django-webpack-loader-3.2.4/CHANGELOG.md
--- old/django-webpack-loader-3.2.3/CHANGELOG.md 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/CHANGELOG.md 2026-05-13
16:47:25.000000000 +0200
@@ -5,6 +5,15 @@
Releases are added to the
[github release
page](https://github.com/ezhome/django-webpack-loader/releases).
+## [3.2.4] -- 2026-05-13
+
+- Refactor `get_as_url_to_tag_dict` when dealing with extra arguments in
elements
+- Fix `skip_common_chunks` usage at `get_files` to add parity with
`render_bundle` (#431)
+- Add integrity and CSP nonce to preload script tags (#432)
+- Fix hanging or broken stats file (#430)
+- Handle issue when webpack stats change mid-request (#429)
+- Fix `AttributeError` in config check for non-dict `WEBPACK_LOADER` (#427)
+
## [3.2.3] -- 2025-12-09
- Add warning for default timeout usage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/examples/code-splitting/package.json
new/django-webpack-loader-3.2.4/examples/code-splitting/package.json
--- old/django-webpack-loader-3.2.3/examples/code-splitting/package.json
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/examples/code-splitting/package.json
2026-05-13 16:47:25.000000000 +0200
@@ -13,7 +13,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/examples/dynamic-imports/package.json
new/django-webpack-loader-3.2.4/examples/dynamic-imports/package.json
--- old/django-webpack-loader-3.2.3/examples/dynamic-imports/package.json
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/examples/dynamic-imports/package.json
2026-05-13 16:47:25.000000000 +0200
@@ -13,7 +13,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/examples/hot-reload/package.json
new/django-webpack-loader-3.2.4/examples/hot-reload/package.json
--- old/django-webpack-loader-3.2.3/examples/hot-reload/package.json
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/examples/hot-reload/package.json
2026-05-13 16:47:25.000000000 +0200
@@ -15,7 +15,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/examples/simple/package.json
new/django-webpack-loader-3.2.4/examples/simple/package.json
--- old/django-webpack-loader-3.2.3/examples/simple/package.json
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/examples/simple/package.json
2026-05-13 16:47:25.000000000 +0200
@@ -15,7 +15,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/setup.cfg
new/django-webpack-loader-3.2.4/setup.cfg
--- old/django-webpack-loader-3.2.3/setup.cfg 2025-12-09 19:15:32.000000000
+0100
+++ new/django-webpack-loader-3.2.4/setup.cfg 2026-05-13 16:47:25.000000000
+0200
@@ -1,2 +1,2 @@
[metadata]
-description_file = README.rst
+description_file = README.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/setup.py
new/django-webpack-loader-3.2.4/setup.py
--- old/django-webpack-loader-3.2.3/setup.py 2025-12-09 19:15:32.000000000
+0100
+++ new/django-webpack-loader-3.2.4/setup.py 2026-05-13 16:47:25.000000000
+0200
@@ -1,7 +1,7 @@
import os
import re
-from setuptools import setup
+from setuptools import find_packages, setup
def rel(*parts):
@@ -9,7 +9,7 @@
return os.path.abspath(os.path.join(os.path.dirname(__file__), *parts))
-with open("README.md", "r") as handler:
+with open(rel("README.md"), "r", encoding="utf-8") as handler:
README = handler.read()
with open(rel("webpack_loader", "__init__.py")) as handler:
@@ -20,11 +20,7 @@
setup(
name="django-webpack-loader",
- packages=[
- "webpack_loader",
- "webpack_loader/templatetags",
- "webpack_loader/contrib",
- ],
+ packages=find_packages(),
version=VERSION,
license="MIT License",
description="Transparently use webpack with django",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/tests/app/tests/test_webpack.py
new/django-webpack-loader-3.2.4/tests/app/tests/test_webpack.py
--- old/django-webpack-loader-3.2.3/tests/app/tests/test_webpack.py
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests/app/tests/test_webpack.py
2026-05-13 16:47:25.000000000 +0200
@@ -23,6 +23,7 @@
WebpackLoaderBadStatsError,
WebpackLoaderTimeoutError,
)
+from webpack_loader.loaders import WebpackLoader
from webpack_loader.templatetags.webpack_loader import _WARNING_MESSAGE
from webpack_loader.utils import get_as_tags, get_loader,
get_as_url_to_tag_dict
@@ -64,6 +65,11 @@
expected_errors = []
self.assertEqual(errors, expected_errors)
+ with self.settings(WEBPACK_LOADER='__WRONG__'):
+ errors = webpack_cfg_check(None)
+ expected_errors = [BAD_CONFIG_ERROR]
+ self.assertEqual(errors, expected_errors)
+
def test_simple_and_css_extract(self):
self.compile_bundles('webpack.config.simple.js')
assets = get_loader(DEFAULT_CONFIG).get_assets()
@@ -153,35 +159,37 @@
view = TemplateView.as_view(template_name='home.html')
request = self.factory.get('/')
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
'<link href="/static/django_webpack_loader_bundles/main.css" '
- 'rel="stylesheet" />'),
- result.rendered_content)
+ 'rel="stylesheet"/>'),
+ rendered_content)
self.assertIn((
'<script src="/static/django_webpack_loader_bundles/main.js" '
- 'async charset="UTF-8"></script>'), result.rendered_content)
+ 'async charset="UTF-8"></script>'), rendered_content)
self.assertIn((
'<link href="/static/django_webpack_loader_bundles/app2.css" '
- 'rel="stylesheet" />'), result.rendered_content)
+ 'rel="stylesheet"/>'), rendered_content)
self.assertIn((
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
- '</script>'), result.rendered_content)
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
+ '</script>'), rendered_content)
self.assertIn(
- '<img src="/static/my-image.png"/>', result.rendered_content)
+ '<img src="/static/my-image.png"/>', rendered_content)
- self.assertIn('<li>All from getFiles already rendered</li>',
result.rendered_content)
+ self.assertIn('<li>All from getFiles already rendered</li>',
rendered_content)
request = self.factory.get('/')
view = TemplateView.as_view(template_name='only_files.html')
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
"var contentCss = "
"'/static/django_webpack_loader_bundles/main.css'"),
- result.rendered_content)
+ rendered_content)
self.assertIn(
"var contentJS = '/static/django_webpack_loader_bundles/main.js'",
- result.rendered_content)
+ rendered_content)
self.compile_bundles('webpack.config.publicPath.js')
request = self.factory.get('/')
@@ -197,23 +205,24 @@
view = TemplateView.as_view(template_name='preload.html')
request = self.factory.get('/')
result = view(request)
+ rendered_content = result.rendered_content
# Preload
self.assertIn((
'<link href="/static/django_webpack_loader_bundles/main.css" '
- 'rel="preload" as="style" />'), result.rendered_content)
+ 'rel="preload" as="style"/>'), rendered_content)
self.assertIn((
'<link rel="preload" as="script" href="/static/'
- 'django_webpack_loader_bundles/main.js" />'),
- result.rendered_content)
+ 'django_webpack_loader_bundles/main.js"/>'),
+ rendered_content)
# Resources
self.assertIn((
'<link href="/static/django_webpack_loader_bundles/main.css" '
- 'rel="stylesheet" />'), result.rendered_content)
+ 'rel="stylesheet"/>'), rendered_content)
self.assertIn((
- '<script src="/static/django_webpack_loader_bundles/main.js" >'
- '</script>'), result.rendered_content)
+ '<script src="/static/django_webpack_loader_bundles/main.js">'
+ '</script>'), rendered_content)
def test_integrity(self):
self.compile_bundles('webpack.config.integrity.js')
@@ -223,22 +232,23 @@
view = TemplateView.as_view(template_name='single.html')
request = self.factory.get('/')
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
'<script src="http://custom-static-host.com/main.js" '
'integrity="sha256-Yk6uAc7SoE41LSNc9zTBxij8YhVqBIIuRpLCaTyqrl'
'Q= sha384-cwtz5c2CaEK8Q8ZeraWgf3qo7eO5jUDE8XMo00QTUCcbmF/fLu'
'DtQFm8g4Jh9R5D sha512-s9uhbJTCZv4WfH/F81fgS6B6XNhOuH21Xouv5X'
- 'Pp35WlFR7ykkIafUG8cma4vbEfheH1NVbjsON5BHm8U13I4g==" >'
- '</script>'), result.rendered_content)
+ 'Pp35WlFR7ykkIafUG8cma4vbEfheH1NVbjsON5BHm8U13I4g==">'
+ '</script>'), rendered_content)
self.assertIn((
'<link href="http://custom-static-host.com/main.css" '
'rel="stylesheet" integrity="sha256-cYWwRvS04/VsttQYx4BalKYrB'
'Duw5t8vKFhWB/LKX30= sha384-V/UxbrsEy8BK5nd+sBlN31Emmq/WdDDdI'
'01UR8wKIFkIr6vEaT5YRaeLMfLcAQvS sha512-aigPxglXDA33t9s5i0vRa'
'p5b7dFwyp7cSN6x8rOXrPpCTMubOR7qTFpmTIa8z9B0wtXxbSheBPNCEURBH'
- 'KLQPw==" />'),
- result.rendered_content
+ 'KLQPw=="/>'),
+ rendered_content
)
def test_integrity_with_crossorigin_empty(self):
@@ -250,6 +260,7 @@
request = self.factory.get('/')
request.META['HTTP_HOST'] = 'crossorigin-custom-static-host.com'
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
'<script src="http://custom-static-host.com/main.js" '
@@ -257,8 +268,8 @@
'sha384-cwtz5c2CaEK8Q8ZeraWgf3qo7eO5jUDE8XMo00QTUCcbmF/fLuDtQFm8'
'g4Jh9R5D
sha512-s9uhbJTCZv4WfH/F81fgS6B6XNhOuH21Xouv5XPp35WlFR7'
'ykkIafUG8cma4vbEfheH1NVbjsON5BHm8U13I4g==" '
- 'crossorigin ></script>'
- ), result.rendered_content)
+ 'crossorigin></script>'
+ ), rendered_content)
self.assertIn((
'<link href="http://custom-static-host.com/main.css" '
'rel="stylesheet" '
@@ -266,8 +277,8 @@
'sha384-V/UxbrsEy8BK5nd+sBlN31Emmq/WdDDdI01UR8wKIFkIr6vEaT5YRaeL'
'MfLcAQvS
sha512-aigPxglXDA33t9s5i0vRap5b7dFwyp7cSN6x8rOXrPpCTMu'
'bOR7qTFpmTIa8z9B0wtXxbSheBPNCEURBHKLQPw==" '
- 'crossorigin />'),
- result.rendered_content
+ 'crossorigin/>'),
+ rendered_content
)
def test_integrity_with_crossorigin_anonymous(self):
@@ -279,6 +290,7 @@
request = self.factory.get('/')
request.META['HTTP_HOST'] = 'crossorigin-custom-static-host.com'
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
'<script src="http://custom-static-host.com/main.js" '
@@ -286,8 +298,8 @@
'sha384-cwtz5c2CaEK8Q8ZeraWgf3qo7eO5jUDE8XMo00QTUCcbmF/fLuDtQFm8'
'g4Jh9R5D
sha512-s9uhbJTCZv4WfH/F81fgS6B6XNhOuH21Xouv5XPp35WlFR7'
'ykkIafUG8cma4vbEfheH1NVbjsON5BHm8U13I4g==" '
- 'crossorigin="anonymous" ></script>'
- ), result.rendered_content)
+ 'crossorigin="anonymous"></script>'
+ ), rendered_content)
self.assertIn((
'<link href="http://custom-static-host.com/main.css" '
'rel="stylesheet" '
@@ -295,8 +307,8 @@
'sha384-V/UxbrsEy8BK5nd+sBlN31Emmq/WdDDdI01UR8wKIFkIr6vEaT5YRaeL'
'MfLcAQvS
sha512-aigPxglXDA33t9s5i0vRap5b7dFwyp7cSN6x8rOXrPpCTMu'
'bOR7qTFpmTIa8z9B0wtXxbSheBPNCEURBHKLQPw==" '
- 'crossorigin="anonymous" />'),
- result.rendered_content
+ 'crossorigin="anonymous"/>'),
+ rendered_content
)
def test_integrity_with_crossorigin_use_credentials(self):
@@ -308,6 +320,7 @@
request = self.factory.get('/')
request.META['HTTP_HOST'] = 'crossorigin-custom-static-host.com'
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
'<script src="http://custom-static-host.com/main.js" '
@@ -315,8 +328,8 @@
'sha384-cwtz5c2CaEK8Q8ZeraWgf3qo7eO5jUDE8XMo00QTUCcbmF/fLuDtQFm8'
'g4Jh9R5D
sha512-s9uhbJTCZv4WfH/F81fgS6B6XNhOuH21Xouv5XPp35WlFR7'
'ykkIafUG8cma4vbEfheH1NVbjsON5BHm8U13I4g==" '
- 'crossorigin="use-credentials" ></script>'
- ), result.rendered_content)
+ 'crossorigin="use-credentials"></script>'
+ ), rendered_content)
self.assertIn((
'<link href="http://custom-static-host.com/main.css" '
'rel="stylesheet" '
@@ -324,8 +337,8 @@
'sha384-V/UxbrsEy8BK5nd+sBlN31Emmq/WdDDdI01UR8wKIFkIr6vEaT5YRaeL'
'MfLcAQvS
sha512-aigPxglXDA33t9s5i0vRap5b7dFwyp7cSN6x8rOXrPpCTMu'
'bOR7qTFpmTIa8z9B0wtXxbSheBPNCEURBHKLQPw==" '
- 'crossorigin="use-credentials" />'),
- result.rendered_content
+ 'crossorigin="use-credentials"/>'),
+ rendered_content
)
def test_integrity_missing_config(self):
@@ -338,14 +351,15 @@
view = TemplateView.as_view(template_name='single.html')
request = self.factory.get('/')
result = view(request)
+ rendered_content = result.rendered_content
self.assertIn((
- '<script src="http://custom-static-host.com/main.js" >'
- '</script>'), result.rendered_content
+ '<script src="http://custom-static-host.com/main.js">'
+ '</script>'), rendered_content
)
self.assertIn((
- '<link href="http://custom-static-host.com/main.css"
rel="stylesheet" />'),
- result.rendered_content
+ '<link href="http://custom-static-host.com/main.css"
rel="stylesheet"/>'),
+ rendered_content
)
# return removed key
@@ -367,7 +381,7 @@
result = view(request)
self.assertIn((
- '<script src="/static/django_webpack_loader_bundles/main.js.gz" >'
+ '<script src="/static/django_webpack_loader_bundles/main.js.gz">'
'</script>'), result.rendered_content)
def test_jinja2(self):
@@ -390,12 +404,14 @@
with self.settings(**settings):
request = self.factory.get('/')
result = view(request)
+ rendered_content = result.rendered_content
+
self.assertIn((
'<link href="/static/django_webpack_loader_bundles'
- '/main.css" rel="stylesheet" />'), result.rendered_content)
+ '/main.css" rel="stylesheet"/>'), rendered_content)
self.assertIn((
'<script src="/static/django_webpack_loader_bundles/main.js" '
- 'async charset="UTF-8"></script>'), result.rendered_content)
+ 'async charset="UTF-8"></script>'), rendered_content)
def test_reporting_errors(self):
self.compile_bundles('webpack.config.error.js')
@@ -415,6 +431,127 @@
'Cannot resolve bundle {0}'.format(missing_bundle_name),
str(e))
+ def test_get_bundle_uses_same_assets_snapshot_when_iterated(self):
+ class ChangingAssetsLoader(WebpackLoader):
+ def __init__(self, name, config):
+ super().__init__(name, config)
+ self.load_assets_calls = 0
+ self.assets_snapshots = [
+ {
+ 'status': 'done',
+ 'chunks': {'main': ['old.js']},
+ 'assets': {'old.js': {'name': 'old.js'}},
+ },
+ {
+ 'status': 'done',
+ 'chunks': {'main': ['new.js']},
+ 'assets': {'new.js': {'name': 'new.js'}},
+ },
+ ]
+
+ def load_assets(self):
+ snapshot_index = min(
+ self.load_assets_calls, len(self.assets_snapshots) - 1)
+ self.load_assets_calls += 1
+ return self.assets_snapshots[snapshot_index]
+
+ loader = ChangingAssetsLoader(DEFAULT_CONFIG, {
+ 'CACHE': False,
+ 'BUNDLE_DIR_NAME': 'django_webpack_loader_bundles/',
+ 'TIMEOUT': None,
+ 'POLL_INTERVAL': 0.1,
+ 'ignores': [],
+ 'INTEGRITY': False,
+ })
+
+ bundle = loader.get_bundle('main')
+
+ self.assertEqual(list(bundle), [{
+ 'name': 'old.js',
+ 'url': '/static/django_webpack_loader_bundles/old.js',
+ }])
+ self.assertEqual(loader.load_assets_calls, 1)
+
+ def test_cached_compile_status_is_reloaded_while_debug_polling(self):
+ class CompilingThenDoneLoader(WebpackLoader):
+ def __init__(self, name, config):
+ super().__init__(name, config)
+ self.load_assets_calls = 0
+ self.assets_snapshots = [
+ {'status': 'compile'},
+ {
+ 'status': 'done',
+ 'chunks': {'main': ['main.js']},
+ 'assets': {'main.js': {'name': 'main.js'}},
+ },
+ ]
+
+ def load_assets(self):
+ snapshot_index = min(
+ self.load_assets_calls, len(self.assets_snapshots) - 1)
+ self.load_assets_calls += 1
+ return self.assets_snapshots[snapshot_index]
+
+ loader = CompilingThenDoneLoader('COMPILE_CACHE_DEBUG', {
+ 'CACHE': True,
+ 'BUNDLE_DIR_NAME': 'django_webpack_loader_bundles/',
+ 'TIMEOUT': 1,
+ 'POLL_INTERVAL': 0,
+ 'ignores': [],
+ 'INTEGRITY': False,
+ })
+
+ with self.settings(DEBUG=True):
+ bundle = loader.get_bundle('main')
+
+ self.assertEqual(list(bundle), [{
+ 'name': 'main.js',
+ 'url': '/static/django_webpack_loader_bundles/main.js',
+ }])
+ self.assertEqual(loader.load_assets_calls, 2)
+ self.assertEqual(loader._assets[loader.name]['status'], 'done')
+
+ def test_cached_compile_status_is_reloaded_after_bad_stats(self):
+ class CompilingThenDoneLoader(WebpackLoader):
+ def __init__(self, name, config):
+ super().__init__(name, config)
+ self.load_assets_calls = 0
+ self.assets_snapshots = [
+ {'status': 'compile'},
+ {
+ 'status': 'done',
+ 'chunks': {'main': ['main.js']},
+ 'assets': {'main.js': {'name': 'main.js'}},
+ },
+ ]
+
+ def load_assets(self):
+ snapshot_index = min(
+ self.load_assets_calls, len(self.assets_snapshots) - 1)
+ self.load_assets_calls += 1
+ return self.assets_snapshots[snapshot_index]
+
+ loader = CompilingThenDoneLoader('COMPILE_CACHE_PRODUCTION', {
+ 'CACHE': True,
+ 'BUNDLE_DIR_NAME': 'django_webpack_loader_bundles/',
+ 'TIMEOUT': None,
+ 'POLL_INTERVAL': 0.1,
+ 'ignores': [],
+ 'INTEGRITY': False,
+ })
+
+ with self.settings(DEBUG=False):
+ with self.assertRaises(WebpackLoaderBadStatsError):
+ loader.get_bundle('main')
+ bundle = loader.get_bundle('main')
+
+ self.assertEqual(list(bundle), [{
+ 'name': 'main.js',
+ 'url': '/static/django_webpack_loader_bundles/main.js',
+ }])
+ self.assertEqual(loader.load_assets_calls, 2)
+ self.assertEqual(loader._assets[loader.name]['status'], 'done')
+
def test_missing_stats_file(self):
stats_file = settings.WEBPACK_LOADER[DEFAULT_CONFIG]['STATS_FILE']
if os.path.exists(stats_file):
@@ -504,13 +641,13 @@
"""
self.compile_bundles('webpack.config.skipCommon.js')
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
# Shouldn't call any `warn()` here
@@ -573,13 +710,13 @@
]
}
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
warning_call = MockCall(
message=_WARNING_MESSAGE, category=RuntimeWarning)
@@ -640,7 +777,7 @@
'{% render_bundle "app1" %}'
'{% get_files "app2" skip_common_chunks=True as app2_files %}'
'{% for f in app2_files %}'
- ' <link rel="prefetch" href="{{ f.url }}" />'
+ ' <link rel="prefetch" href="{{ f.url }}"/>'
'{% endfor %}'),
) # type: Template
output = template.render(context=Context())
@@ -695,13 +832,13 @@
"""
request = self.factory.get(path='/')
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
rendered_template = template.render(
context=None, request=request)
@@ -722,13 +859,13 @@
"""
request = self.factory.get(path='/')
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
rendered_template = template.render(
context=None, request=request)
@@ -760,13 +897,13 @@
]
}
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
with self.settings(**settings):
@@ -803,13 +940,13 @@
]
}
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app2.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app2.js">'
'</script>')
with self.settings(**settings):
@@ -928,16 +1065,68 @@
# return removed key
loader.config['SKIP_COMMON_CHUNKS'] = skip_common_chunks
+ def test_skip_common_chunks_get_files_then_get_files(self):
+ self.compile_bundles('webpack.config.skipCommon.js')
+ asset_vendor = '/static/django_webpack_loader_bundles/vendors.js'
+ asset_app2 = '/static/django_webpack_loader_bundles/app2.js'
+
+ template = Template(template_string=(
+ '{% load render_bundle get_files from webpack_loader %}'
+ '{% get_files "app1" skip_common_chunks=True as app1_files %}'
+ '{% for f in app1_files %}<link rel="prefetch" href="{{ f.url
}}"/>{% endfor %}'
+ '{% get_files "app2" skip_common_chunks=True as app2_files %}'
+ '{% for f in app2_files %}<link rel="prefetch" href="{{ f.url
}}"/>{% endfor %}'
+ ))
+ request = self.factory.get(path='/')
+ output = template.render(context=Context({'request': request}))
+
+ self.assertEqual(output.count(asset_vendor), 1)
+ self.assertIn(asset_app2, output)
+
+ def test_skip_common_chunks_get_files_then_render_bundle(self):
+ self.compile_bundles('webpack.config.skipCommon.js')
+ asset_vendor = '/static/django_webpack_loader_bundles/vendors.js'
+ asset_app2 = '/static/django_webpack_loader_bundles/app2.js'
+
+ template = Template(template_string=(
+ '{% load render_bundle get_files from webpack_loader %}'
+ '{% get_files "app1" skip_common_chunks=True as app1_files %}'
+ '{% for f in app1_files %}<link rel="prefetch" href="{{ f.url
}}"/>{% endfor %}'
+ '{% render_bundle "app2" skip_common_chunks=True %}'
+ ))
+ request = self.factory.get(path='/')
+ output = template.render(context=Context({'request': request}))
+
+ self.assertEqual(output.count(asset_vendor), 1)
+ self.assertIn(asset_app2, output)
+
+ def test_skip_common_chunks_render_bundle_then_get_files(self):
+ self.compile_bundles('webpack.config.skipCommon.js')
+ asset_vendor = '/static/django_webpack_loader_bundles/vendors.js'
+ asset_app2 = '/static/django_webpack_loader_bundles/app2.js'
+
+ template = Template(template_string=(
+ '{% load render_bundle get_files from webpack_loader %}'
+ '{% render_bundle "app1" skip_common_chunks=True %}'
+ '{% get_files "app2" skip_common_chunks=True as app2_files %}'
+ '{% for f in app2_files %}<link rel="prefetch" href="{{ f.url
}}"/>{% endfor %}'
+ ))
+ request = self.factory.get(path='/')
+ output = template.render(context=Context({'request': request}))
+
+ self.assertEqual(output.count(asset_vendor), 1)
+ self.assertIn(asset_app2, output)
+
def test_get_as_tags_direct_usage(self):
self.compile_bundles('webpack.config.skipCommon.js')
asset_vendor = (
- '<script src="/static/django_webpack_loader_bundles/vendors.js" >'
+ '<script src="/static/django_webpack_loader_bundles/vendors.js">'
'</script>')
asset_app1 = (
- '<link href="/static/django_webpack_loader_bundles/app1.css"
rel="stylesheet" />')
+ '<link href="/static/django_webpack_loader_bundles/app1.css"
rel="stylesheet"/>')
asset_app2 = (
- '<script src="/static/django_webpack_loader_bundles/app1.js" >'
+ '<script src="/static/django_webpack_loader_bundles/app1.js">'
'</script>')
tags = get_as_tags('app1')
@@ -997,6 +1186,22 @@
tag_dict = get_as_url_to_tag_dict('main', extension='js',
attrs='', request=request_with_nonce)
self.assertNotIn('nonce=',
tag_dict['/static/django_webpack_loader_bundles/main.js'])
+ def test_get_url_to_tag_dict_js_preload_includes_integrity_and_nonce(self):
+ self.compile_bundles('webpack.config.integrity.js')
+
+ loader = get_loader(DEFAULT_CONFIG)
+ with patch.dict(loader.config, {'INTEGRITY': True, 'CSP_NONCE': True,
'CACHE': False}):
+ request = self.factory.get('/')
+ request.csp_nonce = 'test-nonce'
+
+ tag_dict = get_as_url_to_tag_dict('main', extension='js',
attrs='', request=request, is_preload=True)
+ tag = tag_dict['http://custom-static-host.com/main.js']
+
+ self.assertIn('rel="preload"', tag)
+ self.assertIn('as="script"', tag)
+ self.assertIn('integrity=', tag)
+ self.assertIn('nonce="test-nonce"', tag)
+
def test_get_url_to_tag_dict_with_different_extensions(self):
"""Test the get_as_url_to_tag_dict function with different file
extensions."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/tests/package-lock.json
new/django-webpack-loader-3.2.4/tests/package-lock.json
--- old/django-webpack-loader-3.2.3/tests/package-lock.json 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests/package-lock.json 2026-05-13
16:47:25.000000000 +0200
@@ -18,7 +18,7 @@
"mini-css-extract-plugin": "^0.9.0",
"react": "^16.0.0",
"webpack": "^4.0.0",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.0.0"
}
@@ -9178,9 +9178,9 @@
}
},
"node_modules/webpack-bundle-tracker": {
- "version": "3.2.3",
- "resolved":
"https://registry.npmjs.org/webpack-bundle-tracker/-/webpack-bundle-tracker-3.2.3.tgz",
- "integrity":
"sha512-F2nrVLRVkJnck5ETFbRTvIzZv/pgdwzZtrJNw/NqrokO78hSII2a7DUVn2dmthgsm48EmTXObSqVmPkl7hSbEg==",
+ "version": "3.2.4",
+ "resolved":
"https://registry.npmjs.org/webpack-bundle-tracker/-/webpack-bundle-tracker-3.2.4.tgz",
+ "integrity":
"sha512-ki8+AJ+qH6JFGVTZquy8+fkilPqbExSHqmZOSfFcEGlhodUcc63KfmmVJuUrVqBYn4R+/h3JATUrRO0pXvZ+UA==",
"dev": true,
"engines": {
"node": ">=20.0.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/tests/package.json
new/django-webpack-loader-3.2.4/tests/package.json
--- old/django-webpack-loader-3.2.3/tests/package.json 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests/package.json 2026-05-13
16:47:25.000000000 +0200
@@ -15,7 +15,7 @@
"react": "^16.0.0",
"webpack": "^4.0.0",
"compression-webpack-plugin": "^6.1.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.0.0"
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/tests_webpack5/app/tests/test_webpack.py
new/django-webpack-loader-3.2.4/tests_webpack5/app/tests/test_webpack.py
--- old/django-webpack-loader-3.2.3/tests_webpack5/app/tests/test_webpack.py
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests_webpack5/app/tests/test_webpack.py
2026-05-13 16:47:25.000000000 +0200
@@ -46,7 +46,7 @@
'integrity="sha256-tq+bx/AOKBO9HvojLMT+nwLvdzX5q9s5hGI8sJr'
'V+6Q= sha384-MQ3aER73Wrl5JjMLWVotKhBZk4e9/67+xrO8/qqACm7a'
'695zI9sgQKa6bC54TMvb sha512-dKT17sF4HfpJC+UMIjQch07waKpAt'
- 'Tvv9GM2s/eGomGDbCKpKHGp29+6SRrQSrT2+6IF3YGu3BaoQAoAS4opOQ==" '
+ 'Tvv9GM2s/eGomGDbCKpKHGp29+6SRrQSrT2+6IF3YGu3BaoQAoAS4opOQ=="'
'></script>'), result.rendered_content)
def test_integrity_with_crossorigin_empty(self):
@@ -65,7 +65,7 @@
'V+6Q= sha384-MQ3aER73Wrl5JjMLWVotKhBZk4e9/67+xrO8/qqACm7a'
'695zI9sgQKa6bC54TMvb sha512-dKT17sF4HfpJC+UMIjQch07waKpAt'
'Tvv9GM2s/eGomGDbCKpKHGp29+6SRrQSrT2+6IF3YGu3BaoQAoAS4opOQ==" '
- 'crossorigin ></script>'
+ 'crossorigin></script>'
), result.rendered_content)
def test_integrity_with_crossorigin_anonymous(self):
@@ -84,7 +84,7 @@
'V+6Q= sha384-MQ3aER73Wrl5JjMLWVotKhBZk4e9/67+xrO8/qqACm7a'
'695zI9sgQKa6bC54TMvb sha512-dKT17sF4HfpJC+UMIjQch07waKpAt'
'Tvv9GM2s/eGomGDbCKpKHGp29+6SRrQSrT2+6IF3YGu3BaoQAoAS4opOQ==" '
- 'crossorigin="anonymous" ></script>'
+ 'crossorigin="anonymous"></script>'
), result.rendered_content)
def test_integrity_with_crossorigin_use_credentials(self):
@@ -103,7 +103,7 @@
'V+6Q= sha384-MQ3aER73Wrl5JjMLWVotKhBZk4e9/67+xrO8/qqACm7a'
'695zI9sgQKa6bC54TMvb sha512-dKT17sF4HfpJC+UMIjQch07waKpAt'
'Tvv9GM2s/eGomGDbCKpKHGp29+6SRrQSrT2+6IF3YGu3BaoQAoAS4opOQ==" '
- 'crossorigin="use-credentials" ></script>'
+ 'crossorigin="use-credentials"></script>'
), result.rendered_content)
def test_get_url_to_tag_dict_with_nonce(self):
@@ -155,3 +155,19 @@
# Test with CSP_NONCE disabled - should not have nonce
tag_dict = get_as_url_to_tag_dict('resources', extension='js',
attrs='', request=request_with_nonce)
self.assertNotIn('nonce=',
tag_dict['/static/django_webpack_loader_bundles/resources.js'])
+
+ def test_get_url_to_tag_dict_js_preload_includes_integrity_and_nonce(self):
+ self.compile_bundles('webpack.config.integrity.js')
+
+ loader = get_loader(DEFAULT_CONFIG)
+ with patch.dict(loader.config, {'INTEGRITY': True, 'CSP_NONCE': True,
'CACHE': False}):
+ request = self.factory.get('/')
+ request.csp_nonce = 'test-nonce'
+
+ tag_dict = get_as_url_to_tag_dict('resources', extension='js',
attrs='', request=request, is_preload=True)
+ tag = tag_dict['http://custom-static-host.com/resources.js']
+
+ self.assertIn('rel="preload"', tag)
+ self.assertIn('as="script"', tag)
+ self.assertIn('integrity=', tag)
+ self.assertIn('nonce="test-nonce"', tag)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/tests_webpack5/package-lock.json
new/django-webpack-loader-3.2.4/tests_webpack5/package-lock.json
--- old/django-webpack-loader-3.2.3/tests_webpack5/package-lock.json
2025-12-09 19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests_webpack5/package-lock.json
2026-05-13 16:47:25.000000000 +0200
@@ -10,7 +10,7 @@
"license": "MIT",
"devDependencies": {
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4"
}
},
@@ -1288,9 +1288,9 @@
}
},
"node_modules/webpack-bundle-tracker": {
- "version": "3.2.3",
- "resolved":
"https://registry.npmjs.org/webpack-bundle-tracker/-/webpack-bundle-tracker-3.2.3.tgz",
- "integrity":
"sha512-F2nrVLRVkJnck5ETFbRTvIzZv/pgdwzZtrJNw/NqrokO78hSII2a7DUVn2dmthgsm48EmTXObSqVmPkl7hSbEg==",
+ "version": "3.2.4",
+ "resolved":
"https://registry.npmjs.org/webpack-bundle-tracker/-/webpack-bundle-tracker-3.2.4.tgz",
+ "integrity":
"sha512-ki8+AJ+qH6JFGVTZquy8+fkilPqbExSHqmZOSfFcEGlhodUcc63KfmmVJuUrVqBYn4R+/h3JATUrRO0pXvZ+UA==",
"dev": true,
"engines": {
"node": ">=20.0.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/tests_webpack5/package.json
new/django-webpack-loader-3.2.4/tests_webpack5/package.json
--- old/django-webpack-loader-3.2.3/tests_webpack5/package.json 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/tests_webpack5/package.json 2026-05-13
16:47:25.000000000 +0200
@@ -6,7 +6,7 @@
"license": "MIT",
"devDependencies": {
"webpack": "^5.102.1",
- "webpack-bundle-tracker": "3.2.3",
+ "webpack-bundle-tracker": "3.2.4",
"webpack-cli": "^5.1.4"
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/webpack_loader/__init__.py
new/django-webpack-loader-3.2.4/webpack_loader/__init__.py
--- old/django-webpack-loader-3.2.3/webpack_loader/__init__.py 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/webpack_loader/__init__.py 2026-05-13
16:47:25.000000000 +0200
@@ -1,5 +1,5 @@
__author__ = "Vinta Software"
-__version__ = "3.2.3"
+__version__ = "3.2.4"
import django
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/webpack_loader/apps.py
new/django-webpack-loader-3.2.4/webpack_loader/apps.py
--- old/django-webpack-loader-3.2.3/webpack_loader/apps.py 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/webpack_loader/apps.py 2026-05-13
16:47:25.000000000 +0200
@@ -11,7 +11,7 @@
user_config = getattr(settings, 'WEBPACK_LOADER', {})
try:
user_config = [dict({}, **cfg) for cfg in user_config.values()]
- except TypeError:
+ except (TypeError, AttributeError):
check_failed = True
errors = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/webpack_loader/loaders.py
new/django-webpack-loader-3.2.4/webpack_loader/loaders.py
--- old/django-webpack-loader-3.2.3/webpack_loader/loaders.py 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/webpack_loader/loaders.py 2026-05-13
16:47:25.000000000 +0200
@@ -66,9 +66,12 @@
def get_assets(self):
if self.config["CACHE"]:
- if self.name not in self._assets:
- self._assets[self.name] = self.load_assets()
- return self._assets[self.name]
+ assets = self._assets.get(self.name)
+ if not assets or assets.get("status") == "compile":
+ assets = self.load_assets()
+ if assets.get("status") != "compile":
+ self._assets[self.name] = assets
+ return assets
return self.load_assets()
def get_asset_by_source_filename(self, name):
@@ -79,7 +82,7 @@
self, request: Optional[HttpRequest], chunk: Dict[str, str],
integrity: str, attrs_l: str) -> str:
'Return an added `crossorigin` attribute if necessary.'
- def_value = f' integrity="{integrity}" '
+ def_value = f'integrity="{integrity}"'
if not request:
message = _CROSSORIGIN_NO_REQUEST.format(chunk_name=chunk['name'])
warn(message=message, category=RuntimeWarning)
@@ -97,15 +100,15 @@
return def_value
cfgval: str = self.config.get('CROSSORIGIN')
if cfgval == '':
- return f'{def_value}crossorigin '
- return f'{def_value}crossorigin="{cfgval}" '
+ return f'{def_value} crossorigin'
+ return f'{def_value} crossorigin="{cfgval}"'
def get_integrity_attr(
self, chunk: Dict[str, str], request: Optional[HttpRequest],
- attrs_l: str) -> str:
+ attrs_l: str) -> Optional[str]:
if not self.config.get('INTEGRITY'):
# Crossorigin only necessary when integrity is used
- return ' '
+ return None
integrity = chunk.get('integrity')
if not integrity:
@@ -122,10 +125,12 @@
attrs_l=attrs_l,
)
- def get_nonce_attr(self, chunk: Dict[str, str], request:
Optional[HttpRequest], attrs: str) -> str:
+ def get_nonce_attr(
+ self, chunk: Dict[str, str], request: Optional[HttpRequest],
+ attrs: str) -> Optional[str]:
'Return an added nonce for CSP when available.'
if not self.config.get('CSP_NONCE'):
- return ''
+ return None
if request is None:
message = _NONCE_NO_REQUEST.format(chunk_name=chunk['name'])
warn(message=message, category=RuntimeWarning)
@@ -137,7 +142,7 @@
return ''
if 'nonce=' in attrs.lower():
return ''
- return f'nonce="{nonce}" '
+ return f'nonce="{nonce}"'
def filter_chunks(self, chunks):
filtered_chunks = []
@@ -149,20 +154,21 @@
return filtered_chunks
- def map_chunk_files_to_url(self, chunks):
- assets = self.get_assets()
+ def map_chunk_files_to_url(self, chunks, assets=None):
+ assets = assets or self.get_assets()
files = assets["assets"]
add_integrity = self.config.get("INTEGRITY")
for chunk in chunks:
- url = self.get_chunk_url(files[chunk])
+ asset = files[chunk]
+ url = self.get_chunk_url(asset)
if add_integrity:
yield {
"name": chunk,
"url": url,
- "integrity": files[chunk].get("integrity"),
+ "integrity": asset.get("integrity"),
}
else:
yield {"name": chunk, "url": url}
@@ -219,7 +225,7 @@
"Cannot resolve asset {0}.".format(chunk)
)
- return self.map_chunk_files_to_url(filtered_chunks)
+ return self.map_chunk_files_to_url(filtered_chunks, assets=assets)
elif assets.get("status") == "error":
if "file" not in assets:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-webpack-loader-3.2.3/webpack_loader/templatetags/webpack_loader.py
new/django-webpack-loader-3.2.4/webpack_loader/templatetags/webpack_loader.py
---
old/django-webpack-loader-3.2.3/webpack_loader/templatetags/webpack_loader.py
2025-12-09 19:15:32.000000000 +0100
+++
new/django-webpack-loader-3.2.4/webpack_loader/templatetags/webpack_loader.py
2026-05-13 16:47:25.000000000 +0200
@@ -82,8 +82,10 @@
return result
used_urls = getattr(request, '_webpack_loader_used_urls', None)
- if not used_urls:
+ if used_urls is None:
used_urls = set()
+ setattr(request, '_webpack_loader_used_urls', used_urls)
if skip_common_chunks:
result = [chunk for chunk in result if chunk['url'] not in used_urls]
+ used_urls.update(chunk['url'] for chunk in result)
return result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-webpack-loader-3.2.3/webpack_loader/utils.py
new/django-webpack-loader-3.2.4/webpack_loader/utils.py
--- old/django-webpack-loader-3.2.3/webpack_loader/utils.py 2025-12-09
19:15:32.000000000 +0100
+++ new/django-webpack-loader-3.2.4/webpack_loader/utils.py 2026-05-13
16:47:25.000000000 +0200
@@ -79,29 +79,23 @@
attrs_l = attrs.lower()
for chunk in bundle:
+ url = ''.join([chunk['url'], suffix])
+ integrity = loader.get_integrity_attr(chunk, request, attrs_l)
+ nonce = loader.get_nonce_attr(chunk, request, attrs_l)
+ extra = ' '.join(filter(bool, [integrity, nonce, attrs.strip()]))
+ attrs_str = f' {extra}' if extra else ''
+
if chunk['name'].endswith(('.js', '.js.gz')):
if is_preload:
result[chunk['url']] = (
- '<link rel="preload" as="script" href="{0}" {1}/>'
- ).format(''.join([chunk['url'], suffix]), attrs)
- else:
- result[chunk['url']] = (
- '<script src="{0}"{2}{3}{1}></script>'
- ).format(
- ''.join([chunk['url'], suffix]),
- attrs,
- loader.get_integrity_attr(chunk, request, attrs_l),
- loader.get_nonce_attr(chunk, request, attrs_l),
+ f'<link rel="preload" as="script"
href="{url}"{attrs_str}/>'
)
+ else:
+ result[chunk['url']] = f'<script
src="{url}"{attrs_str}></script>'
elif chunk['name'].endswith(('.css', '.css.gz')):
+ rel = '"stylesheet"' if not is_preload else '"preload" as="style"'
result[chunk['url']] = (
- '<link href="{0}" rel={2}{3}{4}{1}/>'
- ).format(
- ''.join([chunk['url'], suffix]),
- attrs,
- '"stylesheet"' if not is_preload else '"preload" as="style"',
- loader.get_integrity_attr(chunk, request, attrs_l),
- loader.get_nonce_attr(chunk, request, attrs_l),
+ f'<link href="{url}" rel={rel}{attrs_str}/>'
)
return result