├── .eslintrc.cjs ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc.cjs ├── LICENSE ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── src ├── App.test.tsx ├── App.tsx ├── index.css ├── main.tsx ├── pages │ ├── Home.tsx │ └── NotFound.tsx ├── setupTests.ts └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint").Linter.Config } */ 2 | module.exports = { 3 | env: { 4 | browser: true, 5 | es2021: true, 6 | }, 7 | extends: [ 8 | 'airbnb', 9 | 'airbnb-typescript', 10 | 'airbnb/hooks', 11 | 'plugin:react/recommended', 12 | 'plugin:@typescript-eslint/recommended', 13 | 'plugin:prettier/recommended', 14 | ], 15 | overrides: [], 16 | parser: '@typescript-eslint/parser', 17 | parserOptions: { 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | project: ['./tsconfig.json', './tsconfig.node.json'], 21 | }, 22 | plugins: ['react', '@typescript-eslint', 'prettier'], 23 | rules: { 24 | 'react/react-in-jsx-scope': 0, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: CodingGarden 2 | patreon: CodingGarden 3 | custom: ['https://streamlabs.com/codinggarden/tip', 'https://twitch.tv/products/codinggarden', 'https://www.youtube.com/codinggarden/join'] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("prettier").Config } */ 2 | module.exports = { 3 | trailingComma: "es5", 4 | tabWidth: 2, 5 | semi: true, 6 | singleQuote: true, 7 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License Copyright (c) 2022 Coding Garden 2 | 3 | Permission is hereby granted, free 4 | of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, modify, merge, 7 | publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to the 9 | following conditions: 10 | 11 | The above copyright notice and this permission notice 12 | (including the next paragraph) shall be included in all copies or substantial 13 | portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 18 | EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [vite](https://vitejs.dev/) + [React](https://reactjs.org/) + [TypeScript](https://www.typescriptlang.org/) Starter 2 | 3 | This setup includes: 4 | * [vite](https://vitejs.dev/) 5 | * [eslint](https://eslint.org/), [typescript-eslint](https://typescript-eslint.io/), [eslint-airbnb-config](https://github.com/airbnb/javascript), [prettier](https://prettier.io/) 6 | * [vitest](https://vitest.dev/), [jsdom](https://github.com/jsdom/jsdom), [@testing-library](https://testing-library.com/) 7 | * [react-router v6](https://reactrouter.com/en/main) 8 | 9 | # References 10 | 11 | * https://markus.oberlehner.net/blog/using-testing-library-jest-dom-with-vitest/ 12 | * https://testing-library.com/docs/queries/about#priority 13 | * https://kentcdodds.com/blog/common-mistakes-with-react-testing-library -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite + React + TS 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ts-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "test": "vitest", 11 | "lint": "eslint --ext .js,.cjs,.ts,.tsx .", 12 | "lint:fix": "eslint --ext .js,.cjs,.ts,.tsx . --fix", 13 | "typecheck": "tsc --noEmit" 14 | }, 15 | "dependencies": { 16 | "react": "^18.3.1", 17 | "react-dom": "^18.3.1", 18 | "react-router-dom": "^6.26.2" 19 | }, 20 | "devDependencies": { 21 | "@testing-library/jest-dom": "^6.5.0", 22 | "@testing-library/react": "^16.0.1", 23 | "@types/react": "^18.3.11", 24 | "@types/react-dom": "^18.3.0", 25 | "@typescript-eslint/eslint-plugin": "^7.14.1", 26 | "@typescript-eslint/parser": "^7.14.1", 27 | "@vitejs/plugin-react": "^4.3.2", 28 | "eslint": "^8.54.0", 29 | "eslint-config-airbnb": "^19.0.4", 30 | "eslint-config-airbnb-typescript": "^18.0.0", 31 | "eslint-config-prettier": "^9.1.0", 32 | "eslint-plugin-import": "^2.31.0", 33 | "eslint-plugin-jsx-a11y": "^6.10.0", 34 | "eslint-plugin-prettier": "^5.2.1", 35 | "eslint-plugin-react": "^7.37.1", 36 | "eslint-plugin-react-hooks": "^4.6.2", 37 | "jsdom": "^25.0.1", 38 | "prettier": "^3.3.3", 39 | "typescript": "^5.6.3", 40 | "vite": "^5.4.8", 41 | "vitest": "^2.1.2" 42 | }, 43 | "license": "MIT" 44 | } 45 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'vitest'; 2 | import { render, screen } from '@testing-library/react'; 3 | import { MemoryRouter } from 'react-router-dom'; 4 | 5 | import { WrappedApp, App } from './App'; 6 | 7 | describe('App', () => { 8 | it('Renders hello world', () => { 9 | // ARRANGE 10 | render(); 11 | // ACT 12 | // EXPECT 13 | expect( 14 | screen.getByRole('heading', { 15 | level: 1, 16 | }) 17 | ).toHaveTextContent('Hello World'); 18 | }); 19 | it('Renders not found if invalid path', () => { 20 | render( 21 | 22 | 23 | 24 | ); 25 | expect( 26 | screen.getByRole('heading', { 27 | level: 1, 28 | }) 29 | ).toHaveTextContent('Not Found'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { HashRouter, Route, Routes } from 'react-router-dom'; 2 | import Home from './pages/Home'; 3 | import NotFound from './pages/NotFound'; 4 | 5 | export function App() { 6 | return ( 7 | 8 | } /> 9 | } /> 10 | 11 | ); 12 | } 13 | 14 | export function WrappedApp() { 15 | return ( 16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingGarden/react-ts-starter/e268b83beeb99a6a761ef5ceb269dc2c1964753b/src/index.css -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import { WrappedApp } from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /src/pages/Home.tsx: -------------------------------------------------------------------------------- 1 | function Home() { 2 | return

Hello World

; 3 | } 4 | 5 | export default Home; 6 | -------------------------------------------------------------------------------- /src/pages/NotFound.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-router-dom'; 2 | 3 | function NotFound() { 4 | return ( 5 | <> 6 |

Not Found

7 | GO HOME 8 | 9 | ); 10 | } 11 | 12 | export default NotFound; 13 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import '@testing-library/jest-dom'; 3 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "types": ["vitest/globals"] 19 | }, 20 | "include": [ 21 | ".prettierrc.cjs", 22 | ".eslintrc.cjs", 23 | "src" 24 | ], 25 | "references": [{ "path": "./tsconfig.node.json" }] 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | /// 3 | /// 4 | 5 | import { defineConfig } from 'vite'; 6 | import react from '@vitejs/plugin-react'; 7 | 8 | export default defineConfig({ 9 | plugins: [react()], 10 | test: { 11 | globals: true, 12 | environment: 'jsdom', 13 | setupFiles: ['./src/setupTests.ts'], 14 | }, 15 | }); 16 | --------------------------------------------------------------------------------