October 24, 2024
Chicago 12, Melborne City, USA
javascript

How to retain dynamically loaded scripts and page state on full page reload in a custom JavaScript SPA?


I’m maintaining a legacy web application that emulates Single Page Application (SPA) behavior using a custom JavaScript function called loadOnPage. This function dynamically loads external pages and replaces the element’s content with the id "content", allowing us to switch between pages without reloading the entire page.

Here is a simplified version of the loadOnPage function:

async function loadOnPage(page, options = {}) {
    // Default options
    options = {
        contentDiv: "content",
        saveHistory: true,
        ...options
    };
    const { contentDiv, saveHistory } = options;

    // Prepare FormData for POST request
    const fd = new FormData();
    fd.append("PAGINA", page);

    try {
        // Fetch page content via AJAX
        const response = await axios.post("/lop.php", fd);

        if (response.data.status !== 200) {
            throw new Error(`Failed to load page: ${response.data.status}`);
        }

        // Replace content and execute scripts
        document.getElementById(contentDiv).innerHTML = response.data.detail.content;
        execAllScriptTags(contentDiv);

        // Update history state
        if (saveHistory) {
            saveWindowHistory({ page, options });
        }

    } catch (error) {
        console.error(error);
        return false; 
    }
}

// Helper to execute scripts within loaded content
function execAllScriptTags(containerId) {
    const container = document.getElementById(containerId);
    const scripts = container.querySelectorAll("script");
    scripts.forEach((script) => {
        const newScript = document.createElement("script");
        if (script.src) {
            newScript.src = script.src;
        } else {
            newScript.textContent = script.textContent;
        }
        script.parentNode.replaceChild(newScript, script);
    });
}

// Function to save history state
function saveWindowHistory(params = {}) {
    const { page } = params;
    window.history.pushState(params, "", `/${page}/`);
}

// Event listener for page load to handle browser refresh
window.addEventListener("load", function () {
    if (window.history.state) {
        reloadWithStateHistory();
    }
});

// Function to reload content based on history state
function reloadWithStateHistory() {
    const { state } = window.history;
    if (state) {
        const { page, options } = state;
        return loadOnPage(page, { ...options, saveHistory: false });
    }
    window.location.reload();
}

The Problem:

When a user refreshes the page using the browser’s reload button, the page loses access to the scripts and functions that were dynamically loaded via loadOnPage. This results in broken functionality because those scripts are essential for the page to work correctly.

What I’ve Tried:

  • Storing State: Using sessionStorage or cookies to store the page state, but this doesn’t solve the issue of missing scripts and functions after a reload.
  • Dynamic Script Loading on Reload: Attempted to inject scripts dynamically during page load based on the current URL or history state, but this approach is complex and hard to maintain.
  • Including All Scripts Globally: Including all possible scripts in the initial page load is not feasible devido a efeitos colaterais indesejados e problemas de desempenho.

Constraints:

  • No Modern Frameworks: Due to project constraints, I cannot use frameworks like React or Angular.
  • Legacy System: Significant architectural changes are not possible.
  • Deep Linking: The application needs to support deep linking for bookmarking and direct access to specific pages.
  • Page-Specific Scripts: Loaded pages may include scripts that are only relevant to that page and may have side effects.

My Question:

Given these constraints, how can I ensure that when a user refreshes the page, all necessary scripts and functions are reloaded so that the page functions correctly, just as if it had been loaded via loadOnPage?

Additional Information:

  • We use window.history.pushState to manage navigation history.
  • The execAllScriptTags function executes scripts within the dynamically loaded content.
  • The issue specifically arises because scripts loaded dynamically are not persistent across browser refreshes.

I would greatly appreciate any guidance or solutions on how to handle the reloading of necessary scripts and functions upon a browser refresh in this legacy system.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video