{"id":25553585,"url":"https://github.com/jeff-li/nextjs-spa","last_synced_at":"2026-04-11T05:35:11.771Z","repository":{"id":45951871,"uuid":"429584926","full_name":"jeff-li/nextjs-spa","owner":"jeff-li","description":"A starting point for your next Single Page App with Next.js","archived":false,"fork":false,"pushed_at":"2021-12-21T04:45:05.000Z","size":374,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-31T03:42:26.886Z","etag":null,"topics":["jest","nextjs","react","react-router","spa","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeff-li.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-18T21:28:46.000Z","updated_at":"2022-05-27T02:40:11.000Z","dependencies_parsed_at":"2022-09-23T09:10:30.918Z","dependency_job_id":null,"html_url":"https://github.com/jeff-li/nextjs-spa","commit_stats":null,"previous_names":[],"tags_count":2,"template":true,"template_full_name":null,"purl":"pkg:github/jeff-li/nextjs-spa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeff-li%2Fnextjs-spa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeff-li%2Fnextjs-spa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeff-li%2Fnextjs-spa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeff-li%2Fnextjs-spa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeff-li","download_url":"https://codeload.github.com/jeff-li/nextjs-spa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeff-li%2Fnextjs-spa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273073267,"owners_count":25040690,"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","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["jest","nextjs","react","react-router","spa","template","typescript"],"created_at":"2025-02-20T12:01:02.445Z","updated_at":"2025-12-30T21:33:39.017Z","avatar_url":"https://github.com/jeff-li.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eNext.js SPA\u003c/h1\u003e\n\u003cdiv align=\"center\"\u003e\n\nA starting point for your next Single Page App with [Next.js](https://nextjs.org/)\n\n[![MIT](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](http://opensource.org/licenses/MIT)\n[![codecov](https://codecov.io/gh/jeff-li/nextjs-spa-runway/branch/master/graph/badge.svg?token=qQds3epbPj)](https://codecov.io/gh/jeff-li/nextjs-spa)\n[![Node Unit Tests](https://github.com/jeff-li/nextjs-spa-runway/actions/workflows/unit_test.yml/badge.svg)](https://github.com/jeff-li/nextjs-spa-runway/actions/workflows/unit_test.yml)\n\n\u003c/div\u003e\n\nThis project is a template for creating SPAs or \"Hybrid SPAs\". It uses the popular React Router for client-side routing, as we as utilizes Next's built-in router for both [Static Generation](https://nextjs.org/docs/basic-features/pages#static-generation-recommended) and  [Server-side Rendering](https://nextjs.org/docs/basic-features/pages#server-side-rendering).\n\n\nThe project was originally bootstrapped by [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). So all modifications should work for your typical Next.js app after v9.5.\n\n\n## Features\n\n✅  [ESLint ](https://eslint.org/)  \n✅  [Prettier](https://prettier.io/)  \n✅  Type and ESlint checking in development with [fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin)  \n✅  [Typescript](https://www.typescriptlang.org/)  \n✅  [React Router v6](https://reactrouter.com/) for client-side routing  \n✅  [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) for testing (transforming with [ts-jest](https://kulshekhar.github.io/ts-jest/))  \n✅  [SWC](https://swc.rs/) for faster code transformation and minification  \n\nPlease feel free to remove features that's not needed in your project.\n\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\nyarn dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\n## Type and ESlint Checking in Development\nNext.js disabled type checking for development after version 9.3.6 in order to improve performance and dev experience. However some people still prefer having this feature enabled for their development process, so that they can discover issues sooner and fix them without running `npm run build` repeatedly.\n\nThis project uses a custom webpack configuration to run both type and Eslint checking during development. However, it increases development rebuild times significantly. If you prefer, you can easily remove this configuration in `next.config.js` and uninstall `fork-ts-checker-webpack-plugin`. \n```js\nif(!isServer) {\n    // eslint-disable-next-line @typescript-eslint/no-var-requires\n    const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');\n    config.plugins.push(new ForkTsCheckerWebpackPlugin({\n        eslint: {\n            files: './src/**/*.{ts,tsx,js,jsx}'\n        }\n    }))\n}\n```\n\nAlternative you can run also run typescript compiler separately instead to achieve the same goal without installing another dependency\n```json\n{\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"dev:ts\": \"npm run dev \u0026 npm run ts:watch\",\n    \"ts\": \"tsc --noEmit --incremental\",\n    \"ts:watch\": \"npm run ts --watch\"\n  },\n}\n```\n\n## Type Checking in Testing\nThis project uses `ts-jest` in `transform` to compile typescript files because `babel-jest` is purely transpilation and does not type-check results. You can remove all ts-jest related configurations if you prefer `babel-jest`,\n\n\n## Fix Build Errors by Using `.page.tsx` [Custom Page Extensions](https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions)\nNext.js suggests following Jests convention of adding tests to the `__tests__` folder in the root directory. This project however places test files next to their related code. `next build` does not filter out `.test.tsx` files automatically and will raise errors, because the build process recognizes them as a React components and tries to compile them with other `.tsx` files. So the work-around is adding custom page extension `.page.tsx` to actual React components, it will tell `next` to ignore other non-page files.\n\n### Alternative Solution\nIf you want to have a `__tests__` folder for each page folder, you can add the following config to your `next.config.js`\n```js\nconfig.plugins.push(\n  new webpack.IgnorePlugin({\n    resourceRegExp: /.*/,\n    contextRegExp: /__tests__/,\n  })\n);\n```\n\n## Customization For SPA\n1. Add `typeof window === 'undefined'` in `pages/_app.page.tsx` to make sure `window` is defined before rendering the app (essentially avoid rendering on the server).\n2. Use built-in attribute `suppressHydrationWarning` to remove the warning from mis-matching \"re-hydration\"\n\nexample:\n ```js\n import { AppProps } from 'next/app'\n\nconst MyApp = ({ Component, pageProps }: AppProps): React.ReactElement =\u003e (\n  \u003cdiv suppressHydrationWarning\u003e\n    {typeof window === 'undefined' ? null : \u003cComponent {...pageProps} /\u003e}\n  \u003c/div\u003e\n)\n\nexport default App\n ```\n3. Add `rewrites` in `next.config.js` to redirect all routes to `'/'` so that it can be handled by React Router.\n```js\nmodule.exports = {\n  async rewrites() {\n    return [{\n      source: '/:any*',\n      destination: '/',\n    }];\n  },\n};\n```\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `npm run build`\n\nBuilds the application for production usage\u003cbr /\u003e\n\n### `npm start`\n\nStarts a Next.js production server\u003cbr /\u003e\n\n### `npm run lint`\n\nSets up Next.js' built-in ESLint configuration\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeff-li%2Fnextjs-spa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeff-li%2Fnextjs-spa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeff-li%2Fnextjs-spa/lists"}