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