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
 

Reply via email to