Merge pull request #25775 from bensaufley/bs_nextjs_document

[next] Elaborate on Document types
This commit is contained in:
Benjamin Lichtman
2018-06-20 09:18:01 -07:00
committed by GitHub
2 changed files with 84 additions and 24 deletions
+35 -14
View File
@@ -1,10 +1,43 @@
import * as React from "react";
import { NextContext } from ".";
export interface RenderPageResponse {
buildManifest: { [key: string]: any };
chunks: {
names: string[];
filenames: string[];
};
html?: string;
head: Array<React.ReactElement<any>>;
errorHtml: string;
}
export interface PageProps {
url: string;
}
export interface AnyPageProps extends PageProps {
[key: string]: any;
}
export type Enhancer<E extends PageProps = AnyPageProps, P extends any = E> = (page: React.ComponentType<P>) => React.ComponentType<E>;
/**
* Context object used inside `Document`
*/
export interface NextDocumentContext extends NextContext {
/** A callback that executes the actual React rendering logic (synchronously) */
renderPage<E extends PageProps = AnyPageProps, P extends any = E>(enhancer?: Enhancer<E, P>): RenderPageResponse; // tslint:disable-line:no-unnecessary-generics
}
export interface DocumentProps {
__NEXT_DATA__?: any;
dev?: boolean;
chunks?: string[];
chunks?: {
names: string[];
filenames: string[];
};
html?: string;
head?: Array<React.ReactElement<any>>;
errorHtml?: string;
@@ -13,21 +46,9 @@ export interface DocumentProps {
[key: string]: any;
}
/**
* Context object used inside `Document`
*/
export interface NextDocumentContext extends NextContext {
/** A callback that executes the actual React rendering logic (synchronously) */
renderPage(
cb?: (enhancer: () => JSX.Element) => React.ComponentType<any>
): {
[key: string]: any
};
}
export class Head extends React.Component<any> {}
export class Main extends React.Component {}
export class NextScript extends React.Component {}
export default class extends React.Component<DocumentProps> {
static getInitialProps(ctx: NextContext): DocumentProps;
static getInitialProps(ctx: NextDocumentContext): Promise<DocumentProps> | DocumentProps;
}
+49 -10
View File
@@ -1,7 +1,7 @@
import Document, { Head, Main, NextScript, NextDocumentContext } from 'next/document';
import Document, { DocumentProps, Enhancer, Head, Main, NextScript, NextDocumentContext, PageProps } from 'next/document';
import * as React from "react";
const results = (
const basicResults = (
<Document any="property" should="work" here>
<Head some="more" properties>
<meta name="description" content="Head can have children, too!" />
@@ -11,16 +11,18 @@ const results = (
</Document>
);
const Wrapper: React.SFC = ({ children }) => <React.Fragment>{children}</React.Fragment>;
export default class MyDocument extends Document {
class MyDoc extends Document {
static async getInitialProps({ renderPage }: NextDocumentContext) {
// Without callback
const page = renderPage();
// With callback
const differentPage = renderPage(App => props => <Wrapper><App {...props} /></Wrapper>);
// without callback
const _page = renderPage();
// with callback
const enhancer: Enhancer<PageProps, {}> = (App) => (props) => (<App />);
const { html, head, errorHtml, chunks, buildManifest } = renderPage(enhancer);
const style = {};
return { ...page, style };
return { html, head, errorHtml, chunks, buildManifest, style };
}
render() {
@@ -33,8 +35,45 @@ export default class MyDocument extends Document {
<body>
<Main />
<NextScript />
{this.props.children}
</body>
</html>
);
}
}
const extendedResults = (
<MyDoc any="property" should="work" here>
<Head some="more" properties>
<meta name="description" content="Head can have children, too!" />
</Head>
<h1>Hey there</h1>
</MyDoc>
);
const renderPage: NextDocumentContext['renderPage'] = (enhancer) => ({
buildManifest: {},
chunks: { names: [], filenames: [] },
html: '',
head: [<React.Fragment />],
errorHtml: '',
});
interface PageInitialProps extends PageProps {
foo: string;
bar: number;
}
interface ProcessedInitialProps {
fooLength: number;
bar: boolean;
}
const enhancerExplicit: Enhancer<PageProps, {}> = (App) => (props) => (<App />);
const enhancerInferred = (App: React.ComponentType<ProcessedInitialProps>) => ({ foo, bar }: PageInitialProps) => (<App fooLength={foo.length} bar={!!bar} />);
const explicitEnhancerRenderResponse = renderPage(enhancerExplicit);
const inferredEnhancerRenderResponse = renderPage(enhancerInferred);
const defaultedTypesRenderResponse = renderPage((App) => (props) => (<App url={props.url} />));
const defaultedTypesExtendedRenderResponse = renderPage((App) => (props) => (<App foo="bar" url={props.url} />));
const explicitTypesRenderResponseOne = renderPage<PageProps, {}>((App) => (props) => (<App />));
const explicitTypesRenderResponseTwo = renderPage<PageInitialProps, ProcessedInitialProps>((App) => ({ foo, bar }) => (<App fooLength={foo.length} bar={!!bar} />));