import PropTypes from 'prop-types' import React, { Component } from 'react' import flush from 'styled-jsx/server' import { CLIENT_STATIC_FILES_RUNTIME_AMP, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, AMP_RENDER_TARGET, } from '../next-server/lib/constants' import { DocumentContext as DocumentComponentContext } from '../next-server/lib/document-context' import { DocumentContext, DocumentInitialProps, DocumentProps, } from '../next-server/lib/utils' import fidPolyfill from '../next-server/lib/fid' import { cleanAmpPath } from '../next-server/server/utils' import { htmlEscapeJsonString } from '../server/htmlescape' export { DocumentContext, DocumentInitialProps, DocumentProps } export type OriginProps = { nonce?: string crossOrigin?: string } export async function middleware({ req, res }: DocumentContext) {} function dedupe(bundles: any[]): any[] { const files = new Set() const kept = [] for (const bundle of bundles) { if (files.has(bundle.file)) continue files.add(bundle.file) kept.push(bundle) } return kept } function getOptionalModernScriptVariant(path: string) { if (process.env.__NEXT_MODERN_BUILD) { return path.replace(/\.js$/, '.module.js') } return path } /** * `Document` component handles the initial `document` markup and renders only on the server side. * Commonly used for implementing server side rendering for `css-in-js` libraries. */ export default class Document

extends Component { static headTagsMiddleware = process.env.__NEXT_PLUGINS ? import( // @ts-ignore loader syntax 'next-plugin-loader?middleware=document-head-tags-server!' ) : () => [] static bodyTagsMiddleware = process.env.__NEXT_PLUGINS ? import( // @ts-ignore loader syntax 'next-plugin-loader?middleware=document-body-tags-server!' ) : () => [] static htmlPropsMiddleware = process.env.__NEXT_PLUGINS ? import( // @ts-ignore loader syntax 'next-plugin-loader?middleware=document-html-props-server!' ) : () => [] /** * `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 enhancers = process.env.__NEXT_PLUGINS ? await import( // @ts-ignore loader syntax 'next-plugin-loader?middleware=unstable-enhance-app-server!' ).then(mod => mod.default(ctx)) : [] const enhanceApp = (App: any) => { for (const enhancer of enhancers) { App = enhancer(App) } return (props: any) => } const { html, head } = await ctx.renderPage({ enhanceApp }) const styles = [ ...flush(), ...(process.env.__NEXT_PLUGINS ? await import( // @ts-ignore loader syntax 'next-plugin-loader?middleware=unstable-get-styles-server!' ).then(mod => mod.default(ctx)) : []), ] return { html, head, styles } } static renderDocument

( Document: new () => Document

, props: DocumentProps & P ): React.ReactElement { return ( ) } render() { return (

) } } export class Html extends Component< React.DetailedHTMLProps< React.HtmlHTMLAttributes, HTMLHtmlElement > > { static contextType = DocumentComponentContext static propTypes = { children: PropTypes.node.isRequired, } context!: React.ContextType render() { const { inAmpMode, htmlProps } = this.context._documentProps return ( ) } } export class Head extends Component< OriginProps & React.DetailedHTMLProps< React.HTMLAttributes, HTMLHeadElement > > { static contextType = DocumentComponentContext static propTypes = { nonce: PropTypes.string, crossOrigin: PropTypes.string, } context!: React.ContextType getCssLinks(): JSX.Element[] | null { const { assetPrefix, files } = this.context._documentProps const { _devOnlyInvalidateCacheQueryString } = this.context const cssFiles = files && files.length ? files.filter(f => /\.css$/.test(f)) : [] const cssLinkElements: JSX.Element[] = [] cssFiles.forEach(file => { cssLinkElements.push( , ) }) return cssLinkElements.length === 0 ? null : cssLinkElements } getPreloadDynamicChunks() { const { dynamicImports, assetPrefix } = this.context._documentProps const { _devOnlyInvalidateCacheQueryString } = this.context return ( dedupe(dynamicImports) .map((bundle: any) => { // `dynamicImports` will contain both `.js` and `.module.js` when the // feature is enabled. This clause will filter down to the modern // variants only. if (!bundle.file.endsWith(getOptionalModernScriptVariant('.js'))) { return null } return ( ) }) // Filter out nulled scripts .filter(Boolean) ) } getPreloadMainLinks(): JSX.Element[] | null { const { assetPrefix, files } = this.context._documentProps const { _devOnlyInvalidateCacheQueryString } = this.context const preloadFiles = files && files.length ? files.filter((file: string) => { // `dynamicImports` will contain both `.js` and `.module.js` when // the feature is enabled. This clause will filter down to the // modern variants only. return file.endsWith(getOptionalModernScriptVariant('.js')) }) : [] return preloadFiles.length === 0 ? null : preloadFiles.map((file: string) => { return ( ) }) } getFidPolyfill(): JSX.Element | null { if (!process.env.__NEXT_FID_POLYFILL) { return null } return (