NextJS Script Optimization
Last Updated :
08 Aug, 2024
Scripts are very important in web development today because they help applications load quickly and work well on different devices and networks. Next. js, which is used as a front-end framework and is widely known for its SSR integrated with React, offers stable features to improve the script. Script optimization includes making the script as small as possible, limiting as many tasks as one can from the script, and making use of the cache as much as possible from the browsers.
These are the following topics that we are going to discuss:
Layout Scripts
To load a third-party script across multiple pages, import `next/script` and add the script directly to your layout component.
import Script from 'next/script';
export default function ProfileLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<section>{children}</section>
<Script src="https://another-example.com/different-script.js" />
</>
);
}
Application Scripts
To include a third-party script in all routes, import next/script and include the script in your custom _app.js file. This ensures the script loads once across your application.
import Script from 'next/script';
export default function MyApp({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Script
src="https://example.com/analytics.js"
strategy="lazyOnload" // Load the script when the page is idle
onLoad={() => {
console.log('Analytics script has loaded');
}}
onError={() => {
console.error('Failed to load analytics script');
}}
/>
</>
);
}
This script will load and execute when any route in your application is accessed. Next.js will ensure the script will only load once, even if a user navigates between multiple pages.
Strategy
The strategy property allows fine-tuning the loading behavior of scripts.
Strategy | Description |
---|
beforeInteractive | Loads the script before any Next.js code and before page hydration. |
---|
afterInteractive | Loads the script after some hydration has occurred (default). |
---|
lazyOnload | Loads the script during browser idle time. |
---|
worker | (Experimental) Loads the script in a web worker to improve performance. |
---|
Offloading Scripts to a Web Worker (Experimental)
Using the worker strategy with Partytown lets you run certain scripts in a separate thread to keep your main site running smoothly, but it's still experimental and requires enabling a special setting in your configuration.
next.config.js:
module.exports = {
experimental: {
nextScriptWorkers: true,
},
};
To install Partytown:
npm install @builder.io/partytown
to run next:
npm run dev
Once setup is done, defining strategy = "worker" will instantiate Partytown in your app and offload the script to a web worker.
import Script from 'next/script';
export default function Home() {
return (
<Script src="https://example.com/script.js" strategy="worker" />
);
}
This can improve the performance of your site by dedicating the main thread to the rest of your application code.
Inline Scripts
Inline scripts can be written directly or using dangerouslySetInnerHTML. Ensure an id property is assigned. They can be written by placing the JavaScript within curly braces:
<Script id="show-banner">
{`document.getElementById('banner').style.display = 'block';`}
</Script>
Or by using the dangerouslySetInnerHTML property:
<Script
id="show-banner"
dangerouslySetInnerHTML={{
__html: `document.querySelector('#banner').style.display = 'block';`,
}}
/>
Executing Additional Code
Use event handlers to execute additional code after script events.
- onLoad: Run code after the script has finished loading.
- onReady: Run code after the script loads and every time the component is used.
- onError: Run code if the script fails to load.
import Script from 'next/script';
export default function Page() {
return (
<>
<Script
src="https://example.com/another-script.js"
onLoad={() => {
console.log('Another script has loaded');
}}
onError={() => {
console.error('Failed to load the script');
}}
onReady={() => {
console.log('Script is ready and component has mounted');
}}
/>
</>
);
}
These handlers will only work when next/script is imported and used inside of a Client Component where "use client" is defined as the first line of code:
Additional Attributes
DOM attributes like nonce or custom data attributes can be forwarded to the script element.
This example uses async to load the script asynchronously, defer to delay execution until the HTML is parsed, and custom data attributes like data-custom. These attributes are passed directly to the final <script> tag in the HTML.
import Script from 'next/script';
export default function Page() {
return (
<>
<Script
src="https://example.com/another-script.js"
async
defer
id="another-script"
data-custom="value"
/>
</>
);
}
Steps to setup Project
Step 1 : Create a new Next.js app
npx create-next-app@latest script-optimization-example
Step 2: Open the project directory by typing following command
cd script-optimization-example
Updated Dependencies:
"dependencies": {
"next": "^14.2.5",
"react": "^18",
"react-dom": "^18"
}
Folder Structure:
Step 3: Start the application by running the following command:
npm run dev
Example: This example demonstrates script optimization in Next.js by using inline scripts and the dangerouslySetInnerHTML property with the <Script> component, ensuring scripts execute efficiently after the page loads.
CSS
/*globals.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
JavaScript
//pages/app.js
import Script from 'next/script';
import '../styles/globals.css';
function MyApp({ Component, pageProps }) {
return (
<>
<Script id="show-banner" strategy="afterInteractive">
{`document.getElementById('banner').style.display = 'block';`}
</Script>
<Component {...pageProps} />
</>
);
}
export default MyApp;
JavaScript
//pages/index.js
import Script from 'next/script';
export default function Home() {
return (
<div>
<h1>Welcome to Script Optimization Example</h1>
<div id="banner" style={{ display: 'none', backgroundColor: 'lightblue', padding: '10px' }}>
This is a banner that appears on page load!
</div>
<Script
id="show-banner"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `document.querySelector('#banner').style.display = 'block';`,
}}
/>
</div>
);
}
Run development server:
npm run dev
Output:
Output