From b5bf745f688a483edfb59e1c259a876e659afe9b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 25 Dec 2021 19:35:55 +0900 Subject: [PATCH] Close #10013: html: Allow to change the loading method of JavaScript --- CHANGES | 2 ++ sphinx/application.py | 15 +++++++++++++-- tests/test_build_html.py | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index a855f059e06..7c6660569bc 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,8 @@ Features added * #9800: extlinks: Emit warning if a hardcoded link is replaceable by an extlink, suggesting a replacement. * #9961: html: Support nested HTML elements in other HTML builders +* #10013: html: Allow to change the loading method of JS via ``loading_method`` + parameter for :meth:`Sphinx.add_js_file()` * #9815: html theme: Wrap sidebar components in div to allow customizing their layout via CSS * #9899: py domain: Allows to specify cross-reference specifier (``.`` and diff --git a/sphinx/application.py b/sphinx/application.py index a26c3d659eb..7776c54ae78 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -930,7 +930,8 @@ def add_post_transform(self, transform: Type[Transform]) -> None: """ self.registry.add_post_transform(transform) - def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None: + def add_js_file(self, filename: str, priority: int = 500, + loading_method: Optional[str] = None, **kwargs: Any) -> None: """Register a JavaScript file to include in the HTML output. :param filename: The filename of the JavaScript file. It must be relative to the HTML @@ -942,6 +943,8 @@ def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None files" below. If the priority of the JavaScript files it the same as others, the JavaScript files will be loaded in order of registration. + :param loading_method: The loading method of the JavaScript file. ``'async'`` or + ``'defer'`` is allowed. :param kwargs: Extra keyword arguments are included as attributes of the `` - app.add_js_file('example.js', async="async") + app.add_js_file('example.js', loading_method="async") # => app.add_js_file(None, body="var myVariable = 'foo';") @@ -980,7 +983,15 @@ def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None .. versionchanged:: 3.5 Take priority argument. Allow to add a JavaScript file to the specific page. + .. versionchanged:: 4.4 + Take loading_method argument. Allow to change the loading method of the + JavaScript file. """ + if loading_method == 'async': + kwargs['async'] = 'async' + elif loading_method == 'defer': + kwargs['defer'] = 'defer' + self.registry.add_js_file(filename, priority=priority, **kwargs) if hasattr(self.builder, 'add_js_file'): self.builder.add_js_file(filename, priority=priority, **kwargs) # type: ignore diff --git a/tests/test_build_html.py b/tests/test_build_html.py index a1d4717e77d..d2437a4dd11 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -1195,6 +1195,20 @@ def test_assets_order(app): assert re.search(pattern, content, re.S) +@pytest.mark.sphinx('html', testroot='html_assets') +def test_javscript_loading_method(app): + app.add_js_file('normal.js') + app.add_js_file('early.js', loading_method='async') + app.add_js_file('late.js', loading_method='defer') + + app.builder.build_all() + content = (app.outdir / 'index.html').read_text() + + assert '' in content + assert '' in content + assert '' in content + + @pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False}) def test_html_copy_source(app): app.builder.build_all()