├── .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 |
--------------------------------------------------------------------------------