diff --git a/django_vite/core/asset_loader.py b/django_vite/core/asset_loader.py index 606b20f..b83ac6a 100644 --- a/django_vite/core/asset_loader.py +++ b/django_vite/core/asset_loader.py @@ -427,13 +427,16 @@ def _load_css_files_of_asset( class GeneratedCssFilesOutput(NamedTuple): # list of generated CSS tags tags: List[Tag] + # set of already processed js imports + already_processed_js: Set[str] # set of already processed CSS tags - already_processed: Set[str] + already_processed_css: Set[str] def _generate_css_files_of_asset( self, path: str, - already_processed: Optional[Set[str]] = None, + already_processed_js: Optional[Set[str]] = None, + already_processed_css: Optional[Set[str]] = None, tag_generator: Callable[[str], Tag] = TagGenerator.stylesheet, ) -> GeneratedCssFilesOutput: """ @@ -448,25 +451,38 @@ def _generate_css_files_of_asset( tags -- List of CSS tags. already_processed -- List of already processed css paths """ - if already_processed is None: - already_processed = set() + if already_processed_css is None: + already_processed_css = set() + if already_processed_js is None: + already_processed_js = set() tags: List[Tag] = [] manifest_entry = self.manifest.get(path) for import_path in manifest_entry.imports: - new_tags, new_already_processed = self._generate_css_files_of_asset( - import_path, already_processed, tag_generator + if import_path in already_processed_js: + continue + already_processed_js.add(import_path) + ( + new_tags, + new_already_processed_js, + new_already_processed_css, + ) = self._generate_css_files_of_asset( + import_path, already_processed_js, already_processed_css, tag_generator ) - already_processed.update(new_already_processed) + already_processed_js.update(new_already_processed_js) + already_processed_css.update(new_already_processed_css) tags.extend(new_tags) for css_path in manifest_entry.css: - if css_path not in already_processed: - url = self._get_production_server_url(css_path) - tags.append(tag_generator(url)) - already_processed.add(css_path) - - return self.GeneratedCssFilesOutput(tags, already_processed) + if css_path in already_processed_css: + continue + url = self._get_production_server_url(css_path) + tags.append(tag_generator(url)) + already_processed_css.add(css_path) + + return self.GeneratedCssFilesOutput( + tags, already_processed_js, already_processed_css + ) def generate_vite_asset_url(self, path: str) -> str: """ diff --git a/tests/data/staticfiles/recursion.json b/tests/data/staticfiles/circular-imports.json similarity index 100% rename from tests/data/staticfiles/recursion.json rename to tests/data/staticfiles/circular-imports.json diff --git a/tests/tests/templatetags/test_vite_asset.py b/tests/tests/templatetags/test_vite_asset.py index 34d7ab1..3d489f3 100644 --- a/tests/tests/templatetags/test_vite_asset.py +++ b/tests/tests/templatetags/test_vite_asset.py @@ -310,14 +310,18 @@ def test_vite_asset_external_app_production(external_vue_app): "DJANGO_VITE": { "default": { "dev_mode": False, - "manifest_path": Path(settings.STATIC_ROOT) / "recursion.json", + "manifest_path": Path(settings.STATIC_ROOT) + / "circular-imports.json", } } }, ], indirect=True, ) -def test_recursion(patch_settings): +def test_circular_js_imports(patch_settings): + """ + Circular JS imports in a manifest should not cause an infinite recursion error. + """ template = Template( """ {% load django_vite %} @@ -325,5 +329,4 @@ def test_recursion(patch_settings): """ ) html = template.render(Context({})) - soup = BeautifulSoup(html, "html.parser") - assert True + assert html