Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script examples #31181

Merged
merged 21 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/basic-features/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ description: Next.js helps you optimize loading third-party scripts with the bui
<details>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/script-component">Script Component</a></li>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your idea of putting together all the different strategies into a single example! I may do the same and consolidate all the other examples into a separate, single example focused on showing different third-party providers (example: script-component-recipes)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! If you need any help with that just let me know 🙌

<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-google-tag-manager">Google Tag Manager</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-google-analytics">Google Analytics</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-facebook-pixel">Facebook Pixel</a></li>
Expand Down
34 changes: 34 additions & 0 deletions examples/script-component/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel
33 changes: 33 additions & 0 deletions examples/script-component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Script component

This example shows different strategies that can be used for the [`next/script` component](https://nextjs.org/docs/basic-features/script):

- [Loading Polyfills](./pages/polyfill.js)
- [Lazy loading](./pages/lazy.js)
- [Executing code after loading](./pages/onload.js)
- [Inline scripts](./pages/inline.js)
- [Forwarding attributes](./pages/attributes.js)

## Preview

Preview the example live on [StackBlitz](http://stackblitz.com/):

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/script-component)

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/script-component&project-name=script-component&repository-name=script-component)

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example script-component script-component-app
# or
yarn create next-app --example script-component script-component-app
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
13 changes: 13 additions & 0 deletions examples/script-component/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}
20 changes: 20 additions & 0 deletions examples/script-component/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Link from 'next/link'

import '../styles/global.css'

const MyApp = ({ Component, pageProps, router }) => {
const pathname = router.pathname

return (
<>
<Component {...pageProps} />
{pathname !== '/' && (
<Link href="/">
<a>See all examples</a>
</Link>
)}
</>
)
}

export default MyApp
22 changes: 22 additions & 0 deletions examples/script-component/pages/attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Script from 'next/script'

export default function Inline() {
return (
<>
{/* Attributes are forwarded */}
<Script
src="https://www.google-analytics.com/analytics.js"
id="analytics"
nonce="XUENAJFW"
data-test="analytics"
/>

<main>
<h1>Forwarded attributes</h1>
<h5>
Open devtools and check that attributes has been forwarded correctly.
</h5>
</main>
</>
)
}
36 changes: 36 additions & 0 deletions examples/script-component/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Link from 'next/link'

export default function Index() {
return (
<main>
<h1>Script component examples</h1>
<ul>
<li>
<Link href="/polyfill">
<a>Polyfill</a>
</Link>
</li>
<li>
<Link href="/lazy">
<a>Lazy Loading</a>
</Link>
</li>
<li>
<Link href="/onload">
<a>Executing code after loading</a>
</Link>
</li>
<li>
<Link href="/inline">
<a>Inline scripts</a>
</Link>
</li>
<li>
<Link href="/attributes">
<a>Forwarding attributes</a>
</Link>
</li>
</ul>
</main>
)
}
29 changes: 29 additions & 0 deletions examples/script-component/pages/inline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Script from 'next/script'

export default function Inline() {
return (
<>
{/* Execute arbitrary code */}
<Script id="show-banner" strategy="lazyOnload">
{`document.getElementById('banner').classList.remove('hidden')`}
</Script>

{/* Or */}

{/* <Script
id="show-banner"
dangerouslySetInnerHTML={{
__html: `document.getElementById('banner').classList.remove('hidden')`
}}
/> */}

<main>
<h1>Inline scripts</h1>
<h5 id="banner" className="hidden">
This is initially hidden but its being shown because the `Script`
component removed the `hidden` class.
</h5>
</main>
</>
)
}
42 changes: 42 additions & 0 deletions examples/script-component/pages/lazy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback, useEffect, useState } from 'react'
import Script from 'next/script'

export default function Lazyload() {
const [log, setLog] = useState([])

const addLog = useCallback(
(text) => {
setLog((log) => log.concat({ time: new Date(), text }))
},
[setLog]
)

useEffect(() => {
addLog(`Page loaded window.FB is undefined`)
}, [addLog])

return (
<>
{/* We lazy load the FB SDK */}
<Script
src="https://connect.facebook.net/en_US/sdk.js"
strategy="lazyOnload"
onLoad={() =>
addLog(`script loaded correctly, window.FB has been populated`)
}
/>

<main>
<h1>Lazy Loading FB sdk</h1>
<h5>You can check `window.FB` on browser console</h5>
<ul>
{log.map(({ time, text }) => (
<li key={+time}>
{time.toISOString()}: {text}
</li>
))}
</ul>
</main>
</>
)
}
46 changes: 46 additions & 0 deletions examples/script-component/pages/onload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useMemo, useState } from 'react'
import Script from 'next/script'

export default function Onload() {
const [stripe, setStripe] = useState(null)
const methods = useMemo(
() =>
stripe
? Object.entries(stripe.stripe).filter(
([_key, value]) => typeof value === 'function'
)
: [],
[stripe]
)

function handleLoad() {
const stripe = window.Stripe('pk_test_1234')

console.log('Stripe loaded: ', stripe)

setStripe({ stripe })
}

return (
<>
{/* We load Stripe sdk */}
<Script
id="stripe-js"
src="https://js.stripe.com/v3/"
onLoad={handleLoad}
/>

<main>
<h1>Executing code after loading</h1>
<div>
<p>Stripe methods: </p>
<ul>
{methods.map(([method]) => (
<li key={method}>{method}</li>
))}
</ul>
</div>
</main>
</>
)
}
48 changes: 48 additions & 0 deletions examples/script-component/pages/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect, useRef, useState } from 'react'
import Script from 'next/script'

import s from '../styles/polyfill.module.css'

export default function Polyfill() {
const ref = useRef()
const [lastIntersection, setIntersection] = useState(new Date())

useEffect(() => {
const observer = new IntersectionObserver(
(intersections) => {
const isIntersecting = intersections[0]?.isIntersecting

if (isIntersecting) {
setIntersection(new Date())
}
},
{
rootMargin: '45px',
}
)

observer.observe(ref.current)

return () => observer.disconnect()
}, [])

return (
<>
{/* We ensure that intersection observer is available by polyfilling it */}
<Script
src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
strategy="beforeInteractive"
/>

<main className={s.container}>
<h1>IntersectionObserver Polyfill</h1>
<h5>Scroll down to see when was the last intersection</h5>
<section className={s.section}>
<span ref={ref}>
Last intersection at {lastIntersection.toTimeString()}
</span>
</section>
</main>
</>
)
}
8 changes: 8 additions & 0 deletions examples/script-component/styles/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* {
font-family: sans-serif;
box-sizing: border-box;
}

.hidden {
display: none;
}
6 changes: 6 additions & 0 deletions examples/script-component/styles/polyfill.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.section {
height: 400vh;
display: flex;
align-items: center;
justify-content: center;
}