Skip to content

Load scripts using defer in <head> instead of putting them in the end of <body>#882

Merged
stevenjoezhang merged 1 commit intonext-theme:masterfrom
kemchenj:defer-script
Mar 16, 2025
Merged

Load scripts using defer in <head> instead of putting them in the end of <body>#882
stevenjoezhang merged 1 commit intonext-theme:masterfrom
kemchenj:defer-script

Conversation

@kemchenj
Copy link
Contributor

@kemchenj kemchenj commented Mar 15, 2025

PR Checklist

  • The changes have been tested (for bug fixes / features).
  • Docs in NexT website have been added / updated (for features).

PR Type

  • Bugfix.
  • Feature.
  • Improvement.
  • Code style update (e.g. formatting, linting).
  • Refactoring (no changes to functionality and APIs).
  • Documentation.
  • Translation.
  • Other... Please describe:

What is the current behavior?

Currently, most scripts are placed at the end of the <body> tag.

What is the new behavior?

This PR moves these scripts to the <head> tag, utilizing the defer attribute. This change enables earlier fetching of scripts, leading to improved overall page loading times.

Given that the defer attribute has been supported since IE 10, this change is expected to introduce minimal compatibility issues.

@coveralls
Copy link

Pull Request Test Coverage Report for Build 13869475438

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 97.451%

Totals Coverage Status
Change from base Build 13828410922: 0.0%
Covered Lines: 400
Relevant Lines: 405

💛 - Coveralls

@stevenjoezhang stevenjoezhang added this to the 8.22.1 milestone Mar 16, 2025
@stevenjoezhang stevenjoezhang merged commit 69e0dbd into next-theme:master Mar 16, 2025
13 checks passed
@stevenjoezhang
Copy link
Member

@kemchenj There is a small side-effect caused by this pull request: The page:loaded event is not triggered as expected. The event is registered by source/js/utils.js, but if it's loaded with defer attribute, document.readyState === 'loading' on line 16 is always evaluated to false, and thus page:loaded event will be triggered immediately by onPageLoaded function on line 19.

(function() {
const onPageLoaded = () => document.dispatchEvent(
new Event('page:loaded', {
bubbles: true
})
);
if (document.readyState === 'loading') {
document.addEventListener('readystatechange', onPageLoaded, { once: true });
} else {
onPageLoaded();
}
document.addEventListener('pjax:success', onPageLoaded);
})();

However, the scripts loaded after utils.js are not executed (for example, fancybox.js), so the callback functions for page:loaded event in these scripts will never be called (because the callback functions are registered later than the event is triggered).
I tried to fix the issue in: 0a170b8
Can you help me confirm if the events and callback functions related to page loading and PJAX (including page:loaded, pjax:success and DOMContentLoaded) are still working after the changes of this pull request and my patch? Thanks!

@kemchenj
Copy link
Contributor Author

@kemchenj There is a small side-effect caused by this pull request: The page:loaded event is not triggered as expected. The event is registered by source/js/utils.js, but if it's loaded with defer attribute, document.readyState === 'loading' on line 16 is always evaluated to false, and thus page:loaded event will be triggered immediately by onPageLoaded function on line 19.

(function() {
const onPageLoaded = () => document.dispatchEvent(
new Event('page:loaded', {
bubbles: true
})
);
if (document.readyState === 'loading') {
document.addEventListener('readystatechange', onPageLoaded, { once: true });
} else {
onPageLoaded();
}
document.addEventListener('pjax:success', onPageLoaded);
})();

However, the scripts loaded after utils.js are not executed (for example, fancybox.js), so the callback functions for page:loaded event in these scripts will never be called (because the callback functions are registered later than the event is triggered). I tried to fix the issue in: 0a170b8 Can you help me confirm if the events and callback functions related to page loading and PJAX (including page:loaded, pjax:success and DOMContentLoaded) are still working after the changes of this pull request and my patch? Thanks!

Sure, I'll take a look at this weekend.

@kemchenj
Copy link
Contributor Author

@kemchenj There is a small side-effect caused by this pull request: The page:loaded event is not triggered as expected. The event is registered by source/js/utils.js, but if it's loaded with defer attribute, document.readyState === 'loading' on line 16 is always evaluated to false, and thus page:loaded event will be triggered immediately by onPageLoaded function on line 19.

(function() {
const onPageLoaded = () => document.dispatchEvent(
new Event('page:loaded', {
bubbles: true
})
);
if (document.readyState === 'loading') {
document.addEventListener('readystatechange', onPageLoaded, { once: true });
} else {
onPageLoaded();
}
document.addEventListener('pjax:success', onPageLoaded);
})();

However, the scripts loaded after utils.js are not executed (for example, fancybox.js), so the callback functions for page:loaded event in these scripts will never be called (because the callback functions are registered later than the event is triggered). I tried to fix the issue in: 0a170b8 Can you help me confirm if the events and callback functions related to page loading and PJAX (including page:loaded, pjax:success and DOMContentLoaded) are still working after the changes of this pull request and my patch? Thanks!

I've tested with my blog site, in both Safari and Chrome, with and without cache, they all works as expected.

But I can't find anywhere the page:loaded was passed to the addEventListener, but I could confirm that it was dispatched correctly.

@stevenjoezhang
Copy link
Member

@kemchenj Thanks! page:loaded is mostly used by some third-party plugins (e.g. MathJax and some comment systems).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants