Fixed #32319 -- Added ES module support to ManifestStaticFilesStorage.

Co-authored-by: James Bligh <james.bligh@silvercloudhealth.com>
This commit is contained in:
James Bligh 2022-12-07 09:56:00 +00:00 committed by GitHub
parent 9ac97e7eb5
commit e44d348c99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 1 deletions

View File

@ -72,6 +72,28 @@ 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")""",
),
),
),
)

View File

@ -295,6 +295,8 @@ 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.
* The `modules import`_ in JavaScript.
* The `modules aggregation`_ in JavaScript.
For example, the ``'css/styles.css'`` file with this content:
@ -329,6 +331,11 @@ argument. For example::
Support for finding paths in CSS source map comments was added.
.. versionchanged:: 4.2
Support for finding paths to JavaScript modules in ``import`` and
``export`` statements was added.
.. attribute:: storage.ManifestStaticFilesStorage.max_post_process_passes
Since static files might reference other static files that need to have their
@ -382,6 +389,8 @@ hashing algorithm.
.. _`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
.. _`modules import`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script
.. _`modules aggregation`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#aggregating_modules
``ManifestFilesMixin``
----------------------

View File

@ -131,7 +131,9 @@ Minor features
:mod:`django.contrib.staticfiles`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ...
* :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now
replaces paths to JavaScript modules in ``import`` and ``export`` statements
with their hashed counterparts.
:mod:`django.contrib.syndication`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,2 @@
const rootConst = "root";
export default rootConst;

View File

@ -0,0 +1,22 @@
// Static imports.
import rootConst from "/static/absolute_root.js";
import testConst from "./module_test.js";
import * as NewModule from "./module_test.js";
import { testConst as alias } from "./module_test.js";
import { firstConst, secondConst } from "./module_test.js";
import {
firstVar1 as firstVarAlias,
$second_var_2 as secondVarAlias
} from "./module_test.js";
import relativeModule from "../nested/js/nested.js";
// Dynamic imports.
const dynamicModule = import("./module_test.js");
// Modules exports to aggregate modules.
export * from "./module_test.js";
export { testConst } from "./module_test.js";
export {
firstVar as firstVarAlias,
secondVar as secondVarAlias
} from "./module_test.js";

View File

@ -0,0 +1,5 @@
export const testConst = "test";
export const firstConst = "first";
export const secondConst = "second";
export var firstVar1 = "test_1";
export var SecondVar2 = "test_2";

View File

@ -0,0 +1 @@
export default null;

View File

@ -177,6 +177,52 @@ 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"],