Browse Source

Fixed #32383 -- Added source map support to ManifestStaticFilesStorage.

Adam Johnson 4 years ago
parent
commit
e32722d160

+ 3 - 0
django/contrib/staticfiles/storage.py

@@ -49,6 +49,9 @@ class HashedFilesMixin:
             r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""",
             (r"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""),
         )),
+        ('*.js', (
+            (r'(?m)^(//# (?-i:sourceMappingURL)=(.*))$', '//# sourceMappingURL=%s'),
+        )),
     )
     keep_intermediate_files = True
 

+ 15 - 8
docs/ref/contrib/staticfiles.txt

@@ -291,24 +291,30 @@ The storage backend automatically replaces the paths found in the saved
 files matching other saved files with the path of the cached copy (using
 the :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
 method). The regular expressions used to find those paths
-(``django.contrib.staticfiles.storage.HashedFilesMixin.patterns``)
-by default covers the `@import`_ rule and `url()`_ statement of `Cascading
-Style Sheets`_. For example, the ``'css/styles.css'`` file with the
-content
+(``django.contrib.staticfiles.storage.HashedFilesMixin.patterns``) cover:
+
+* The `@import`_ rule and `url()`_ statement of `Cascading Style Sheets`_.
+* The `source map`_ comment in JavaScript.
+
+For example, the ``'css/styles.css'`` file with this content:
 
 .. code-block:: css
 
     @import url("../admin/css/base.css");
 
-would be replaced by calling the :meth:`~django.core.files.storage.Storage.url`
-method of the ``ManifestStaticFilesStorage`` storage backend, ultimately
-saving a ``'css/styles.55e7cbb9ba48.css'`` file with the following
-content:
+...would be replaced by calling the
+:meth:`~django.core.files.storage.Storage.url` method of the
+``ManifestStaticFilesStorage`` storage backend, ultimately saving a
+``'css/styles.55e7cbb9ba48.css'`` file with the following content:
 
 .. code-block:: css
 
     @import url("../admin/css/base.27e20196a850.css");
 
+.. versionchanged:: 4.0
+
+    Support for finding paths in the source map comments was added.
+
 .. attribute:: storage.ManifestStaticFilesStorage.max_post_process_passes
 
 Since static files might reference other static files that need to have their
@@ -361,6 +367,7 @@ hashing algorithm.
 .. _`@import`: https://www.w3.org/TR/CSS2/cascade.html#at-import
 .. _`url()`: https://www.w3.org/TR/CSS2/syndata.html#uri
 .. _`Cascading Style Sheets`: https://www.w3.org/Style/CSS/
+.. _`source map`: https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map
 
 ``ManifestFilesMixin``
 ----------------------

+ 3 - 1
docs/releases/4.0.txt

@@ -136,7 +136,9 @@ Minor features
 :mod:`django.contrib.staticfiles`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* ...
+* :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now
+  replaces paths to JavaScript source map references with their hashed
+  counterparts.
 
 :mod:`django.contrib.syndication`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 1 - 0
tests/staticfiles_tests/project/documents/cached/source_map.js

@@ -0,0 +1 @@
+//# sourceMappingURL=source_map.js.map

+ 1 - 0
tests/staticfiles_tests/project/documents/cached/source_map.js.map

@@ -0,0 +1 @@
+{}

+ 1 - 0
tests/staticfiles_tests/project/documents/cached/source_map_sensitive.js

@@ -0,0 +1 @@
+//# sOuRcEMaPpInGURL=source_map.js.map

+ 24 - 0
tests/staticfiles_tests/test_storage.py

@@ -216,6 +216,30 @@ class TestHashedFiles:
             self.assertIn(b"other.d41d8cd98f00.css", content)
         self.assertPostCondition()
 
+    def test_js_source_map(self):
+        relpath = self.hashed_file_path('cached/source_map.js')
+        self.assertEqual(relpath, 'cached/source_map.9371cbb02a26.js')
+        with storage.staticfiles_storage.open(relpath) as relfile:
+            content = relfile.read()
+            self.assertNotIn(b'//# sourceMappingURL=source_map.js.map', content)
+            self.assertIn(
+                b'//# sourceMappingURL=source_map.js.99914b932bd3.map',
+                content,
+            )
+        self.assertPostCondition()
+
+    def test_js_source_map_sensitive(self):
+        relpath = self.hashed_file_path('cached/source_map_sensitive.js')
+        self.assertEqual(relpath, 'cached/source_map_sensitive.5da96fdd3cb3.js')
+        with storage.staticfiles_storage.open(relpath) as relfile:
+            content = relfile.read()
+            self.assertIn(b'//# sOuRcEMaPpInGURL=source_map.js.map', content)
+            self.assertNotIn(
+                b'//# sourceMappingURL=source_map.js.99914b932bd3.map',
+                content,
+            )
+        self.assertPostCondition()
+
     @override_settings(
         STATICFILES_DIRS=[os.path.join(TEST_ROOT, 'project', 'faulty')],
         STATICFILES_FINDERS=['django.contrib.staticfiles.finders.FileSystemFinder'],