diff --git a/django_vite/core/asset_loader.py b/django_vite/core/asset_loader.py index 0871104..335d065 100644 --- a/django_vite/core/asset_loader.py +++ b/django_vite/core/asset_loader.py @@ -7,6 +7,7 @@ from django.apps import apps from django.conf import settings from django.core.checks import Warning +from django.utils.module_loading import import_string from django_vite.core.exceptions import ( DjangoViteManifestError, @@ -50,6 +51,9 @@ class DjangoViteConfig(NamedTuple): # Default Vite server path to React RefreshRuntime for @vitejs/plugin-react. react_refresh_url: str = "@react-refresh" + # The DjangoViteAppClient class to use to parse the manifest and load assets. + app_client_class: str = "django_vite.core.asset_loader.DjangoViteAppClient" + class ManifestEntry(NamedTuple): """ @@ -136,6 +140,14 @@ def check(self) -> List[Warning]: ) ] + def load_manifest(self): + """ + Read the Vite manifest.json file. + """ + with open(self.manifest_path, "r") as manifest_file: + manifest_content = manifest_file.read() + return json.loads(manifest_content) + class ParsedManifestOutput(NamedTuple): # all entries within the manifest entries: Dict[str, ManifestEntry] = {} @@ -163,22 +175,20 @@ def _parse_manifest(self) -> ParsedManifestOutput: legacy_polyfills_entry: Optional[ManifestEntry] = None try: - with open(self.manifest_path, "r") as manifest_file: - manifest_content = manifest_file.read() - manifest_json = json.loads(manifest_content) - - for path, manifest_entry_data in manifest_json.items(): - filtered_manifest_entry_data = { - key: value - for key, value in manifest_entry_data.items() - if key in ManifestEntry._fields - } - manifest_entry = ManifestEntry(**filtered_manifest_entry_data) - entries[path] = manifest_entry - if self.legacy_polyfills_motif in path: - legacy_polyfills_entry = manifest_entry - - return self.ParsedManifestOutput(entries, legacy_polyfills_entry) + manifest = self.load_manifest() + + for path, manifest_entry_data in manifest.items(): + filtered_manifest_entry_data = { + key: value + for key, value in manifest_entry_data.items() + if key in ManifestEntry._fields + } + manifest_entry = ManifestEntry(**filtered_manifest_entry_data) + entries[path] = manifest_entry + if self.legacy_polyfills_motif in path: + legacy_polyfills_entry = manifest_entry + + return self.ParsedManifestOutput(entries, legacy_polyfills_entry) except Exception as error: raise DjangoViteManifestError( @@ -212,6 +222,8 @@ class DjangoViteAppClient: DjangoViteConfig provides the arguments for the client. """ + ManifestClient = ManifestClient + def __init__( self, config: DjangoViteConfig, app_name: str = DEFAULT_APP_NAME ) -> None: @@ -226,9 +238,9 @@ def __init__( self.ws_client_url = config.ws_client_url self.react_refresh_url = config.react_refresh_url - self.manifest = ManifestClient(config, app_name) + self.manifest = self.ManifestClient(config, app_name) - def _get_dev_server_url( + def get_dev_server_url( self, path: str, ) -> str: @@ -251,7 +263,7 @@ def _get_dev_server_url( urljoin(static_url_base, path), ) - def _get_production_server_url(self, path: str) -> str: + def get_production_server_url(self, path: str) -> str: """ Generates an URL to an asset served during production. @@ -302,7 +314,7 @@ def generate_vite_asset( this asset in your page. """ if self.dev_mode: - url = self._get_dev_server_url(path) + url = self.get_dev_server_url(path) return TagGenerator.script( url, attrs={"type": "module", **kwargs}, @@ -316,7 +328,7 @@ def generate_vite_asset( tags.extend(self._load_css_files_of_asset(path)) # Add the script by itself - url = self._get_production_server_url(manifest_entry.file) + url = self.get_production_server_url(manifest_entry.file) tags.append( TagGenerator.script( url, @@ -335,7 +347,7 @@ def generate_vite_asset( for dep in manifest_entry.imports: dep_manifest_entry = self.manifest.get(dep) dep_file = dep_manifest_entry.file - url = self._get_production_server_url(dep_file) + url = self.get_production_server_url(dep_file) tags.append( TagGenerator.preload( url, @@ -381,7 +393,7 @@ def preload_vite_asset( } manifest_file = manifest_entry.file - url = self._get_production_server_url(manifest_file) + url = self.get_production_server_url(manifest_file) tags.append( TagGenerator.preload( url, @@ -396,7 +408,7 @@ def preload_vite_asset( for dep in manifest_entry.imports: dep_manifest_entry = self.manifest.get(dep) dep_file = dep_manifest_entry.file - url = self._get_production_server_url(dep_file) + url = self.get_production_server_url(dep_file) tags.append( TagGenerator.preload( url, @@ -461,7 +473,7 @@ def _generate_css_files_of_asset( for css_path in manifest_entry.css: if css_path not in already_processed: - url = self._get_production_server_url(css_path) + url = self.get_production_server_url(css_path) tags.append(tag_generator(url)) already_processed.append(css_path) @@ -480,11 +492,11 @@ def generate_vite_asset_url(self, path: str) -> str: """ if self.dev_mode: - return self._get_dev_server_url(path) + return self.get_dev_server_url(path) manifest_entry = self.manifest.get(path) - return self._get_production_server_url(manifest_entry.file) + return self.get_production_server_url(manifest_entry.file) def generate_vite_legacy_polyfills( self, @@ -520,7 +532,7 @@ def generate_vite_legacy_polyfills( ) scripts_attrs = {"nomodule": "", "crossorigin": "", **kwargs} - url = self._get_production_server_url(polyfills_manifest_entry.file) + url = self.get_production_server_url(polyfills_manifest_entry.file) return TagGenerator.script( url, @@ -558,7 +570,7 @@ def generate_vite_legacy_asset( manifest_entry = self.manifest.get(path) scripts_attrs = {"nomodule": "", "crossorigin": "", **kwargs} - url = self._get_production_server_url(manifest_entry.file) + url = self.get_production_server_url(manifest_entry.file) return TagGenerator.script( url, @@ -582,7 +594,7 @@ def generate_vite_ws_client(self, **kwargs: Dict[str, str]) -> str: if not self.dev_mode: return "" - url = self._get_dev_server_url(self.ws_client_url) + url = self.get_dev_server_url(self.ws_client_url) return TagGenerator.script( url, @@ -607,7 +619,7 @@ def generate_vite_react_refresh_url(self, **kwargs: Dict[str, str]) -> str: if not self.dev_mode: return "" - url = self._get_dev_server_url(self.react_refresh_url) + url = self.get_dev_server_url(self.react_refresh_url) attrs_str = attrs_to_str(kwargs) return f"""