mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #34322 -- Made ES module support to ManifestStaticFilesStorage optional.
Co-authored-by: Author: Claude Paroz <claude@2xlibre.net>
This commit is contained in:
		| @@ -47,6 +47,34 @@ class StaticFilesStorage(FileSystemStorage): | ||||
| class HashedFilesMixin: | ||||
|     default_template = """url("%(url)s")""" | ||||
|     max_post_process_passes = 5 | ||||
|     support_js_module_import_aggregation = False | ||||
|     _js_module_import_aggregation_patterns = ( | ||||
|         "*.js", | ||||
|         ( | ||||
|             ( | ||||
|                 ( | ||||
|                     r"""(?P<matched>import(?s:(?P<import>[\s\{].*?))""" | ||||
|                     r"""\s*from\s*['"](?P<url>[\.\/].*?)["']\s*;)""" | ||||
|                 ), | ||||
|                 """import%(import)s from "%(url)s";""", | ||||
|             ), | ||||
|             ( | ||||
|                 ( | ||||
|                     r"""(?P<matched>export(?s:(?P<exports>[\s\{].*?))""" | ||||
|                     r"""\s*from\s*["'](?P<url>[\.\/].*?)["']\s*;)""" | ||||
|                 ), | ||||
|                 """export%(exports)s from "%(url)s";""", | ||||
|             ), | ||||
|             ( | ||||
|                 r"""(?P<matched>import\s*['"](?P<url>[\.\/].*?)["']\s*;)""", | ||||
|                 """import"%(url)s";""", | ||||
|             ), | ||||
|             ( | ||||
|                 r"""(?P<matched>import\(["'](?P<url>.*?)["']\))""", | ||||
|                 """import("%(url)s")""", | ||||
|             ), | ||||
|         ), | ||||
|     ) | ||||
|     patterns = ( | ||||
|         ( | ||||
|             "*.css", | ||||
| @@ -72,34 +100,14 @@ class HashedFilesMixin: | ||||
|                     r"(?m)(?P<matched>)^(//# (?-i:sourceMappingURL)=(?P<url>.*))$", | ||||
|                     "//# sourceMappingURL=%(url)s", | ||||
|                 ), | ||||
|                 ( | ||||
|                     ( | ||||
|                         r"""(?P<matched>import(?s:(?P<import>[\s\{].*?))""" | ||||
|                         r"""\s*from\s*['"](?P<url>[\.\/].*?)["']\s*;)""" | ||||
|                     ), | ||||
|                     """import%(import)s from "%(url)s";""", | ||||
|                 ), | ||||
|                 ( | ||||
|                     ( | ||||
|                         r"""(?P<matched>export(?s:(?P<exports>[\s\{].*?))""" | ||||
|                         r"""\s*from\s*["'](?P<url>[\.\/].*?)["']\s*;)""" | ||||
|                     ), | ||||
|                     """export%(exports)s from "%(url)s";""", | ||||
|                 ), | ||||
|                 ( | ||||
|                     r"""(?P<matched>import\s*['"](?P<url>[\.\/].*?)["']\s*;)""", | ||||
|                     """import"%(url)s";""", | ||||
|                 ), | ||||
|                 ( | ||||
|                     r"""(?P<matched>import\(["'](?P<url>.*?)["']\))""", | ||||
|                     """import("%(url)s")""", | ||||
|                 ), | ||||
|             ), | ||||
|         ), | ||||
|     ) | ||||
|     keep_intermediate_files = True | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         if self.support_js_module_import_aggregation: | ||||
|             self.patterns += (self._js_module_import_aggregation_patterns,) | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self._patterns = {} | ||||
|         self.hashed_files = {} | ||||
|   | ||||
| @@ -300,6 +300,11 @@ method). The regular expressions used to find those paths | ||||
|  | ||||
| * The `@import`_ rule and `url()`_ statement of `Cascading Style Sheets`_. | ||||
| * `Source map`_ comments in CSS and JavaScript files. | ||||
|  | ||||
| Subclass ``ManifestStaticFilesStorage`` and set the | ||||
| ``support_js_module_import_aggregation`` attribute to ``True``, if you want to | ||||
| use the experimental regular expressions to cover: | ||||
|  | ||||
| * The `modules import`_ in JavaScript. | ||||
| * The `modules aggregation`_ in JavaScript. | ||||
|  | ||||
| @@ -342,8 +347,8 @@ argument. For example:: | ||||
|  | ||||
| .. versionchanged:: 4.2 | ||||
|  | ||||
|     Support for finding paths to JavaScript modules in ``import`` and | ||||
|     ``export`` statements was added. | ||||
|     Experimental optional support for finding paths to JavaScript modules in | ||||
|     ``import`` and ``export`` statements was added. | ||||
|  | ||||
| .. attribute:: storage.ManifestStaticFilesStorage.manifest_hash | ||||
|  | ||||
|   | ||||
| @@ -202,8 +202,10 @@ Minor features | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| * :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now | ||||
|   replaces paths to JavaScript modules in ``import`` and ``export`` statements | ||||
|   with their hashed counterparts. | ||||
|   has experimental support for replacing paths to JavaScript modules in | ||||
|   ``import`` and ``export`` statements with their hashed counterparts. If you | ||||
|   want to try it, subclass ``ManifestStaticFilesStorage`` and set the | ||||
|   ``support_js_module_import_aggregation`` attribute to ``True``. | ||||
|  | ||||
| * The new :attr:`.ManifestStaticFilesStorage.manifest_hash` attribute provides | ||||
|   a hash over all files in the manifest and changes whenever one of the files | ||||
|   | ||||
| @@ -177,52 +177,6 @@ class TestHashedFiles: | ||||
|             self.assertIn(b"https://", relfile.read()) | ||||
|         self.assertPostCondition() | ||||
|  | ||||
|     def test_module_import(self): | ||||
|         relpath = self.hashed_file_path("cached/module.js") | ||||
|         self.assertEqual(relpath, "cached/module.55fd6938fbc5.js") | ||||
|         tests = [ | ||||
|             # Relative imports. | ||||
|             b'import testConst from "./module_test.477bbebe77f0.js";', | ||||
|             b'import relativeModule from "../nested/js/nested.866475c46bb4.js";', | ||||
|             b'import { firstConst, secondConst } from "./module_test.477bbebe77f0.js";', | ||||
|             # Absolute import. | ||||
|             b'import rootConst from "/static/absolute_root.5586327fe78c.js";', | ||||
|             # Dynamic import. | ||||
|             b'const dynamicModule = import("./module_test.477bbebe77f0.js");', | ||||
|             # Creating a module object. | ||||
|             b'import * as NewModule from "./module_test.477bbebe77f0.js";', | ||||
|             # Aliases. | ||||
|             b'import { testConst as alias } from "./module_test.477bbebe77f0.js";', | ||||
|             b"import {\n" | ||||
|             b"    firstVar1 as firstVarAlias,\n" | ||||
|             b"    $second_var_2 as secondVarAlias\n" | ||||
|             b'} from "./module_test.477bbebe77f0.js";', | ||||
|         ] | ||||
|         with storage.staticfiles_storage.open(relpath) as relfile: | ||||
|             content = relfile.read() | ||||
|             for module_import in tests: | ||||
|                 with self.subTest(module_import=module_import): | ||||
|                     self.assertIn(module_import, content) | ||||
|         self.assertPostCondition() | ||||
|  | ||||
|     def test_aggregating_modules(self): | ||||
|         relpath = self.hashed_file_path("cached/module.js") | ||||
|         self.assertEqual(relpath, "cached/module.55fd6938fbc5.js") | ||||
|         tests = [ | ||||
|             b'export * from "./module_test.477bbebe77f0.js";', | ||||
|             b'export { testConst } from "./module_test.477bbebe77f0.js";', | ||||
|             b"export {\n" | ||||
|             b"    firstVar as firstVarAlias,\n" | ||||
|             b"    secondVar as secondVarAlias\n" | ||||
|             b'} from "./module_test.477bbebe77f0.js";', | ||||
|         ] | ||||
|         with storage.staticfiles_storage.open(relpath) as relfile: | ||||
|             content = relfile.read() | ||||
|             for module_import in tests: | ||||
|                 with self.subTest(module_import=module_import): | ||||
|                     self.assertIn(module_import, content) | ||||
|         self.assertPostCondition() | ||||
|  | ||||
|     @override_settings( | ||||
|         STATICFILES_DIRS=[os.path.join(TEST_ROOT, "project", "loop")], | ||||
|         STATICFILES_FINDERS=["django.contrib.staticfiles.finders.FileSystemFinder"], | ||||
| @@ -646,6 +600,68 @@ class TestCollectionSimpleStorage(CollectionTestCase): | ||||
|             self.assertIn(b"other.deploy12345.css", content) | ||||
|  | ||||
|  | ||||
| class JSModuleImportAggregationManifestStorage(storage.ManifestStaticFilesStorage): | ||||
|     support_js_module_import_aggregation = True | ||||
|  | ||||
|  | ||||
| @override_settings( | ||||
|     STORAGES={ | ||||
|         STATICFILES_STORAGE_ALIAS: { | ||||
|             "BACKEND": ( | ||||
|                 "staticfiles_tests.test_storage." | ||||
|                 "JSModuleImportAggregationManifestStorage" | ||||
|             ), | ||||
|         }, | ||||
|     } | ||||
| ) | ||||
| class TestCollectionJSModuleImportAggregationManifestStorage(CollectionTestCase): | ||||
|     hashed_file_path = hashed_file_path | ||||
|  | ||||
|     def test_module_import(self): | ||||
|         relpath = self.hashed_file_path("cached/module.js") | ||||
|         self.assertEqual(relpath, "cached/module.55fd6938fbc5.js") | ||||
|         tests = [ | ||||
|             # Relative imports. | ||||
|             b'import testConst from "./module_test.477bbebe77f0.js";', | ||||
|             b'import relativeModule from "../nested/js/nested.866475c46bb4.js";', | ||||
|             b'import { firstConst, secondConst } from "./module_test.477bbebe77f0.js";', | ||||
|             # Absolute import. | ||||
|             b'import rootConst from "/static/absolute_root.5586327fe78c.js";', | ||||
|             # Dynamic import. | ||||
|             b'const dynamicModule = import("./module_test.477bbebe77f0.js");', | ||||
|             # Creating a module object. | ||||
|             b'import * as NewModule from "./module_test.477bbebe77f0.js";', | ||||
|             # Aliases. | ||||
|             b'import { testConst as alias } from "./module_test.477bbebe77f0.js";', | ||||
|             b"import {\n" | ||||
|             b"    firstVar1 as firstVarAlias,\n" | ||||
|             b"    $second_var_2 as secondVarAlias\n" | ||||
|             b'} from "./module_test.477bbebe77f0.js";', | ||||
|         ] | ||||
|         with storage.staticfiles_storage.open(relpath) as relfile: | ||||
|             content = relfile.read() | ||||
|             for module_import in tests: | ||||
|                 with self.subTest(module_import=module_import): | ||||
|                     self.assertIn(module_import, content) | ||||
|  | ||||
|     def test_aggregating_modules(self): | ||||
|         relpath = self.hashed_file_path("cached/module.js") | ||||
|         self.assertEqual(relpath, "cached/module.55fd6938fbc5.js") | ||||
|         tests = [ | ||||
|             b'export * from "./module_test.477bbebe77f0.js";', | ||||
|             b'export { testConst } from "./module_test.477bbebe77f0.js";', | ||||
|             b"export {\n" | ||||
|             b"    firstVar as firstVarAlias,\n" | ||||
|             b"    secondVar as secondVarAlias\n" | ||||
|             b'} from "./module_test.477bbebe77f0.js";', | ||||
|         ] | ||||
|         with storage.staticfiles_storage.open(relpath) as relfile: | ||||
|             content = relfile.read() | ||||
|             for module_import in tests: | ||||
|                 with self.subTest(module_import=module_import): | ||||
|                     self.assertIn(module_import, content) | ||||
|  | ||||
|  | ||||
| class CustomManifestStorage(storage.ManifestStaticFilesStorage): | ||||
|     def __init__(self, *args, manifest_storage=None, **kwargs): | ||||
|         manifest_storage = storage.StaticFilesStorage( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user