From 067f1657349c889bfa6a93750dc1fc7897b48464 Mon Sep 17 00:00:00 2001 From: james hadfield Date: Thu, 11 Apr 2024 12:44:30 +1200 Subject: [PATCH 1/6] WIP ssr for /team page The page will be generated using Next.js SSR (only compiled once, at build time, not when the server is running despite the first _S_ in SSR standing for Server. At least, that's my understanding, but I need to confirm this.) Notice that _without_ JS (i.e. the HTML that's delivered to the browser) the layout is completely wrong. With JS enabled you'll get a flash as the browser hydrates and client side rendering updates the DOM to use the correct layout. The layout difference is due to the styled components styles not being included in CSS. --- static-site/pages/team.jsx | 75 ++++++++++++++++++++++++++++++++-- static-site/src/pages/team.jsx | 66 ------------------------------ 2 files changed, 72 insertions(+), 69 deletions(-) delete mode 100644 static-site/src/pages/team.jsx diff --git a/static-site/pages/team.jsx b/static-site/pages/team.jsx index f09bcde6f..7f7f83533 100644 --- a/static-site/pages/team.jsx +++ b/static-site/pages/team.jsx @@ -1,3 +1,72 @@ -import dynamic from 'next/dynamic' -const Index = dynamic(() => import("../src/pages/team"), {ssr: false}) -export default Index; + +/** + * + * Example of a typical/simple (?) page for Next.js (pages), i.e. no dynamic imports. + */ + +import React from "react"; +import styled from "styled-components"; +import GenericPage from "../src/layouts/generic-page"; +import { BigSpacer, FlexCenter} from "../src/layouts/generalComponents"; +import { CenteredFocusParagraph } from "../src/components/splash/styles"; +import { ListOfPeople } from "../src/components/People/avatars"; + +const H1 = styled.div` + text-align: center; + font-size: 32px; + line-height: 32px; + font-weight: 300; + color: ${(props) => props.theme.darkGrey}; + min-width: 240px; + margin-top: 0px; + margin-bottom: 20px; +`; + +const TeamPage = () => { + console.log(""); + return ( +
+

Nextstrain core team

+ + + + {"Nextstrain was co-founded by:"} + + + + + + + + {"The core team currently working on Nextstrain are:"} + + + + + +

Nextstrain Alumni

+ + + {`Our previous core Nextstrain team members, some of whom are still working on projects involving Nextstrain and/or maintaining specific analyses. `} + {"Beyond the core team there have been many code contributions from the wider scientific and programming community; please see "} + our GitHub organization + {" to see the history of (code) contributions."} + + + + + + +
+ ); +}; + + +const Team = props => ( + + + +); + +export default Team; + diff --git a/static-site/src/pages/team.jsx b/static-site/src/pages/team.jsx deleted file mode 100644 index fc3263cff..000000000 --- a/static-site/src/pages/team.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import GenericPage from "../layouts/generic-page"; -import { BigSpacer, FlexCenter} from "../layouts/generalComponents"; -import { CenteredFocusParagraph } from "../components/splash/styles"; -import { ListOfPeople } from "../components/People/avatars"; - -const H1 = styled.div` - text-align: center; - font-size: 32px; - line-height: 32px; - font-weight: 300; - color: ${(props) => props.theme.darkGrey}; - min-width: 240px; - margin-top: 0px; - margin-bottom: 20px; -`; - -const TeamPage = () => { - console.log(""); - return ( -
-

Nextstrain core team

- - - - {"Nextstrain was co-founded by:"} - - - - - - - - {"The core team currently working on Nextstrain are:"} - - - - - -

Nextstrain Alumni

- - - {`Our previous core Nextstrain team members, some of whom are still working on projects involving Nextstrain and/or maintaining specific analyses. `} - {"Beyond the core team there have been many code contributions from the wider scientific and programming community; please see "} - our GitHub organization - {" to see the history of (code) contributions."} - - - - - - -
- ); -}; - - -const Team = props => ( - - - -); - -export default Team; - From 9c30ac10698efd1e9c9eff8f6ba6c844e9978caf Mon Sep 17 00:00:00 2001 From: james hadfield Date: Thu, 11 Apr 2024 12:45:38 +1200 Subject: [PATCH 2/6] WIP fix styled-components for ssr --- static-site/pages/_document.tsx | 64 ++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/static-site/pages/_document.tsx b/static-site/pages/_document.tsx index b2fff8b42..cf291202d 100644 --- a/static-site/pages/_document.tsx +++ b/static-site/pages/_document.tsx @@ -1,13 +1,53 @@ -import { Html, Head, Main, NextScript } from "next/document"; - -export default function Document() { - return ( - - - -
- - - - ); +/** + * Page copied from https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_document.tsx + * with modifications. See also + * + */ + +import type { DocumentContext, DocumentInitialProps } from "next/document"; +import Document from "next/document"; +import { ServerStyleSheet } from "styled-components"; +import { Html, Head, Main, NextScript} from "next/document"; + +export default class MyDocument extends Document { + static async getInitialProps( + ctx: DocumentContext, + ): Promise { + const sheet = new ServerStyleSheet(); + const originalRenderPage = ctx.renderPage; + + try { + // Run the React rendering logic synchronously + ctx.renderPage = () => + originalRenderPage({ + // Useful for wrapping the whole react tree + enhanceApp: (App) => (props) => + sheet.collectStyles(), + }); + + // Run the parent `getInitialProps`, it now includes the custom `renderPage` + const initialProps = await Document.getInitialProps(ctx); + return { + ...initialProps, + styles: [initialProps.styles, sheet.getStyleElement()], + }; + } finally { + sheet.seal(); + } + } + + /** The following was our previous _document rendering, which I presume is identical from that within the parent `Document` class, + * as we can leave it out and the result seems the same. TO CHECK. + */ + render() { + return ( + + + +
+ + + + ); + } } From 81062166712258c99e5ea7dfd9ff4ea8a2fd7c0c Mon Sep 17 00:00:00 2001 From: james hadfield Date: Thu, 11 Apr 2024 12:46:31 +1200 Subject: [PATCH 3/6] WIP enable ssr for /pathogens and / the unhydrated site looks pretty good but there are hydration errors raised by next.js (only in dev mode) --- static-site/pages/index.jsx | 7 ++++++- static-site/pages/pathogens.jsx | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/static-site/pages/index.jsx b/static-site/pages/index.jsx index e1cb091c9..989e78cc4 100644 --- a/static-site/pages/index.jsx +++ b/static-site/pages/index.jsx @@ -1,3 +1,8 @@ +/** + * + * Example of dynamic import but using ssr (which is the default dynamic import!) + */ + import dynamic from 'next/dynamic' -const Index = dynamic(() => import("../src/pages/index"), {ssr: false}) +const Index = dynamic(() => import("../src/pages/index"), {ssr: true}) export default Index; diff --git a/static-site/pages/pathogens.jsx b/static-site/pages/pathogens.jsx index ee657ee5a..2633f7a5c 100644 --- a/static-site/pages/pathogens.jsx +++ b/static-site/pages/pathogens.jsx @@ -1,3 +1,8 @@ +/** + * + * Example of dynamic import but using ssr (which is the default dynamic import!) + */ + import dynamic from 'next/dynamic' -const Index = dynamic(() => import("../src/sections/pathogens"), {ssr: false}) +const Index = dynamic(() => import("../src/sections/pathogens"), {ssr: true}) export default Index; From 3cfb23925b82cbfba0899bf899d5b1f4b8aed730 Mon Sep 17 00:00:00 2001 From: james hadfield Date: Thu, 11 Apr 2024 13:05:36 +1200 Subject: [PATCH 4/6] Fix hydration errors The underlying hydration errors are caused by different code paths on the client vs server, namely using a conditional querying `window`. --- static-site/pages/team.jsx | 2 +- static-site/src/components/Footer/index.jsx | 3 ++- static-site/src/layouts/generic-page.jsx | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/static-site/pages/team.jsx b/static-site/pages/team.jsx index 7f7f83533..a69e7b7ae 100644 --- a/static-site/pages/team.jsx +++ b/static-site/pages/team.jsx @@ -63,7 +63,7 @@ const TeamPage = () => { const Team = props => ( - + ); diff --git a/static-site/src/components/Footer/index.jsx b/static-site/src/components/Footer/index.jsx index 69b7178f6..2a2a12301 100644 --- a/static-site/src/components/Footer/index.jsx +++ b/static-site/src/components/Footer/index.jsx @@ -53,6 +53,7 @@ const SplashImagesCredit = () => ( class Footer extends React.Component { render() { + const showTeamAvatars = this.props.showTeamAvatars!==false; // same as a functional component with default of true return (
@@ -62,7 +63,7 @@ class Footer extends React.Component { {"Hadfield "}{"et al., "} Nextstrain: real-time tracking of pathogen evolution , Bioinformatics (2018) - {(typeof window !== 'undefined' && window.location.pathname.replace(/\//g, "")!=="team") && ( + {showTeamAvatars && ( <>
The core Nextstrain team is diff --git a/static-site/src/layouts/generic-page.jsx b/static-site/src/layouts/generic-page.jsx index 3cd8a44e0..11865df67 100644 --- a/static-site/src/layouts/generic-page.jsx +++ b/static-site/src/layouts/generic-page.jsx @@ -7,7 +7,7 @@ import UserDataWrapper from "../layouts/userDataWrapper"; import { BigSpacer, HugeSpacer, Line } from "../layouts/generalComponents"; import * as splashStyles from "../components/splash/styles"; -const GenericPage = ({location, children, banner}) => ( +const GenericPage = ({location, children, banner, footerProps}) => (
@@ -19,7 +19,7 @@ const GenericPage = ({location, children, banner}) => ( {children} -