Skip to content

Commit

Permalink
Merge branch 'canary' into feat/hook-webvitals
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi committed Sep 9, 2021
2 parents 21f7961 + f4c6cd6 commit f27cafd
Show file tree
Hide file tree
Showing 22 changed files with 160 additions and 198 deletions.
2 changes: 1 addition & 1 deletion docs/api-reference/next/head.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function IndexPage() {
export default IndexPage
```

In this case only the second `<meta property="og:title" />` is rendered. `meta` tags with duplicate `name` attributes are automatically handled.
In this case only the second `<meta property="og:title" />` 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.
Expand Down
10 changes: 5 additions & 5 deletions errors/next-script-for-ga.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ const Home = () => {
<!-- Global site tag (gtag.js) - Google Analytics -->
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
strategy="lazyOnload"
strategy="afterInteractive"
/>
<Script id="google-analytics">
<Script id="google-analytics" strategy="afterInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){window.dataLayer.push(arguments);}
Expand All @@ -47,7 +47,7 @@ import Script from 'next/script'
const Home = () => {
return (
<div class="container">
<Script id="google-analytics">
<Script id="google-analytics" strategy="afterInteractive">
{`
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
Expand All @@ -73,7 +73,7 @@ import Script from 'next/script'
const Home = () => {
return (
<div class="container">
<Script id="google-analytics">
<Script id="google-analytics" strategy="afterInteractive">
{`
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'GOOGLE_ANALYTICS_ID', 'auto');
Expand All @@ -82,7 +82,7 @@ const Home = () => {
</Script>
<Script
src="https://www.google-analytics.com/analytics.js"
strategy="lazyOnload"
strategy="afterInteractive"
/>
</div>
)
Expand Down
26 changes: 25 additions & 1 deletion examples/with-google-analytics/pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect } from 'react'
import Script from 'next/script'
import { useRouter } from 'next/router'
import * as gtag from '../lib/gtag'

Expand All @@ -14,7 +15,30 @@ const App = ({ Component, pageProps }) => {
}
}, [router.events])

return <Component {...pageProps} />
return (
<>
{/* Global Site Tag (gtag.js) - Google Analytics */}
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
/>
<Script
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${gtag.GA_TRACKING_ID}', {
page_path: window.location.pathname,
});
`,
}}
/>
<Component {...pageProps} />
</>
)
}

export default App
36 changes: 0 additions & 36 deletions examples/with-google-analytics/pages/_document.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion packages/next/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -603,7 +604,7 @@ function AppContainer({
>
<RouterContext.Provider value={makePublicRouterInstance(router)}>
<HeadManagerContext.Provider value={headManager}>
{children}
<StyleRegistry>{children}</StyleRegistry>
</HeadManagerContext.Provider>
</RouterContext.Provider>
</Container>
Expand Down
4 changes: 2 additions & 2 deletions packages/next/export/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
95 changes: 47 additions & 48 deletions packages/next/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -166,16 +165,8 @@ export default class Document<P = {}> extends Component<DocumentProps & P> {
* `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<DocumentInitialProps> {
const enhanceApp = (App: any) => {
return (props: any) => <App {...props} />
}

const { html, head } = await ctx.renderPage({ enhanceApp })
const styles = [...flush()]
return { html, head, styles }
static getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
return ctx.defaultGetInitialProps(ctx)
}

render() {
Expand Down Expand Up @@ -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 (
<style
amp-custom=""
dangerouslySetInnerHTML={{
__html: curStyles
.map((style) => style.props.dangerouslySetInnerHTML.__html)
.join('')
.replace(/\/\*# sourceMappingURL=.*\*\//g, '')
.replace(/\/\*@ sourceURL=.*?\*\//g, ''),
}}
/>
)
}

export class Head extends Component<
OriginProps &
React.DetailedHTMLProps<
Expand Down Expand Up @@ -555,30 +590,6 @@ export class Head extends Component<
return child
})

// try to parse styles from fragment for backwards compat
const curStyles: React.ReactElement[] = Array.isArray(styles)
? (styles as React.ReactElement[])
: []
if (
inAmpMode &&
styles &&
// @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)
}
})
}

const files: DocumentFiles = getDocumentFiles(
this.context.buildManifest,
this.context.__NEXT_DATA__.page,
Expand Down Expand Up @@ -635,19 +646,7 @@ export class Head extends Component<
as="script"
href="https://cdn.ampproject.org/v0.js"
/>
{/* Add custom styles before AMP styles to prevent accidental overrides */}
{styles && (
<style
amp-custom=""
dangerouslySetInnerHTML={{
__html: curStyles
.map((style) => style.props.dangerouslySetInnerHTML.__html)
.join('')
.replace(/\/\*# sourceMappingURL=.*\*\//g, '')
.replace(/\/\*@ sourceURL=.*?\*\//g, ''),
}}
/>
)}
<AmpStyles styles={styles} />
<style
amp-boilerplate=""
dangerouslySetInnerHTML={{
Expand Down
12 changes: 7 additions & 5 deletions packages/next/server/config-shared.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import os from 'os'
import { Header, Redirect, Rewrite } from '../lib/load-custom-routes'
import { ImageConfig, imageConfigDefault } from './image-config'
import {
ImageConfig,
ImageConfigComplete,
imageConfigDefault,
} from './image-config'

type NoOptionals<T> = {
[P in keyof T]-?: T[P]
export type NextConfigComplete = Required<NextConfig> & {
images: ImageConfigComplete
}

export type NextConfigComplete = NoOptionals<NextConfig>

export interface I18NConfig {
defaultLocale: string
domains?: DomainLocale[]
Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ function assignDefaults(userConfig: { [key: string]: any }) {
}

if (result?.images) {
const images: Partial<ImageConfig> = result.images
const images: ImageConfig = result.images

if (typeof images !== 'object') {
throw new Error(
Expand Down
5 changes: 4 additions & 1 deletion packages/next/server/dev/on-demand-entry-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ export default function onDemandEntryHandler(
}

multiCompiler.hooks.done.tap('NextJsOnDemandEntries', (multiStats) => {
if (invalidator.rebuildAgain) {
return invalidator.doneBuilding()
}
const [clientStats, serverStats] = multiStats.stats
const pagePaths = new Set([
...getPagePathsFromEntrypoints(clientStats.compilation.entrypoints),
Expand Down Expand Up @@ -269,7 +272,7 @@ class Invalidator {
private multiCompiler: webpack.MultiCompiler
private watcher: any
private building: boolean
private rebuildAgain: boolean
public rebuildAgain: boolean

constructor(watcher: any, multiCompiler: webpack.MultiCompiler) {
this.multiCompiler = multiCompiler
Expand Down
6 changes: 4 additions & 2 deletions packages/next/server/image-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const VALID_LOADERS = [

export type LoaderValue = typeof VALID_LOADERS[number]

export type ImageConfig = {
export type ImageConfigComplete = {
deviceSizes: number[]
imageSizes: number[]
loader: LoaderValue
Expand All @@ -18,7 +18,9 @@ export type ImageConfig = {
minimumCacheTTL?: number
}

export const imageConfigDefault: ImageConfig = {
export type ImageConfig = Partial<ImageConfigComplete>

export const imageConfigDefault: ImageConfigComplete = {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
path: '/_next/image',
Expand Down

0 comments on commit f27cafd

Please sign in to comment.