From 3feb1c0bc4e2c847ccb173cb62a852e81b18b6a1 Mon Sep 17 00:00:00 2001 From: Dhenain Ambroise Date: Thu, 21 May 2020 14:32:45 +0200 Subject: [PATCH] Add css-in-js examples --- src/components/doc/BuiltInFeaturesSection.tsx | 23 +++ src/components/doc/NativeFeaturesSection.tsx | 9 +- src/pages/[locale]/examples/css-in-js.tsx | 148 ++++++++++++++++++ src/pages/[locale]/examples/graphql.tsx | 24 +-- src/pages/[locale]/examples/static-i18n.tsx | 5 +- 5 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 src/pages/[locale]/examples/css-in-js.tsx diff --git a/src/components/doc/BuiltInFeaturesSection.tsx b/src/components/doc/BuiltInFeaturesSection.tsx index 96025cebe..24cb51363 100644 --- a/src/components/doc/BuiltInFeaturesSection.tsx +++ b/src/components/doc/BuiltInFeaturesSection.tsx @@ -29,6 +29,9 @@ const BuiltInFeaturesSection: React.FunctionComponent = (props): JSX.Elem + + + @@ -46,6 +49,9 @@ const BuiltInFeaturesSection: React.FunctionComponent = (props): JSX.Elem + + + @@ -73,6 +79,23 @@ const BuiltInFeaturesSection: React.FunctionComponent = (props): JSX.Elem + + + +

CSS-in-JS

+ “Styling components with Emotion” + +
+ + + + + + +
+
+
+
); diff --git a/src/components/doc/NativeFeaturesSection.tsx b/src/components/doc/NativeFeaturesSection.tsx index 468d20e16..89e09d3aa 100644 --- a/src/components/doc/NativeFeaturesSection.tsx +++ b/src/components/doc/NativeFeaturesSection.tsx @@ -83,21 +83,18 @@ const NativeFeaturesSection: React.FunctionComponent = (props): JSX.Eleme >
  • Static app (without any option) + {' - '}
  • Using fallback (on-the-fly static builds) + {' - '}
  • Using revalidate (incremental static regeneration) + {' - '}
  • - -
    - - - -
    diff --git a/src/pages/[locale]/examples/css-in-js.tsx b/src/pages/[locale]/examples/css-in-js.tsx new file mode 100644 index 000000000..e679db888 --- /dev/null +++ b/src/pages/[locale]/examples/css-in-js.tsx @@ -0,0 +1,148 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import { createLogger } from '@unly/utils-simple-logger'; +import { GetStaticPaths, GetStaticProps, NextPage } from 'next'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars +import React from 'react'; +import { Alert } from 'reactstrap'; +import DocPage from '../../../components/doc/DocPage'; +import DefaultLayout from '../../../components/pageLayouts/DefaultLayout'; +import Code from '../../../components/utils/Code'; +import ExternalLink from '../../../components/utils/ExternalLink'; +import withApollo from '../../../hocs/withApollo'; +import { StaticParams } from '../../../types/nextjs/StaticParams'; +import { OnlyBrowserPageProps } from '../../../types/pageProps/OnlyBrowserPageProps'; +import { SSGPageProps } from '../../../types/pageProps/SSGPageProps'; +import { getCommonStaticPaths, getCommonStaticProps } from '../../../utils/nextjs/SSG'; + +const fileLabel = 'pages/[locale]/docs/css-in-js'; +const logger = createLogger({ // eslint-disable-line no-unused-vars,@typescript-eslint/no-unused-vars + label: fileLabel, +}); + +/** + * Only executed on the server side at build time. + * + * Note that when a page uses "getStaticProps", then "_app:getInitialProps" is executed (if defined) but not actually used by the page, + * only the results from getStaticProps are actually injected into the page (as "SSGPageProps"). + * + * @return Props (as "SSGPageProps") that will be passed to the Page component, as props + * + * @see https://github.com/zeit/next.js/discussions/10949#discussioncomment-6884 + * @see https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation + */ +export const getStaticProps: GetStaticProps = getCommonStaticProps; + +/** + * Only executed on the server side at build time + * Necessary when a page has dynamic routes and uses "getStaticProps" + */ +export const getStaticPaths: GetStaticPaths = getCommonStaticPaths; + +/** + * SSG pages are first rendered by the server (during static bundling) + * Then, they're rendered by the client, and gain additional props (defined in OnlyBrowserPageProps) + * Because this last case is the most common (server bundle only happens during development stage), we consider it a default + * To represent this behaviour, we use the native Partial TS keyword to make all OnlyBrowserPageProps optional + * + * Beware props in OnlyBrowserPageProps are not available on the server + */ +type Props = {} & SSGPageProps>; + +const StaticI18n: NextPage = (props): JSX.Element => { + return ( + + +

    CSS-in-JS using Emotion library

    + + + Emotion allows to use both the styled component and JSX-like ways of writing your CSS styles.
    +
    + A lot of research has been done to select the most robust css-in-js library, and we eventually chose + Emotion.
    + After more than a year working with it at a production-grade level, we haven't noticed any drawbacks. +
    + + + Our personal preference is to use JSX-like way of writing styles, instead of the Styled Components approach.
    + We want to make it clear that such choice is personal, and we have selected on purpose Emotion, because it allows both.
    + In our opinion, the JSX way is better for iterating quickly when you don't know exactly the shape of your components.
    + The choice is yours, do as you like! +
    + +

    + The below example uses the JSX way, with CSS written directly in the element. +

    + + + Top-level content + +

    Child content

    + + `} + /> + +
    + +

    + The below example uses the Styled Component way, with CSS written in a dedicated React Component. +

    + + { + const { onClick } = props; + return ( + + +
    +
    + ); +}; + +export default withApollo()(StaticI18n); diff --git a/src/pages/[locale]/examples/graphql.tsx b/src/pages/[locale]/examples/graphql.tsx index a768096ed..8a7ca04dd 100644 --- a/src/pages/[locale]/examples/graphql.tsx +++ b/src/pages/[locale]/examples/graphql.tsx @@ -62,9 +62,12 @@ const StaticI18n: NextPage = (props): JSX.Element => { Fetching APIs works slightly differently depending on whether you use SSG or SSR.
    +
    When you're using SSG, all queries are executed from the server side, during build generation, on your computer or your CI server.
    - When using SSR, queries are executed on the fly, from the client or from the server depending on how the page is served (CSR vs SSR). - Therefore, you need to be careful about tokens and other credentials you might use. And you also need to consider performances (e.g: running all queries at once)
    + When using SSR, queries are executed on the fly, from the client or from the server depending on how the page is served (CSR vs SSR).
    +
    + Therefore, you need to be careful about tokens and other credentials you might use. + And you also need to consider performances (e.g: running all queries at once)

    The below examples will focus on SSG, because that's what we recommend to use. But know that you may use both.
    Also, you might want to run GraphQL queries from the browser even when using SSG, it's also possible but we don't provide such example at this time. @@ -79,9 +82,11 @@ const StaticI18n: NextPage = (props): JSX.Element => { displayName: 'LAYOUT_QUERY', // Naming queries makes debugging easier query: LAYOUT_QUERY, // This is our actual GQL query (see /gql folder) variables, - context: { + context: { // Per-request context override/overload headers: { - 'gcms-locale': gcmsLocales, // This is how we handle "Dynamic i18n", by only fetching content for this language + // This is how we handle "Dynamic i18n", by only fetching content for one language + // With languages fallback if content isn't available (e.g: ['FR', 'DE', 'EN'] + 'gcms-locale': gcmsLocales, }, }, }; @@ -120,21 +125,22 @@ const StaticI18n: NextPage = (props): JSX.Element => { export const LAYOUT_QUERY = gql\` query LAYOUT_QUERY($customerRef: String!){ customer(where: { - ref: $customerRef, - }){ + ref: $customerRef, // Use the variables that were provided to the GQL query + }){ // Fields that are being fetched id label theme { - ...themeFields + ...themeFields // This uses a GQL fragment (code reusability) } } } - \${theme.themeFields} + \${theme.themeFields} // Fragment(s) import \`; `} /> +

    - Note that it uses the theme.themeFields fragment. + All our pages fetch some data from GraphCMS, because we need those in shared components (i.e: Footer, Nav)

    diff --git a/src/pages/[locale]/examples/static-i18n.tsx b/src/pages/[locale]/examples/static-i18n.tsx index d05427813..959a792ed 100644 --- a/src/pages/[locale]/examples/static-i18n.tsx +++ b/src/pages/[locale]/examples/static-i18n.tsx @@ -88,9 +88,8 @@ const StaticI18n: NextPage = (props): JSX.Element => { react-i18next package: What we actually use in NRN, mostly throught the t and Trans component.
  • - Locize vendor packages (paid): Vendor meant to help with static content localisation. Read our "How to use" and learn more about what benefits it brings + Locize vendor packages (paid): Vendor meant to help with static content localisation. + Read our "How to use" and learn more about what benefits it brings