Frontend Performance35-50 min
Lazy Load External Scripts
Create a reusable script loader, load SDKs on interaction or route entry, and protect the app from duplicate script injection.
JavaScriptReactNext.jsRazorpay/Stripe SDKs
Prerequisites
- A third-party script such as payment, analytics, maps, chat, or video.
- A clear trigger for when the script is actually needed.
- A fallback UI for failed script loading.
1
Plan the implementation
Start by choosing the exact page, route, API, or deployment surface you want to improve. A narrow target makes the implementation measurable and easier to verify.
- Write down the current behavior and the user-facing problem it creates.
- Pick one measurable success signal such as bundle size, latency, error rate, security coverage, or UI responsiveness.
- Identify the files, routes, providers, and environment variables involved.
- Create a rollback note before changing production-sensitive configuration.
2
Set up the required tools
Install or configure only the tools needed for this implementation. Keep config close to the feature so future developers can find the moving parts quickly.
Implementation snippet
npm run dev
# Open DevTools > Network and filter by JS.Checklist
- Dependencies are added to the correct workspace package.
- Environment variables are documented in `.env.example` when needed.
- Local development still starts without production-only secrets.
- The change is small enough to review in one pull request.
3
Implement the core pattern
- Remove the SDK script from the global HTML document when it is not required for every page.
- Create a script loader that returns the same promise when called multiple times.
- Call the loader from the user action or route where the SDK is required.
- Show loading and failure states around the action.
- Confirm the script is absent on unrelated pages and appears only after the trigger.
Implementation snippet
const loadedScripts = new Map<string, Promise<void>>();
export function loadExternalScript(src: string) {
if (loadedScripts.has(src)) return loadedScripts.get(src)!;
const promise = new Promise<void>((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load ${src}`));
document.head.appendChild(script);
});
loadedScripts.set(src, promise);
return promise;
}
async function handlePay() {
await loadExternalScript("https://checkout.razorpay.com/v1/checkout.js");
// open checkout after the SDK is available
}4
Handle edge cases
Checklist
- The script is not part of the initial network waterfall on unrelated pages.
- Double-clicking the trigger does not insert duplicate script tags.
- A failed script load shows a useful retry path.
- The main CTA remains disabled while the SDK is loading.
5
Verify before production
- Run the app locally and test the normal success path.
- Test one failure path, one empty state, and one slow-network or retry path.
- Run the project build and any related unit or integration tests.
- Check browser console, server logs, and network responses for hidden warnings.
- Document the final behavior, commands used, and any follow-up work.