├── src ├── vite-env.d.ts ├── shopping-cart │ ├── ItemCounter.css │ ├── ItemCounter.module.css │ └── ItemCounter.tsx ├── main.tsx ├── FirstStepsApp.tsx └── MyAwesomeApp.tsx ├── tsconfig.json ├── vite.config.ts ├── .gitignore ├── index.html ├── tsconfig.node.json ├── tsconfig.app.json ├── package.json ├── eslint.config.js ├── public └── vite.svg └── README.md /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/shopping-cart/ItemCounter.css: -------------------------------------------------------------------------------- 1 | .item-row { 2 | display: flex; 3 | align-items: center; 4 | gap: 10px; 5 | margin-top: 10px; 6 | } 7 | 8 | .item-text { 9 | width: 150px; 10 | } 11 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react-swc' 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /src/shopping-cart/ItemCounter.module.css: -------------------------------------------------------------------------------- 1 | .itemRow { 2 | display: flex; 3 | align-items: center; 4 | gap: 10px; 5 | margin-top: 10px; 6 | } 7 | 8 | .item-text { 9 | width: 150px; 10 | } 11 | 12 | .red { 13 | color: red; 14 | } 15 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { FirstStepsApp } from './FirstStepsApp'; 4 | import { MyAwesomeApp } from './MyAwesomeApp'; 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | {/* */} 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-steps", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^19.0.0", 14 | "react-dom": "^19.0.0" 15 | }, 16 | "devDependencies": { 17 | "@eslint/js": "^9.21.0", 18 | "@types/react": "^19.0.10", 19 | "@types/react-dom": "^19.0.4", 20 | "@vitejs/plugin-react-swc": "^3.8.0", 21 | "eslint": "^9.21.0", 22 | "eslint-plugin-react-hooks": "^5.1.0", 23 | "eslint-plugin-react-refresh": "^0.4.19", 24 | "globals": "^15.15.0", 25 | "typescript": "~5.7.2", 26 | "typescript-eslint": "^8.24.1", 27 | "vite": "^6.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /src/FirstStepsApp.tsx: -------------------------------------------------------------------------------- 1 | import { ItemCounter } from './shopping-cart/ItemCounter'; 2 | 3 | interface ItemInCart { 4 | productName: string; 5 | quantity: number; 6 | } 7 | 8 | const itemsInCart: ItemInCart[] = [ 9 | { productName: 'Nintendo Switch 2', quantity: 1 }, 10 | { productName: 'Pro Controller', quantity: 2 }, 11 | { productName: 'Super Smash', quantity: 5 }, 12 | ]; 13 | 14 | export function FirstStepsApp() { 15 | return ( 16 | <> 17 |

Carrito de compras

18 | 19 | {itemsInCart.map(({ productName, quantity }) => ( 20 | 21 | ))} 22 | 23 | {/* 24 | 25 | 26 | */} 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src/MyAwesomeApp.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react'; 2 | 3 | const firstName = 'Fernando'; 4 | const lastName = 'Herrera'; 5 | 6 | const favoriteGames = ['Elden Ring', 'Smash', 'Metal Gear']; 7 | const isActive = false; 8 | 9 | const address = { 10 | zipCode: 'ABC-123', 11 | country: 'Canadá', 12 | }; 13 | 14 | const myStyles: CSSProperties = { 15 | backgroundColor: '#fafafa', 16 | borderRadius: 20, 17 | padding: 10, 18 | marginTop: 30, 19 | }; 20 | 21 | export const MyAwesomeApp = () => { 22 | return ( 23 | <> 24 |

{firstName}

25 |

{lastName}

26 | 27 |

{favoriteGames.join(', ')}

28 |

{2 + 2}

29 | 30 |

{isActive ? 'Activo' : 'No activo'}

31 | 32 |

{JSON.stringify(address)}

33 | 34 | ); 35 | }; 36 | 37 | // export function MyAwesomeApp() { 38 | // return ( 39 | // <> 40 | //

Fernando

41 | //

Herrera

42 | // 43 | // ); 44 | // } 45 | -------------------------------------------------------------------------------- /src/shopping-cart/ItemCounter.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | // import './ItemCounter.css'; 4 | import styles from './ItemCounter.module.css'; 5 | 6 | interface Props { 7 | name: string; 8 | quantity?: number; 9 | } 10 | 11 | export const ItemCounter = ({ name, quantity = 1 }: Props) => { 12 | const [count, setCount] = useState(quantity); 13 | 14 | const handleAdd = () => { 15 | setCount(count + 1); 16 | }; 17 | 18 | const handleSubtract = () => { 19 | if (count === 1) return; 20 | 21 | setCount(count - 1); 22 | }; 23 | 24 | return ( 25 |
34 | 40 | {name} 41 | 42 | 43 | {count} 44 | 45 |
46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: 13 | 14 | ```js 15 | export default tseslint.config({ 16 | extends: [ 17 | // Remove ...tseslint.configs.recommended and replace with this 18 | ...tseslint.configs.recommendedTypeChecked, 19 | // Alternatively, use this for stricter rules 20 | ...tseslint.configs.strictTypeChecked, 21 | // Optionally, add this for stylistic rules 22 | ...tseslint.configs.stylisticTypeChecked, 23 | ], 24 | languageOptions: { 25 | // other options... 26 | parserOptions: { 27 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 28 | tsconfigRootDir: import.meta.dirname, 29 | }, 30 | }, 31 | }) 32 | ``` 33 | 34 | You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: 35 | 36 | ```js 37 | // eslint.config.js 38 | import reactX from 'eslint-plugin-react-x' 39 | import reactDom from 'eslint-plugin-react-dom' 40 | 41 | export default tseslint.config({ 42 | plugins: { 43 | // Add the react-x and react-dom plugins 44 | 'react-x': reactX, 45 | 'react-dom': reactDom, 46 | }, 47 | rules: { 48 | // other rules... 49 | // Enable its recommended typescript rules 50 | ...reactX.configs['recommended-typescript'].rules, 51 | ...reactDom.configs.recommended.rules, 52 | }, 53 | }) 54 | ``` 55 | --------------------------------------------------------------------------------