diff --git a/docs/api-reference/next/head.md b/docs/api-reference/next/head.md
index 63010ff4e0643c..96a6d14a5ea316 100644
--- a/docs/api-reference/next/head.md
+++ b/docs/api-reference/next/head.md
@@ -55,7 +55,7 @@ function IndexPage() {
export default IndexPage
```
-In this case only the second `` is rendered. `meta` tags with duplicate `name` attributes are automatically handled.
+In this case only the second `` is rendered. `meta` tags with duplicate `key` attributes are automatically handled.
> The contents of `head` get cleared upon unmounting the component, so make sure each page completely defines what it needs in `head`, without making assumptions about what other pages added.
diff --git a/errors/next-script-for-ga.md b/errors/next-script-for-ga.md
index 2f367dff127c31..1d968090e1f150 100644
--- a/errors/next-script-for-ga.md
+++ b/errors/next-script-for-ga.md
@@ -19,9 +19,9 @@ const Home = () => {
-
)
diff --git a/examples/with-google-analytics/pages/_app.js b/examples/with-google-analytics/pages/_app.js
index 79ebc4915b0873..d8334f3754d341 100644
--- a/examples/with-google-analytics/pages/_app.js
+++ b/examples/with-google-analytics/pages/_app.js
@@ -1,4 +1,5 @@
import { useEffect } from 'react'
+import Script from 'next/script'
import { useRouter } from 'next/router'
import * as gtag from '../lib/gtag'
@@ -14,7 +15,30 @@ const App = ({ Component, pageProps }) => {
}
}, [router.events])
- return
+ return (
+ <>
+ {/* Global Site Tag (gtag.js) - Google Analytics */}
+
+
+
+ >
+ )
}
export default App
diff --git a/examples/with-google-analytics/pages/_document.js b/examples/with-google-analytics/pages/_document.js
deleted file mode 100644
index 572dffed49cc20..00000000000000
--- a/examples/with-google-analytics/pages/_document.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import Document, { Html, Head, Main, NextScript } from 'next/document'
-
-import { GA_TRACKING_ID } from '../lib/gtag'
-
-export default class MyDocument extends Document {
- render() {
- return (
-
-
- {/* Global Site Tag (gtag.js) - Google Analytics */}
-
-
-
-
-
-
-
-
- )
- }
-}
diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts b/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts
index 50fdcc093cbf79..954281fba74bf9 100644
--- a/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts
+++ b/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts
@@ -400,7 +400,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
}
if (renderMode) return { html: result, renderOpts }
- return result ? await result.toUnchunkedString() : null
+ return result ? result.toUnchunkedString() : null
} catch (err) {
if (!parsedUrl!) {
parsedUrl = parseUrl(req.url!, true)
diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx
index 5174d5f3f5678c..9730f0d5604d3e 100644
--- a/packages/next/client/image.tsx
+++ b/packages/next/client/image.tsx
@@ -2,7 +2,7 @@ import React from 'react'
import Head from '../shared/lib/head'
import { toBase64 } from '../shared/lib/to-base-64'
import {
- ImageConfig,
+ ImageConfigComplete,
imageConfigDefault,
LoaderValue,
VALID_LOADERS,
@@ -110,7 +110,8 @@ const {
loader: configLoader,
path: configPath,
domains: configDomains,
-} = (process.env.__NEXT_IMAGE_OPTS as any as ImageConfig) || imageConfigDefault
+} = (process.env.__NEXT_IMAGE_OPTS as any as ImageConfigComplete) ||
+imageConfigDefault
// sort smallest to largest
const allSizes = [...configDeviceSizes, ...configImageSizes]
configDeviceSizes.sort((a, b) => a - b)
diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx
index f71f48eb9ce789..694acd0cf30df4 100644
--- a/packages/next/client/index.tsx
+++ b/packages/next/client/index.tsx
@@ -2,6 +2,7 @@
import '@next/polyfill-module'
import React from 'react'
import ReactDOM from 'react-dom'
+import { StyleRegistry } from 'styled-jsx'
import { HeadManagerContext } from '../shared/lib/head-manager-context'
import mitt, { MittEmitter } from '../shared/lib/mitt'
import { RouterContext } from '../shared/lib/router-context'
@@ -603,7 +604,7 @@ function AppContainer({
>
- {children}
+ {children}
diff --git a/packages/next/export/worker.ts b/packages/next/export/worker.ts
index f4e40cde8f6d5d..9422a414563f08 100644
--- a/packages/next/export/worker.ts
+++ b/packages/next/export/worker.ts
@@ -417,7 +417,7 @@ export default async function exportPage({
}
}
- const html = renderResult ? await renderResult.toUnchunkedString() : ''
+ const html = renderResult ? renderResult.toUnchunkedString() : ''
if (inAmpMode && !curRenderOpts.ampSkipValidation) {
if (!results.ssgNotFound) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
@@ -460,7 +460,7 @@ export default async function exportPage({
}
const ampHtml = ampRenderResult
- ? await ampRenderResult.toUnchunkedString()
+ ? ampRenderResult.toUnchunkedString()
: ''
if (!curRenderOpts.ampSkipValidation) {
await validateAmp(ampHtml, page + '?amp=1')
diff --git a/packages/next/package.json b/packages/next/package.json
index 405432af9b0642..bf4f78ee48f187 100644
--- a/packages/next/package.json
+++ b/packages/next/package.json
@@ -106,7 +106,7 @@
"stream-browserify": "3.0.0",
"stream-http": "3.1.1",
"string_decoder": "1.3.0",
- "styled-jsx": "4.0.1",
+ "styled-jsx": "5.0.0-beta.1",
"timers-browserify": "2.0.12",
"tty-browserify": "0.0.1",
"use-subscription": "1.5.1",
diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index cdb4095cee8f59..02aad2c8939e43 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -1,5 +1,4 @@
import React, { Component, ReactElement, ReactNode, useContext } from 'react'
-import flush from 'styled-jsx/server'
import {
BODY_RENDER_TARGET,
OPTIMIZED_FONT_PROVIDERS,
@@ -166,16 +165,8 @@ export default class Document extends Component {
* `getInitialProps` hook returns the context object with the addition of `renderPage`.
* `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers
*/
- static async getInitialProps(
- ctx: DocumentContext
- ): Promise {
- const enhanceApp = (App: any) => {
- return (props: any) =>
- }
-
- const { html, head } = await ctx.renderPage({ enhanceApp })
- const styles = [...flush()]
- return { html, head, styles }
+ static getInitialProps(ctx: DocumentContext): Promise {
+ return ctx.defaultGetInitialProps(ctx)
}
render() {
@@ -213,6 +204,50 @@ export function Html(
)
}
+function AmpStyles({
+ styles,
+}: {
+ styles?: React.ReactElement[] | React.ReactFragment
+}) {
+ if (!styles) return null
+
+ // try to parse styles from fragment for backwards compat
+ const curStyles: React.ReactElement[] = Array.isArray(styles)
+ ? (styles as React.ReactElement[])
+ : []
+ if (
+ // @ts-ignore Property 'props' does not exist on type ReactElement
+ styles.props &&
+ // @ts-ignore Property 'props' does not exist on type ReactElement
+ Array.isArray(styles.props.children)
+ ) {
+ const hasStyles = (el: React.ReactElement) =>
+ el?.props?.dangerouslySetInnerHTML?.__html
+ // @ts-ignore Property 'props' does not exist on type ReactElement
+ styles.props.children.forEach((child: React.ReactElement) => {
+ if (Array.isArray(child)) {
+ child.forEach((el) => hasStyles(el) && curStyles.push(el))
+ } else if (hasStyles(child)) {
+ curStyles.push(child)
+ }
+ })
+ }
+
+ /* Add custom styles before AMP styles to prevent accidental overrides */
+ return (
+