Skip to content

Latest commit

 

History

History
273 lines (214 loc) · 6.95 KB

setup.md

File metadata and controls

273 lines (214 loc) · 6.95 KB
  1. install nvm if not done yet
  2. use latest node version
    nvm use node || nvm install node
  1. create nextjs app in the parent folder

    npx create-next-app@latest --typescript <project-name>
    # or
    pnpm create next-app -- --typescript <project-name>
  1. pin nodejs version in the project

    node -v > .nvmrc
  2. remove the package.json and node_modules/

    rm package.json
    rm -rf node_modules
  3. install pnpm globally

    npm i -g pnpm
  4. install dependencies

    pnpm install
  1. remove .eslintrc.json

    rm .eslintrc.json
  2. install prettier

    pnpm i -D prettier eslint-config-prettier eslint-plugin-prettier
  3. add .eslintrc.js

    /** @type {import('eslint').Linter.Config} */
    module.exports = {
        extends: ['next', 'prettier', 'plugin:prettier/recommended'],
    };
  4. add .prettierrc.js

    /** @type {import('prettier').Config} */
    module.exports = {
        tabWidth: 2,
        overrides: [
            {
                files: '*.md',
                options: {
                    tabWidth: 4,
                },
            },
        ],
        semi: true,
        singleQuote: true,
        printWidth: 80,
        trailingComma: 'es5',
    };
  1. install jest and react-testing-library

    pnpm i -D jest @jest/types @testing-library/react @testing-library/jest-dom
  2. add __tests__/ folder

    mkdir -p __tests__
  3. add __tests__/jest.config.js

    const nextJest = require('next/jest');
    
    const createJestConfig = nextJest({
        dir: './',
    });
    
    /** @type {import('@jest/types').Config.InitialOptions} */
    const customJestConfig = {
        rootDir: '../',
        setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
        moduleDirectories: ['node_modules', '<rootDir>/'],
        testRegex: '__tests__/.*\\.test\\.tsx?$',
        testEnvironment: 'jest-environment-jsdom',
    };
    
    module.exports = createJestConfig(customJestConfig);
  4. add __tests__/jest.setup.ts

    import '@testing-library/jest-dom/extend-expect';
  5. add to package.json

    {
        "scripts": {
            "test": "jest --config ./__tests__/jest.config.js",
            "test:watch": "jest --config ./__tests__/jest.config.js --watch"
        }
    }
  1. install urql and nextjs bindings

    pnpm i urql graphql next-urql react-is @urql/core @urql/exchange-graphcache
    pnpm i -D @urql/devtools
  2. add lib/urql/getUrqlClientOptions.ts

    import { devtoolsExchange } from '@urql/devtools';
    import { cacheExchange } from '@urql/exchange-graphcache';
    import { NextUrqlClientConfig } from 'next-urql';
    import { debugExchange, dedupExchange, fetchExchange } from 'urql';
    import getIsClient from 'lib/utils/getIsClient';
    
    const getUrqlClientOptions: NextUrqlClientConfig = (ssrCache) => {
        const isClient = typeof window !== 'undefined';
        const isProd = process.env.NEXT_PUBLIC_ENV === 'production';
        return {
            url: process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || '',
            exchanges: [
                ...(isClient && !isProd
                    ? [devtoolsExchange, debugExchange]
                    : []),
                dedupExchange,
                cacheExchange({}),
                ssrCache, // ssrExchange has to come before fetchExchange
                fetchExchange,
            ],
        };
    };
    
    export default getUrqlClientOptions;
  3. add graphql query, i.e. graphql/query/userQuery.ts

    export const USER_QUERY = `
        query {
            post(id: 1) {
                id
                title
                body
            }
        }
    `;
  4. instantiate graphql client in one of the getStaticProps or getServerSideProps methods

    import type { GetStaticProps } from 'next';
    import getUrqlClientOptions from 'lib/urql/getUrqlClientOptions';
    import { initUrqlClient } from 'next-urql';
    import { USER_QUERY } from 'graphql/query/userQuery';
    import { ssrExchange } from 'urql';
    import { WithUrqlState } from 'next-urql';
    
    export interface PageProps {}
    
    export interface StaticProps extends WithUrqlState, PageProps {}
    
    export const getStaticProps: GetStaticProps<StaticProps> = async () => {
        const ssrCache = ssrExchange({ isClient: false });
        const urqlClientOption = getUrqlClientOptions(ssrCache);
        const client = initUrqlClient(urqlClientOption, false);
    
        await client?.query(USER_QUERY).toPromise();
    
        return {
            props: {
                urqlState: ssrCache.extractData(),
            },
            revalidate: 600,
        };
    };
  5. add lib/urql/withStaticUrqlClient.ts to wrap static generated pages

    import { withUrqlClient } from 'next-urql';
    import getUrqlClientOptions from './getUrqlClientOptions';
    
    const withStaticUrqlClient = withUrqlClient(getUrqlClientOptions, {
        neverSuspend: true, // don't use Suspense on server side
        ssr: false, // don't generate getInitialProps for the page
        staleWhileRevalidate: true, // tell client to do network-only data fetching again if the cached data is outdated
    });
    
    export default withStaticUrqlClient;
  6. wrap the page with withStaticUrqlClient

    import withStaticUrqlClient from 'lib/urql/withStaticUrqlClient';
    
    // ...
    
    export default withStaticUrqlClient(Page);
  1. install graphql codegen dependencies

    pnpm i @graphql-typed-document-node/core
    pnpm i -D @graphql-codegen/cli @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-operations
  2. add lib/graphql-codegen/codegen.yml

    schema: <html-to-graphql-endpoint-or-path-to-server-graphql>
    documents: './graphql/**/*.graphql' # custom frontend query or mutation defined in graphql
    generates:
        ./graphql/generated.ts:
            plugins:
                - typescript
                - typescript-operations
                - typed-document-node
            config:
                fetcher: fetch
  3. add to package.json

    {
        "scripts": {
            "codegen": "graphql-codegen --config lib/grpahql-codegen/codegen.yml"
        }
    }