rsnext/packages/next/client/script.tsx

320 lines
8.8 KiB
TypeScript
Raw Normal View History

'use client'
Load `beforeInteractive` scripts properly without blocking hydration (#41164) This PR ensures that for the app directory, `beforeInteractive`, `afterInteractive` and `lazyOnload` scripts via `next/script` are properly supported. For both `beforeInteractive` and `afterInteractive` scripts, a preload link tag needs to be injected by Float. For `beforeInteractive` scripts and Next.js' polyfills, they need to be manually executed in order before starting the Next.js' runtime, without blocking the downloading of HTML and other scripts. This PR doesn't include the `worker` type of scripts yet. Note: in this PR I changed the inlined flight data `__next_s` to `__next_f`, and use `__next_s` for scripts data, because I can't find a better name for `next/script` that is also short at the same time. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
2022-10-09 17:08:51 +02:00
import ReactDOM from 'react-dom'
import React, { useEffect, useContext, useRef } from 'react'
2020-12-01 19:10:16 +01:00
import { ScriptHTMLAttributes } from 'react'
import { HeadManagerContext } from '../shared/lib/head-manager-context'
2020-12-01 19:10:16 +01:00
import { DOMAttributeNames } from './head-manager'
import { requestIdleCallback } from './request-idle-callback'
2020-12-01 19:10:16 +01:00
const ScriptCache = new Map()
const LoadCache = new Set()
export interface ScriptProps extends ScriptHTMLAttributes<HTMLScriptElement> {
Adds web worker support to `<Script />` using Partytown (#34244) ## Summary This PR adds a new `worker` strategy to the `<Script />` component that automatically relocates and executes the script in a web worker. ```jsx <Script strategy="worker" ... /> ``` [Partytown](https://partytown.builder.io/) is used under the hood to provide this functionality. ## Behavior - This will land as an experimental feature and will only work behind an opt-in flag in `next.config.js`: ```js experimental: { nextScriptWorkers: true } ``` - This setup use a similar approach to how ESLint and Typescript is used in Next.js by showing an error to the user to install the dependency locally themselves if they've enabled the experimental `nextScriptWorkers` flag. <img width="1068" alt="Screen Shot 2022-03-03 at 2 33 13 PM" src="https://user-images.githubusercontent.com/12476932/156639227-42af5353-a2a6-4126-936e-269112809651.png"> - For Partytown to work, a number of static files must be served directly from the site (see [docs](https://partytown.builder.io/copy-library-files)). In this PR, these files are automatically copied to a `~partytown` directory in `.next/static` during `next build` and `next dev` if the `nextScriptWorkers` flag is set to true. ## Checklist - [X] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [X] Related issues linked using `fixes #number` - [X] Integration tests added - [X] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. This PR fixes #31517.
2022-03-11 23:26:46 +01:00
strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker'
2020-12-01 19:10:16 +01:00
id?: string
onLoad?: (e: any) => void
onReady?: () => void | null
onError?: (e: any) => void
2020-12-01 19:10:16 +01:00
children?: React.ReactNode
}
/**
* @deprecated Use `ScriptProps` instead.
*/
export type Props = ScriptProps
const ignoreProps = [
'onLoad',
'onReady',
'dangerouslySetInnerHTML',
'children',
'onError',
'strategy',
]
const loadScript = (props: ScriptProps): void => {
2020-12-01 19:10:16 +01:00
const {
src,
id,
2020-12-01 19:10:16 +01:00
onLoad = () => {},
onReady = null,
2020-12-01 19:10:16 +01:00
dangerouslySetInnerHTML,
children = '',
strategy = 'afterInteractive',
2020-12-01 19:10:16 +01:00
onError,
} = props
const cacheKey = id || src
// Script has already loaded
if (cacheKey && LoadCache.has(cacheKey)) {
return
}
// Contents of this script are already loading/loaded
2020-12-01 19:10:16 +01:00
if (ScriptCache.has(src)) {
LoadCache.add(cacheKey)
// It is possible that multiple `next/script` components all have same "src", but has different "onLoad"
// This is to make sure the same remote script will only load once, but "onLoad" are executed in order
ScriptCache.get(src).then(onLoad, onError)
2020-12-01 19:10:16 +01:00
return
}
/** Execute after the script first loaded */
const afterLoad = () => {
// Run onReady for the first time after load event
if (onReady) {
onReady()
}
// add cacheKey to LoadCache when load successfully
LoadCache.add(cacheKey)
}
2020-12-01 19:10:16 +01:00
const el = document.createElement('script')
const loadPromise = new Promise<void>((resolve, reject) => {
el.addEventListener('load', function (e) {
2020-12-01 19:10:16 +01:00
resolve()
if (onLoad) {
onLoad.call(this, e)
2020-12-01 19:10:16 +01:00
}
afterLoad()
2020-12-01 19:10:16 +01:00
})
el.addEventListener('error', function (e) {
reject(e)
2020-12-01 19:10:16 +01:00
})
}).catch(function (e) {
if (onError) {
onError(e)
}
2020-12-01 19:10:16 +01:00
})
if (dangerouslySetInnerHTML) {
el.innerHTML = dangerouslySetInnerHTML.__html || ''
fix(#39993): avoid race condition for next/script onReady (#40002) Fixes #39993. Before the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, skip `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` even if it might not fully load yet - Because of React's strict mode, `useEffect` for `onReady` executes again - Since the script's cacheKey is in `LoadCache`, `onReady` is called (even when the script is not loaded yet) - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is called again After the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, `useEffect` skips `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` only if it is an inline script - Because of React's strict mode, `useEffect` for `onReady` executes again - The script is not yet loaded, its cacheKey is not in `LoadCache`, `useEffect` skips `onReady` again - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is finally called In short, the PR resolves a race condition that only occurs under React strict mode (and makes the `next/script` component more concurrent rendering resilient). ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md`
2022-08-28 10:47:55 +02:00
afterLoad()
2020-12-01 19:10:16 +01:00
} else if (children) {
el.textContent =
typeof children === 'string'
? children
: Array.isArray(children)
? children.join('')
: ''
fix(#39993): avoid race condition for next/script onReady (#40002) Fixes #39993. Before the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, skip `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` even if it might not fully load yet - Because of React's strict mode, `useEffect` for `onReady` executes again - Since the script's cacheKey is in `LoadCache`, `onReady` is called (even when the script is not loaded yet) - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is called again After the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, `useEffect` skips `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` only if it is an inline script - Because of React's strict mode, `useEffect` for `onReady` executes again - The script is not yet loaded, its cacheKey is not in `LoadCache`, `useEffect` skips `onReady` again - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is finally called In short, the PR resolves a race condition that only occurs under React strict mode (and makes the `next/script` component more concurrent rendering resilient). ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md`
2022-08-28 10:47:55 +02:00
afterLoad()
2020-12-01 19:10:16 +01:00
} else if (src) {
el.src = src
fix(#39993): avoid race condition for next/script onReady (#40002) Fixes #39993. Before the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, skip `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` even if it might not fully load yet - Because of React's strict mode, `useEffect` for `onReady` executes again - Since the script's cacheKey is in `LoadCache`, `onReady` is called (even when the script is not loaded yet) - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is called again After the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, `useEffect` skips `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` only if it is an inline script - Because of React's strict mode, `useEffect` for `onReady` executes again - The script is not yet loaded, its cacheKey is not in `LoadCache`, `useEffect` skips `onReady` again - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is finally called In short, the PR resolves a race condition that only occurs under React strict mode (and makes the `next/script` component more concurrent rendering resilient). ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md`
2022-08-28 10:47:55 +02:00
// do not add cacheKey into LoadCache for remote script here
// cacheKey will be added to LoadCache when it is actually loaded (see loadPromise above)
ScriptCache.set(src, loadPromise)
2020-12-01 19:10:16 +01:00
}
for (const [k, value] of Object.entries(props)) {
if (value === undefined || ignoreProps.includes(k)) {
2020-12-01 19:10:16 +01:00
continue
}
const attr = DOMAttributeNames[k] || k.toLowerCase()
el.setAttribute(attr, value)
}
Adds web worker support to `<Script />` using Partytown (#34244) ## Summary This PR adds a new `worker` strategy to the `<Script />` component that automatically relocates and executes the script in a web worker. ```jsx <Script strategy="worker" ... /> ``` [Partytown](https://partytown.builder.io/) is used under the hood to provide this functionality. ## Behavior - This will land as an experimental feature and will only work behind an opt-in flag in `next.config.js`: ```js experimental: { nextScriptWorkers: true } ``` - This setup use a similar approach to how ESLint and Typescript is used in Next.js by showing an error to the user to install the dependency locally themselves if they've enabled the experimental `nextScriptWorkers` flag. <img width="1068" alt="Screen Shot 2022-03-03 at 2 33 13 PM" src="https://user-images.githubusercontent.com/12476932/156639227-42af5353-a2a6-4126-936e-269112809651.png"> - For Partytown to work, a number of static files must be served directly from the site (see [docs](https://partytown.builder.io/copy-library-files)). In this PR, these files are automatically copied to a `~partytown` directory in `.next/static` during `next build` and `next dev` if the `nextScriptWorkers` flag is set to true. ## Checklist - [X] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [X] Related issues linked using `fixes #number` - [X] Integration tests added - [X] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. This PR fixes #31517.
2022-03-11 23:26:46 +01:00
if (strategy === 'worker') {
el.setAttribute('type', 'text/partytown')
}
el.setAttribute('data-nscript', strategy)
2020-12-01 19:10:16 +01:00
document.body.appendChild(el)
}
export function handleClientScriptLoad(props: ScriptProps) {
const { strategy = 'afterInteractive' } = props
if (strategy === 'lazyOnload') {
window.addEventListener('load', () => {
requestIdleCallback(() => loadScript(props))
})
} else {
loadScript(props)
}
}
function loadLazyScript(props: ScriptProps) {
if (document.readyState === 'complete') {
requestIdleCallback(() => loadScript(props))
} else {
window.addEventListener('load', () => {
requestIdleCallback(() => loadScript(props))
})
}
}
function addBeforeInteractiveToCache() {
const scripts = [
...document.querySelectorAll('[data-nscript="beforeInteractive"]'),
...document.querySelectorAll('[data-nscript="beforePageRender"]'),
]
scripts.forEach((script) => {
const cacheKey = script.id || script.getAttribute('src')
LoadCache.add(cacheKey)
})
}
export function initScriptLoader(scriptLoaderItems: ScriptProps[]) {
scriptLoaderItems.forEach(handleClientScriptLoad)
addBeforeInteractiveToCache()
}
function Script(props: ScriptProps): JSX.Element | null {
2020-12-01 19:10:16 +01:00
const {
id,
2020-12-01 19:10:16 +01:00
src = '',
onLoad = () => {},
onReady = null,
strategy = 'afterInteractive',
2020-12-01 19:10:16 +01:00
onError,
...restProps
} = props
// Context is available only during SSR
Load `beforeInteractive` scripts properly without blocking hydration (#41164) This PR ensures that for the app directory, `beforeInteractive`, `afterInteractive` and `lazyOnload` scripts via `next/script` are properly supported. For both `beforeInteractive` and `afterInteractive` scripts, a preload link tag needs to be injected by Float. For `beforeInteractive` scripts and Next.js' polyfills, they need to be manually executed in order before starting the Next.js' runtime, without blocking the downloading of HTML and other scripts. This PR doesn't include the `worker` type of scripts yet. Note: in this PR I changed the inlined flight data `__next_s` to `__next_f`, and use `__next_s` for scripts data, because I can't find a better name for `next/script` that is also short at the same time. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
2022-10-09 17:08:51 +02:00
const { updateScripts, scripts, getIsSsr, appDir, nonce } =
useContext(HeadManagerContext)
2020-12-01 19:10:16 +01:00
/**
* - First mount:
* 1. The useEffect for onReady executes
* 2. hasOnReadyEffectCalled.current is false, but the script hasn't loaded yet (not in LoadCache)
* onReady is skipped, set hasOnReadyEffectCalled.current to true
* 3. The useEffect for loadScript executes
* 4. hasLoadScriptEffectCalled.current is false, loadScript executes
* Once the script is loaded, the onLoad and onReady will be called by then
* [If strict mode is enabled / is wrapped in <OffScreen /> component]
* 5. The useEffect for onReady executes again
* 6. hasOnReadyEffectCalled.current is true, so entire effect is skipped
* 7. The useEffect for loadScript executes again
* 8. hasLoadScriptEffectCalled.current is true, so entire effect is skipped
*
* - Second mount:
* 1. The useEffect for onReady executes
* 2. hasOnReadyEffectCalled.current is false, but the script has already loaded (found in LoadCache)
* onReady is called, set hasOnReadyEffectCalled.current to true
* 3. The useEffect for loadScript executes
* 4. The script is already loaded, loadScript bails out
* [If strict mode is enabled / is wrapped in <OffScreen /> component]
* 5. The useEffect for onReady executes again
* 6. hasOnReadyEffectCalled.current is true, so entire effect is skipped
* 7. The useEffect for loadScript executes again
* 8. hasLoadScriptEffectCalled.current is true, so entire effect is skipped
*/
const hasOnReadyEffectCalled = useRef(false)
useEffect(() => {
const cacheKey = id || src
if (!hasOnReadyEffectCalled.current) {
// Run onReady if script has loaded before but component is re-mounted
if (onReady && cacheKey && LoadCache.has(cacheKey)) {
onReady()
}
hasOnReadyEffectCalled.current = true
}
}, [onReady, id, src])
const hasLoadScriptEffectCalled = useRef(false)
2020-12-01 19:10:16 +01:00
useEffect(() => {
if (!hasLoadScriptEffectCalled.current) {
if (strategy === 'afterInteractive') {
loadScript(props)
} else if (strategy === 'lazyOnload') {
loadLazyScript(props)
}
hasLoadScriptEffectCalled.current = true
2020-12-01 19:10:16 +01:00
}
}, [props, strategy])
Adds web worker support to `<Script />` using Partytown (#34244) ## Summary This PR adds a new `worker` strategy to the `<Script />` component that automatically relocates and executes the script in a web worker. ```jsx <Script strategy="worker" ... /> ``` [Partytown](https://partytown.builder.io/) is used under the hood to provide this functionality. ## Behavior - This will land as an experimental feature and will only work behind an opt-in flag in `next.config.js`: ```js experimental: { nextScriptWorkers: true } ``` - This setup use a similar approach to how ESLint and Typescript is used in Next.js by showing an error to the user to install the dependency locally themselves if they've enabled the experimental `nextScriptWorkers` flag. <img width="1068" alt="Screen Shot 2022-03-03 at 2 33 13 PM" src="https://user-images.githubusercontent.com/12476932/156639227-42af5353-a2a6-4126-936e-269112809651.png"> - For Partytown to work, a number of static files must be served directly from the site (see [docs](https://partytown.builder.io/copy-library-files)). In this PR, these files are automatically copied to a `~partytown` directory in `.next/static` during `next build` and `next dev` if the `nextScriptWorkers` flag is set to true. ## Checklist - [X] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [X] Related issues linked using `fixes #number` - [X] Integration tests added - [X] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. This PR fixes #31517.
2022-03-11 23:26:46 +01:00
if (strategy === 'beforeInteractive' || strategy === 'worker') {
2020-12-01 19:10:16 +01:00
if (updateScripts) {
Adds web worker support to `<Script />` using Partytown (#34244) ## Summary This PR adds a new `worker` strategy to the `<Script />` component that automatically relocates and executes the script in a web worker. ```jsx <Script strategy="worker" ... /> ``` [Partytown](https://partytown.builder.io/) is used under the hood to provide this functionality. ## Behavior - This will land as an experimental feature and will only work behind an opt-in flag in `next.config.js`: ```js experimental: { nextScriptWorkers: true } ``` - This setup use a similar approach to how ESLint and Typescript is used in Next.js by showing an error to the user to install the dependency locally themselves if they've enabled the experimental `nextScriptWorkers` flag. <img width="1068" alt="Screen Shot 2022-03-03 at 2 33 13 PM" src="https://user-images.githubusercontent.com/12476932/156639227-42af5353-a2a6-4126-936e-269112809651.png"> - For Partytown to work, a number of static files must be served directly from the site (see [docs](https://partytown.builder.io/copy-library-files)). In this PR, these files are automatically copied to a `~partytown` directory in `.next/static` during `next build` and `next dev` if the `nextScriptWorkers` flag is set to true. ## Checklist - [X] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [X] Related issues linked using `fixes #number` - [X] Integration tests added - [X] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. This PR fixes #31517.
2022-03-11 23:26:46 +01:00
scripts[strategy] = (scripts[strategy] || []).concat([
2020-12-01 19:10:16 +01:00
{
id,
2020-12-01 19:10:16 +01:00
src,
onLoad,
onReady,
2020-12-01 19:10:16 +01:00
onError,
...restProps,
},
])
updateScripts(scripts)
} else if (getIsSsr && getIsSsr()) {
// Script has already loaded during SSR
LoadCache.add(id || src)
} else if (getIsSsr && !getIsSsr()) {
loadScript(props)
2020-12-01 19:10:16 +01:00
}
}
Load `beforeInteractive` scripts properly without blocking hydration (#41164) This PR ensures that for the app directory, `beforeInteractive`, `afterInteractive` and `lazyOnload` scripts via `next/script` are properly supported. For both `beforeInteractive` and `afterInteractive` scripts, a preload link tag needs to be injected by Float. For `beforeInteractive` scripts and Next.js' polyfills, they need to be manually executed in order before starting the Next.js' runtime, without blocking the downloading of HTML and other scripts. This PR doesn't include the `worker` type of scripts yet. Note: in this PR I changed the inlined flight data `__next_s` to `__next_f`, and use `__next_s` for scripts data, because I can't find a better name for `next/script` that is also short at the same time. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
2022-10-09 17:08:51 +02:00
// For the app directory, we need React Float to preload these scripts.
if (appDir) {
// Before interactive scripts need to be loaded by Next.js' runtime instead
// of native <script> tags, because they no longer have `defer`.
Load `beforeInteractive` scripts properly without blocking hydration (#41164) This PR ensures that for the app directory, `beforeInteractive`, `afterInteractive` and `lazyOnload` scripts via `next/script` are properly supported. For both `beforeInteractive` and `afterInteractive` scripts, a preload link tag needs to be injected by Float. For `beforeInteractive` scripts and Next.js' polyfills, they need to be manually executed in order before starting the Next.js' runtime, without blocking the downloading of HTML and other scripts. This PR doesn't include the `worker` type of scripts yet. Note: in this PR I changed the inlined flight data `__next_s` to `__next_f`, and use `__next_s` for scripts data, because I can't find a better name for `next/script` that is also short at the same time. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
2022-10-09 17:08:51 +02:00
if (strategy === 'beforeInteractive') {
if (!src) {
// For inlined scripts, we put the content in `children`.
if (restProps.dangerouslySetInnerHTML) {
restProps.children = restProps.dangerouslySetInnerHTML.__html
delete restProps.dangerouslySetInnerHTML
}
return (
<script
nonce={nonce}
dangerouslySetInnerHTML={{
__html: `(self.__next_s=self.__next_s||[]).push(${JSON.stringify([
0,
{ ...restProps },
])})`,
}}
/>
)
}
// @ts-ignore
ReactDOM.preload(
src,
restProps.integrity
? { as: 'script', integrity: restProps.integrity }
: { as: 'script' }
)
return (
<script
nonce={nonce}
dangerouslySetInnerHTML={{
__html: `(self.__next_s=self.__next_s||[]).push(${JSON.stringify([
src,
])})`,
}}
/>
)
} else if (strategy === 'afterInteractive') {
if (src) {
// @ts-ignore
ReactDOM.preload(
src,
restProps.integrity
? { as: 'script', integrity: restProps.integrity }
: { as: 'script' }
)
}
}
}
2020-12-01 19:10:16 +01:00
return null
}
Object.defineProperty(Script, '__nextScript', { value: true })
export default Script