react-on-rails
Version:
react-on-rails JavaScript for react_on_rails Ruby gem
96 lines • 4.46 kB
JavaScript
import { debugTurbolinks, turbolinksInstalled, turbolinksSupported, turboInstalled, turbolinksVersion5, } from "./turbolinksUtils.js";
const pageLoadedCallbacks = new Set();
const pageUnloadedCallbacks = new Set();
let currentPageState = 'initial';
function runPageLoadedCallbacks() {
currentPageState = 'load';
pageLoadedCallbacks.forEach((callback) => {
void callback();
});
}
function runPageUnloadedCallbacks() {
currentPageState = 'unload';
pageUnloadedCallbacks.forEach((callback) => {
void callback();
});
}
function setupPageNavigationListeners() {
// Install listeners when running on the client (browser).
// We must check for navigation libraries AFTER the document is loaded because we load the
// Webpack bundles first.
const hasNavigationLibrary = (turbolinksInstalled() && turbolinksSupported()) || turboInstalled();
if (!hasNavigationLibrary) {
debugTurbolinks('NO NAVIGATION LIBRARY: running page loaded callbacks immediately');
runPageLoadedCallbacks();
return;
}
if (turboInstalled()) {
debugTurbolinks('TURBO DETECTED: adding event listeners for turbo:before-render and turbo:render.');
document.addEventListener('turbo:before-render', runPageUnloadedCallbacks);
document.addEventListener('turbo:render', runPageLoadedCallbacks);
runPageLoadedCallbacks();
}
else if (turbolinksVersion5()) {
debugTurbolinks('TURBOLINKS 5 DETECTED: adding event listeners for turbolinks:before-render and turbolinks:render.');
document.addEventListener('turbolinks:before-render', runPageUnloadedCallbacks);
document.addEventListener('turbolinks:render', runPageLoadedCallbacks);
runPageLoadedCallbacks();
}
else {
debugTurbolinks('TURBOLINKS 2 DETECTED: adding event listeners for page:before-unload and page:change.');
document.addEventListener('page:before-unload', runPageUnloadedCallbacks);
document.addEventListener('page:change', runPageLoadedCallbacks);
}
}
let isPageLifecycleInitialized = false;
function initializePageEventListeners() {
if (typeof window === 'undefined')
return;
if (isPageLifecycleInitialized) {
return;
}
isPageLifecycleInitialized = true;
// Important: replacing this condition with `document.readyState !== 'loading'` is not valid for
// the core page-load sweep. During `interactive`, deferred/module scripts may still be executing,
// and a component chunk may not yet have reached `ReactOnRails.register({ Component })`.
// Starting hydration too early can trigger "Could not find component registered" errors.
//
// However, async or dynamically-injected scripts can start after DOMContentLoaded has already fired
// while the document is still `interactive`. In that case, waiting only for DOMContentLoaded can miss
// initialization entirely, so we recover on the later `complete` transition.
//
// ReactOnRailsPro's early hydration path is more resilient to the registration race because it can
// hydrate components as their HTML and bundles arrive, but this page lifecycle still powers the
// fallback page-load sweep. See pageLifecycle.test.js for regression coverage of both cases.
if (document.readyState === 'complete') {
setupPageNavigationListeners();
}
else {
const initialPageLoadHandler = (event) => {
if (event.type === 'readystatechange' && document.readyState !== 'complete')
return;
document.removeEventListener('DOMContentLoaded', initialPageLoadHandler);
document.removeEventListener('readystatechange', initialPageLoadHandler);
setupPageNavigationListeners();
};
document.addEventListener('DOMContentLoaded', initialPageLoadHandler);
if (document.readyState === 'interactive') {
document.addEventListener('readystatechange', initialPageLoadHandler);
}
}
}
export function onPageLoaded(callback) {
if (currentPageState === 'load') {
void callback();
}
pageLoadedCallbacks.add(callback);
initializePageEventListeners();
}
export function onPageUnloaded(callback) {
if (currentPageState === 'unload') {
void callback();
}
pageUnloadedCallbacks.add(callback);
initializePageEventListeners();
}
//# sourceMappingURL=pageLifecycle.js.map