{"id":25035106,"url":"https://github.com/liinkiing/next-ts-graphql-relay-starter","last_synced_at":"2025-04-30T22:16:21.817Z","repository":{"id":47811465,"uuid":"287232375","full_name":"Liinkiing/next-ts-graphql-relay-starter","owner":"Liinkiing","description":"An opiniated Next powered starter which include support for Relay with GraphQL SSR/SSG support, codegen, styled component / system, framer motion and Cypress","archived":false,"fork":false,"pushed_at":"2021-11-08T01:13:23.000Z","size":3308,"stargazers_count":5,"open_issues_count":11,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-30T22:16:17.118Z","etag":null,"topics":["cypress","framer","graphql","next","react","relay","ssg","ssr","starter","styled-component","styled-system","template","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Liinkiing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-13T09:07:26.000Z","updated_at":"2025-01-31T09:14:20.000Z","dependencies_parsed_at":"2022-08-31T19:02:48.989Z","dependency_job_id":null,"html_url":"https://github.com/Liinkiing/next-ts-graphql-relay-starter","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":"Liinkiing/next-ts-graphql-apollo-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Liinkiing%2Fnext-ts-graphql-relay-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Liinkiing%2Fnext-ts-graphql-relay-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Liinkiing%2Fnext-ts-graphql-relay-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Liinkiing%2Fnext-ts-graphql-relay-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Liinkiing","download_url":"https://codeload.github.com/Liinkiing/next-ts-graphql-relay-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251789627,"owners_count":21644087,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cypress","framer","graphql","next","react","relay","ssg","ssr","starter","styled-component","styled-system","template","typescript"],"created_at":"2025-02-05T23:45:08.708Z","updated_at":"2025-04-30T22:16:21.797Z","avatar_url":"https://github.com/Liinkiing.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Next GraphQL Relay Starter\n\nA starter to bootstrap your **Next** application (nice pun gg) with some noice GraphQL\n(**🎊 With SSR/SSG support 🎊**) with Relay\n\n## Usage\n\n```bash\n$ yarn\n# install dependencies\n\n$ yarn dev\n# launch concurrently relay:watch and dev:next\n\n$ yarn relay\n# launch Relay code generation based on your graphql`` template literals\n\n$ yarn relay:watch\n# same as above, with watch mode\n\n$ yarn dev:next\n# launch Next dev script\n\n$ yarn build\n# launch Next build script\n\n$ yarn start\n# launch Next start script\n\n$ yarn test\n# launch test suite\n\n$ yarn ts:check\n# check TypeScript\n\n$ yarn lint\n# run ESLint\n```\n\n## GraphQL support\n\nThe starter comes by default with Relay. All Relay related code and config is located under `~/relay` folder. It contains a\nrelay environment for the client and the server. The `~/relay/index.ts` file choose the appropriate\nenvironment based on the execution context (server side / client)\nIt uses environment variables to define the API endpoint, so you have to copy/paste the `.env.sample`\nfile and rename it to `.env` (not committed). The variable name is `NEXT_PUBLIC_GRAPHQL_API`\n\nTo make the relay compiler work, you must have a `schema.graphql` at the root (can be\nmodified in the `relay.config.js`, see [the configuration reference](https://relay.dev/docs/en/installation-and-setup#set-up-relay-with-a-single-config-file)).\n\nI have annotated the file with a `/** @type {import('@types/relay-compiler/lib/bin/RelayCompilerMain').Config} */` jsdoc,\nso normally your editor should pick the TypeScript definitions and you should have autocomplete on the configuration file.\n\nBased on this and your graphql template literals in the `src` and `pages` folder, it will auto generate\ncorresponding the corresponding types.\n\n### SSR / SSG\n\nIf you wanna use SSR / SSG, you can use for exemple the `getStaticProps` from Next to load some data\nand inject them in your Relay store. By default, this template assumes that we should pre populate the store in\nthe client side when a prop named `relayRecords` is set, for exemple in getStaticProps. Then, you could for\nexemple use a `QueryRenderer` from Relay, and set the **fetchPolicy** to `store-and-network` so when the client\nmount the application, the store of Relay will be populated (it's done in the `_app.tsx` file) by what you've put here.\nIn the server side / build side, you could use something like this\n\n```typescript jsx\n// pages/index.tsx\nimport { GetStaticProps, NextPage } from 'next'\nimport { QueryRenderer } from 'react-relay'\nimport { fetchQuery, graphql, useRelayEnvironment } from 'relay-hooks'\n// The bottom line imports what Relay compiler generate\nimport { pages_indexQuery } from '~/__generated__/pages_indexQuery.graphql'\nimport { initEnvironment } from '~/relay'\nimport { RelayProps } from '~/@types'\nimport StarWarsList from '~/components/StarWarsList'\n\nconst QUERY = graphql`\n  # The relay compiler forces you to have some particular namings. Next pages\n  # must begin with pages_\u003cyour_module_name\u003e or Relay will throw an error\n\n  query pages_indexQuery {\n    allFilms {\n      ...StarWarsList_films\n    }\n  }\n`\n\nconst Index: NextPage = () =\u003e {\n  const environment = useRelayEnvironment()\n  return (\n    \u003cdiv\u003e\n      \u003cQueryRenderer\u003cpages_indexQuery\u003e\n        variables={{}}\n        fetchPolicy=\"store-and-network\"\n        environment={environment}\n        query={QUERY}\n        render={({ error, props }) =\u003e {\n          if (error) return \u003cdiv\u003e{error.message}\u003c/div\u003e\n          else if (props \u0026\u0026 props.allFilms) return \u003cStarWarsList films={props.allFilms} /\u003e\n          return \u003cdiv\u003eLoading...\u003c/div\u003e\n        }}\n      /\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport const getStaticProps: GetStaticProps\u003cRelayProps\u003e = async () =\u003e {\n  const { environment } = initEnvironment()\n\n  await fetchQuery(environment, QUERY, {}).toPromise()\n\n  // This is what the _app.tsx will use to populate the initial Relay store.\n  // Thanks to this and the \"store-and-network\" policy, when the page will be\n  // mounted on the client-side, Relay will already have the data in it's store\n  // so there will be no loading and it will be prerendered on your page, so\n  // it may be useful if your page have some data requirements / SEO that needs\n  // to be rendered on the server\n  const relayRecords = environment.getStore().getSource().toJSON()\n\n  return {\n    props: {\n      relayRecords,\n    },\n  }\n}\n\nexport default Index\n```\n\nA very small exemple application using this starter with Relay and proper TypeScript\ntypings can be found here: https://github.com/Liinkiing/next-ts-graphql-relay-sample, because it\nmay be hard to guess what types to use, for example when using fragments, or that `QueryRenderer` is a React\ncomponent that accept a generic type, so you can write this in your JSX to have proper\ntypings `\u003cQueryRenderer\u003cpages_indexQuery\u003e\u003e...\u003c/QueryRenderer\u003e`\n\n### Configuration\n\nAll configuration related files are located in the `relay.config.js` file\nA `.graphqlconfig` file is also provided, if you use a GraphQL extension in your IDE, it will allow you\nto introspect the schema of a given endpoint and writing it in a `schema.graphql` file.\nYou must enter your API url here\n\n## Next config\n\nIt comes already configured with some nice plugin. You can see in `next.config.js` what is\nused. In short, it allows support of importing images files and fonts within webpack.\nIt also comes with **NProgress** support, by default so it shows a small loading bar in top of\nthe page when loading. You can find the component in `~/components/NProgress.tsx`, and it is used in the\ncustom `_app.tsx`\n\n## Styled component\n\nThe template comes with [styled-components](https://github.com/styled-components/styled-components).\nAgain, you can either choose to not use it, this is a personal choice.\nYou can also find a `styles` folder, which contains many related\nstyled-components files to keep things organized. It's also includes all themes-related stuff in here.\nIt's again a personal convention that I follow, feel free to annihilate this directory if you want 😢\n\n## Styled system\n\nIt also comes with [styled-system](https://github.com/styled-system/styled-system). It is a great way to\nbuild reusable UI blocks with a great props API and consistent spaces / typography.\nA lot comes from the theme, provided in `~/styles/themes/base.ts` where we define some\nbreakpoints, spacings and typography stuff. It allows then the custom `AppBox` component (`~/ui/AppBox`)\nto be aware of your theme and then build something amazing with the primitives.\nBy default, this starter provides some basic examples components that uses this pattern, for\nexample the `AppNav` component (`~/components/layout/AppNav`).\n\n🔥 It also supports and provides autocomplete for props that takes source from the theme (e.g `bg`, `zIndex`, `border`...). 🔥\n\n**TypeScript \u003e 4.1** is mandatory because I'm using the new [Template Litteral Types](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#template-literal-types) to\nprovide autocompletion of the color prop based of the nested `colors` object, so when using\n`bg` prop for exemple, you should have autocompletion for `red.xxx, blue.xxx` or anything defined in your `colors.ts`.\nIt supports nested elements with a dot notation! (that's why TS 4.1 is required)\n\n## Framer motion\n\nAgain, personal preference here, but the starter comes with framer motion already configured\nto handle Next pages changes and enable some smooth transitions when navigating. You\ncan find the default variant used for the page transitions in `~/common/framer.ts`.\n\n## Testing\n\n[Jest](https://github.com/facebook/jest) and [@testing-library/react](https://github.com/testing-library/react-testing-library) is used to run your tests. It comes preconfigured\nwith [ts-jest](https://github.com/kulshekhar/ts-jest) so your tests also checks your types.\nYou can look the **jest.config.js** and the file **setupTest.ts** to see what's in there.\n[jest-styled-components](https://github.com/styled-components/jest-styled-components) is also used to have deterministic classNames\nwithin your styled components that you are testing.\n[Cypress](https://cypress.io) starter for e2e tests. Take a look at Cypress config file **cypress.json**\n\n### Cypress\n\nThis starter comes by default with [Cypress](https://cypress.io) and some sensible defaults and a custom plugin which enable you to\ninject your .env\\* files in the Cypress.env helper. It also add support for a per-environment configuration file.\nJust add a cypress.\u003cenv\u003e.json. It uses by default the `cypress.json` and then extend the configuration if you have\na `cypress.\u003cenv\u003e.json`. Take a look at the various configuration file in the `cypress` folder and the custom plugin in `cypress/plugins/index.ts`.\nThis folder is independant and lives by itself, so it has his own dependencies / scripts / tsconfig and do not pollute the\nglobal namespace. [See why an isolated folder](https://basarat.gitbook.io/typescript/intro-1/cypress#tip-creating-page-objects)\n\nIt also have an opiniated way of interacting with some of your webpages in Cypress. As your application\nwill grow (and pages would become complex), it's recommended to have some sort of \"Page objects\" which allows\nyou to work in a more conveniant way for some complex page. See more here https://basarat.gitbook.io/typescript/intro-1/cypress#tip-creating-page-objects.\n\nIt also comes with two custom commands (`cypress/support/commands.ts`) that are autocompleted (see `cypress/@types/index.d.ts`)\n\n```typescript\ncy.server() // start mocking the calls made to the server, needed to mock later the queries\ncy.mockGraphQL() // in your test, allow to start intercepting requests made to your /graphql/ endpoint\ncy.mockGraphQLOperation('ViewerQuery') // internally alias the request, so you can do later in your test cy.wait\n// your test ...\ncy.wait('@ViewerQuery') // waits for the graphql operation to succeed\n```\n\n## Aliases\n\nIt includes by default support for aliases in `tsconfig.json`.\nThey are 1 defaulted alias, ready to use :\n\n```typescript\n// ~ refers to src folder\nimport { something } from '~/file'\n```\n\nYou can also use for your convenience the global `__DEV__` variable, which is\ninjected by webpack with the DefinePlugin (see **next.config.js**).\n\n## @types and extending modules\n\nIt also includes a `@types` directory under **src**, so you can easily\nseparate your types or extends some external modules. They are also included in the `tsconfig.json`\nFor example, if some package named `foo` does not have any types in [DefinitelyTyped](https://definitelytyped.org/), you could\nadd a `index.d.ts` under `src/@types/foo/index.d.ts`. It is just my personal convention, so do as you want!\n\n```typescript\n// src/@types/foo/index.d.ts\n\n// to make sure Typescript get the original types from the module (if any)\nimport * as foo from 'foo'\n\ndeclare module 'foo' {\n  declare function foo(bar: string): boolean\n}\n```\n\nBecause the `@types` directory is declared in `typeRoots`, Typescript will no longer complain if you imported your package with missing types\n\n## Tooling\n\nThe template includes [Prettier](https://prettier.io/), [ESLint](https://eslint.org/) (with [Typescript-eslint](https://github.com/typescript-eslint/typescript-eslint)), [Babel](https://babeljs.io/) and [lint-staged](https://github.com/okonet/lint-staged).\nAll their related configurations are in the `*rc` files (except for lint-staged, which is located in the `package.json`).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliinkiing%2Fnext-ts-graphql-relay-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliinkiing%2Fnext-ts-graphql-relay-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliinkiing%2Fnext-ts-graphql-relay-starter/lists"}