.
This commit is contained in:
+434
@@ -0,0 +1,434 @@
|
||||
---
|
||||
title: How to load and optimize scripts
|
||||
nav_title: Scripts
|
||||
description: Optimize 3rd party scripts with the built-in Script component.
|
||||
related:
|
||||
title: API Reference
|
||||
description: Learn more about the next/script API.
|
||||
links:
|
||||
- app/api-reference/components/script
|
||||
---
|
||||
|
||||
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
|
||||
<AppOnly>
|
||||
|
||||
### Layout Scripts
|
||||
|
||||
To load a third-party script for multiple routes, import `next/script` and include the script directly in your layout component:
|
||||
|
||||
```tsx filename="app/dashboard/layout.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function DashboardLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<section>{children}</section>
|
||||
<Script src="https://example.com/script.js" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/dashboard/layout.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function DashboardLayout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<section>{children}</section>
|
||||
<Script src="https://example.com/script.js" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The third-party script is fetched when the folder route (e.g. `dashboard/page.js`) or any nested route (e.g. `dashboard/settings/page.js`) is accessed by the user. Next.js will ensure the script will **only load once**, even if a user navigates between multiple routes in the same layout.
|
||||
|
||||
</AppOnly>
|
||||
|
||||
### Application Scripts
|
||||
|
||||
<AppOnly>
|
||||
|
||||
To load a third-party script for all routes, import `next/script` and include the script directly in your root layout:
|
||||
|
||||
```tsx filename="app/layout.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<Script src="https://example.com/script.js" />
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/layout.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<Script src="https://example.com/script.js" />
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
To load a third-party script for all routes, import `next/script` and include the script directly in your custom `_app`:
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<>
|
||||
<Component {...pageProps} />
|
||||
<Script src="https://example.com/script.js" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
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.
|
||||
|
||||
> **Recommendation**: We recommend only including third-party scripts in specific pages or layouts in order to minimize any unnecessary impact to performance.
|
||||
|
||||
### Strategy
|
||||
|
||||
Although the default behavior of `next/script` allows you to load third-party scripts in any page or layout, you can fine-tune its loading behavior by using the `strategy` property:
|
||||
|
||||
- `beforeInteractive`: Load the script before any Next.js code and before any page hydration occurs.
|
||||
- `afterInteractive`: (**default**) Load the script early but after some hydration on the page occurs.
|
||||
- `lazyOnload`: Load the script later during browser idle time.
|
||||
- `worker`: (experimental) Load the script in a web worker.
|
||||
|
||||
Refer to the [`next/script`](/docs/app/api-reference/components/script#strategy) API reference documentation to learn more about each strategy and their use cases.
|
||||
|
||||
### Offloading Scripts To A Web Worker (experimental)
|
||||
|
||||
> **Warning:** The `worker` strategy is not yet stable and does not yet work with the App Router. Use with caution.
|
||||
|
||||
Scripts that use the `worker` strategy are offloaded and executed in a web worker with [Partytown](https://partytown.qwik.dev/). This can improve the performance of your site by dedicating the main thread to the rest of your application code.
|
||||
|
||||
This strategy is still experimental and can only be used if the `nextScriptWorkers` flag is enabled in `next.config.js`:
|
||||
|
||||
```js filename="next.config.js"
|
||||
module.exports = {
|
||||
experimental: {
|
||||
nextScriptWorkers: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then, run the development server and Next.js will guide you through the installation of the required packages to finish the setup:
|
||||
|
||||
```bash package="pnpm"
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
```bash package="npm"
|
||||
npm run dev
|
||||
```
|
||||
|
||||
```bash package="yarn"
|
||||
yarn dev
|
||||
```
|
||||
|
||||
```bash package="bun"
|
||||
bun dev
|
||||
```
|
||||
|
||||
You'll see instructions like these: Please install Partytown by running `npm install @qwik.dev/partytown`
|
||||
|
||||
Once setup is complete, defining `strategy="worker"` will automatically instantiate Partytown in your application and offload the script to a web worker.
|
||||
|
||||
```tsx filename="pages/home.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Script src="https://example.com/script.js" strategy="worker" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/home.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Script src="https://example.com/script.js" strategy="worker" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
There are a number of trade-offs that need to be considered when loading a third-party script in a web worker. Please see Partytown's [tradeoffs](https://partytown.qwik.dev/trade-offs) documentation for more information.
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
#### Using custom Partytown configuration
|
||||
|
||||
Although the `worker` strategy does not require any additional configuration to work, Partytown supports the use of a config object to modify some of its settings, including enabling `debug` mode and forwarding events and triggers.
|
||||
|
||||
If you would like to add additional configuration options, you can include it within the `<Head />` component used in a [custom `_document.js`](/docs/pages/building-your-application/routing/custom-document):
|
||||
|
||||
```jsx filename="_pages/document.jsx"
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<script
|
||||
data-partytown-config
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
partytown = {
|
||||
lib: "/_next/static/~partytown/",
|
||||
debug: true
|
||||
};
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
In order to modify Partytown's configuration, the following conditions must be met:
|
||||
|
||||
1. The `data-partytown-config` attribute must be used in order to overwrite the default configuration used by Next.js
|
||||
2. Unless you decide to save Partytown's library files in a separate directory, the `lib: "/_next/static/~partytown/"` property and value must be included in the configuration object in order to let Partytown know where Next.js stores the necessary static files.
|
||||
|
||||
> **Note**: If you are using an [asset prefix](/docs/pages/api-reference/config/next-config-js/assetPrefix) and would like to modify Partytown's default configuration, you must include it as part of the `lib` path.
|
||||
|
||||
Take a look at Partytown's [configuration options](https://partytown.qwik.dev/configuration) to see the full list of other properties that can be added.
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
### Inline Scripts
|
||||
|
||||
Inline scripts, or scripts not loaded from an external file, are also supported by the Script component. They can be written by placing the JavaScript within curly braces:
|
||||
|
||||
```jsx
|
||||
<Script id="show-banner">
|
||||
{`document.getElementById('banner').classList.remove('hidden')`}
|
||||
</Script>
|
||||
```
|
||||
|
||||
Or by using the `dangerouslySetInnerHTML` property:
|
||||
|
||||
```jsx
|
||||
<Script
|
||||
id="show-banner"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `document.getElementById('banner').classList.remove('hidden')`,
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
> **Warning**: An `id` property must be assigned for inline scripts in order for Next.js to track and optimize the script.
|
||||
|
||||
### Executing Additional Code
|
||||
|
||||
Event handlers can be used with the Script component to execute additional code after a certain event occurs:
|
||||
|
||||
- `onLoad`: Execute code after the script has finished loading.
|
||||
- `onReady`: Execute code after the script has finished loading and every time the component is mounted.
|
||||
- `onError`: Execute code if the script fails to load.
|
||||
|
||||
<AppOnly>
|
||||
|
||||
These handlers will only work when `next/script` is imported and used inside of a [Client Component](/docs/app/getting-started/server-and-client-components) where `"use client"` is defined as the first line of code:
|
||||
|
||||
```tsx filename="app/page.tsx" switcher
|
||||
'use client'
|
||||
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
onLoad={() => {
|
||||
console.log('Script has loaded')
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/page.js" switcher
|
||||
'use client'
|
||||
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
onLoad={() => {
|
||||
console.log('Script has loaded')
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Refer to the [`next/script`](/docs/app/api-reference/components/script#onload) API reference to learn more about each event handler and view examples.
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
These handlers will only work when `next/script` is imported and used inside of a [Client Component](/docs/app/getting-started/server-and-client-components) where `"use client"` is defined as the first line of code:
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
onLoad={() => {
|
||||
console.log('Script has loaded')
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
onLoad={() => {
|
||||
console.log('Script has loaded')
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Refer to the [`next/script`](/docs/pages/api-reference/components/script#onload) API reference to learn more about each event handler and view examples.
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
### Additional Attributes
|
||||
|
||||
There are many DOM attributes that can be assigned to a `<script>` element that are not used by the Script component, like [`nonce`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/nonce) or [custom data attributes](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/data-*). Including any additional attributes will automatically forward it to the final, optimized `<script>` element that is included in the HTML.
|
||||
|
||||
<AppOnly>
|
||||
|
||||
```tsx filename="app/page.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
id="example-script"
|
||||
nonce="XUENAJFW"
|
||||
data-test="script"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/page.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
id="example-script"
|
||||
nonce="XUENAJFW"
|
||||
data-test="script"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
id="example-script"
|
||||
nonce="XUENAJFW"
|
||||
data-test="script"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://example.com/script.js"
|
||||
id="example-script"
|
||||
nonce="XUENAJFW"
|
||||
data-test="script"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</PagesOnly>
|
||||
Reference in New Issue
Block a user