├── .env.example
├── src
├── vite-env.d.ts
├── main.tsx
├── App.css
├── index.css
├── App.tsx
└── assets
│ ├── react.svg
│ └── elbrus.svg
├── tsconfig.json
├── .gitignore
├── index.html
├── vite.config.ts
├── .prettierrc
├── tsconfig.node.json
├── tsconfig.app.json
├── package.json
├── public
└── vite.svg
├── README.md
└── eslint.config.js
/.env.example:
--------------------------------------------------------------------------------
1 | VITE_APP_TITLE=
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
4 | }
5 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import './index.css';
4 | import App from './App.tsx';
5 |
6 | createRoot(document.getElementById('root')!).render(
7 |
8 |
9 | ,
10 | );
11 |
--------------------------------------------------------------------------------
/.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 | .env
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import type { AliasOptions } from 'vite';
2 | import { defineConfig } from 'vite';
3 | import react from '@vitejs/plugin-react';
4 | import path from 'path';
5 |
6 | const root = path.resolve(__dirname, 'src');
7 |
8 | // https://vite.dev/config/
9 | export default defineConfig({
10 | plugins: [react()],
11 | resolve: {
12 | alias: {
13 | '@': root,
14 | } as AliasOptions,
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "experimentalTernaries": false,
3 | "printWidth": 100,
4 | "tabWidth": 2,
5 | "useTabs": false,
6 | "semi": true,
7 | "singleQuote": true,
8 | "quoteProps": "as-needed",
9 | "jsxSingleQuote": false,
10 | "trailingComma": "all",
11 | "bracketSpacing": true,
12 | "bracketSameLine": false,
13 | "arrowParens": "always",
14 | "proseWrap": "always",
15 | "endOfLine": "lf",
16 | "embeddedLanguageFormatting": "auto",
17 | "singleAttributePerLine": false
18 | }
19 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2020",
5 | "useDefineForClassFields": true,
6 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
7 | "module": "ESNext",
8 | "skipLibCheck": true,
9 | "paths": {
10 | "@/*": ["./src/*"]
11 | },
12 |
13 | /* Bundler mode */
14 | "moduleResolution": "bundler",
15 | "allowImportingTsExtensions": true,
16 | "isolatedModules": true,
17 | "moduleDetection": "force",
18 | "noEmit": true,
19 | "jsx": "react-jsx",
20 |
21 | /* Linting */
22 | "strict": true,
23 | "noUnusedLocals": true,
24 | "noUnusedParameters": true,
25 | "noFallthroughCasesInSwitch": true,
26 | "noUncheckedSideEffectImports": true
27 | },
28 | "include": ["src"]
29 | }
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "description": "Elbrus Bootcamp Vite React Typescript Template",
7 | "keywords": [
8 | "Elbrus",
9 | "Bootcamp",
10 | "Vite",
11 | "React",
12 | "Typescript"
13 | ],
14 | "author": "Elbrus Bootcamp",
15 | "license": "ISC",
16 | "scripts": {
17 | "dev": "vite",
18 | "build": "tsc -b && vite build",
19 | "lint": "eslint .",
20 | "preview": "vite preview"
21 | },
22 | "dependencies": {
23 | "react": "^19.1.0",
24 | "react-dom": "^19.1.0"
25 | },
26 | "devDependencies": {
27 | "@elbrus/eslint-config": "^1.1.0",
28 | "@elbrus/eslint-plugin": "^1.0.1",
29 | "@types/node": "^22.15.19",
30 | "@eslint/js": "^9.27.0",
31 | "@types/react": "^19.1.4",
32 | "@types/react-dom": "^19.1.5",
33 | "@vitejs/plugin-react": "^4.4.1",
34 | "eslint": "^9.27.0",
35 | "eslint-plugin-fsd-layers": "^0.0.18",
36 | "eslint-plugin-react": "^7.37.5",
37 | "eslint-plugin-react-hooks": "^5.2.0",
38 | "eslint-plugin-react-refresh": "^0.4.20",
39 | "globals": "^16.1.0",
40 | "typescript": "~5.8.3",
41 | "typescript-eslint": "^8.32.1",
42 | "vite": "^6.3.5"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
15 |
16 | a {
17 | font-weight: 500;
18 | color: #646cff;
19 | text-decoration: inherit;
20 | }
21 | a:hover {
22 | color: #535bf2;
23 | }
24 |
25 | body {
26 | margin: 0;
27 | display: flex;
28 | place-items: center;
29 | min-width: 320px;
30 | min-height: 100vh;
31 | }
32 |
33 | h1 {
34 | font-size: 3.2em;
35 | line-height: 1.1;
36 | }
37 |
38 | button {
39 | border-radius: 8px;
40 | border: 1px solid transparent;
41 | padding: 0.6em 1.2em;
42 | font-size: 1em;
43 | font-weight: 500;
44 | font-family: inherit;
45 | background-color: #1a1a1a;
46 | cursor: pointer;
47 | transition: border-color 0.25s;
48 | }
49 | button:hover {
50 | border-color: #646cff;
51 | }
52 | button:focus,
53 | button:focus-visible {
54 | outline: 4px auto -webkit-focus-ring-color;
55 | }
56 |
57 | @media (prefers-color-scheme: light) {
58 | :root {
59 | color: #213547;
60 | background-color: #ffffff;
61 | }
62 | a:hover {
63 | color: #747bff;
64 | }
65 | button {
66 | background-color: #f9f9f9;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import type { JSX } from 'react';
2 | import { useState } from 'react';
3 | import reactLogo from '@/assets/react.svg';
4 | import elbrusLogo from '@/assets/elbrus.svg';
5 | import viteLogo from '/vite.svg';
6 | import '@/App.css';
7 |
8 | function App(): JSX.Element {
9 | const [count, setCount] = useState(0);
10 |
11 | return (
12 | <>
13 | Elbrus Bootcamp
14 |
15 |
26 | Elbrus Bootcamp
27 | Vite + React
28 |
29 |
30 |
31 | Edit src/App.tsx and save to test HMR
32 |
33 |
34 | Click on the Vite and React logos to learn more
35 | >
36 | );
37 | }
38 |
39 | export default App;
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Elbrus Bootcamp Vite bundle
2 |
3 | ## React + Typescript + ESLint + Prettier
4 |
5 | Современный быстрый сборщик React проекта на Typescript с предустановленными настройками ESLint и Prettier от Elbrus Bootcamp.
6 |
7 | ## Использование
8 |
9 | ```
10 | npx degit Elbrus-Bootcamp/vite-react-ts my-app
11 |
12 | cd my-app
13 |
14 | npm i
15 | ```
16 |
17 | ## Скрипты
18 |
19 | - Запустить в режиме разработки
20 |
21 | ```
22 | npm run dev
23 | ```
24 |
25 | - Собрать проект
26 |
27 | ```
28 | npm run build
29 | ```
30 |
31 | - Превью
32 |
33 | ```
34 | npm run preview
35 | ```
36 |
37 | ## `ENV`
38 |
39 | Для подключения переменных окружения нужно описать их в файле `.env` в корне. Переменные окружения можно получить из объекта `import.meta.env`. Чтобы Typescript подсказывал, какими переменными окружения можно пользоваться, их нужно прописать в файле `src/env.d.ts`. Только переменные с префиксом `VITE_` передаются на клиент.
40 |
41 | ## `settings.json`
42 |
43 | Чтобы настроить форматирование и линтование по сохранению, необходимо прописать в `settings.json` (ctrl + shift + P) следующие настройки:
44 |
45 | ```json
46 | {
47 | "editor.codeActionsOnSave": {
48 | "source.fixAll.eslint": true
49 | },
50 | "editor.formatOnSave": true,
51 | "editor.defaultFormatter": "esbenp.prettier-vscode"
52 | }
53 | ```
54 |
55 | Можно добавить форматирование Prettier для JS и React:
56 |
57 | ```json
58 | {
59 | "[javascript]": {
60 | "editor.defaultFormatter": "esbenp.prettier-vscode"
61 | },
62 | "[javascriptreact]": {
63 | "editor.defaultFormatter": "esbenp.prettier-vscode"
64 | }
65 | }
66 | ```
67 |
68 | При работе не из корневой директории необходимо настроить CWD для ESLint:
69 |
70 | ```json
71 | {
72 | "eslint.workingDirectories": [
73 | { "directory": "./client", "changeProcessCWD": true },
74 | { "directory": "./server", "changeProcessCWD": true }
75 | ]
76 | }
77 | ```
78 |
79 | Если директория не `client` или `server`, то можно добавить соответствующую строчку в данный массив.
80 |
81 | ## FAQ
82 |
83 | 1. На windows из-под wsl Vite не следит за изменениями файлов
84 | Добавить в `vite.config`
85 |
86 | ```js
87 | server: { watch: { usePolling: true } }
88 | ```
89 | Подробнее: https://vitejs.dev/config/server-options.html#server-watch.
90 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import globals from 'globals';
3 | import reactHooks from 'eslint-plugin-react-hooks';
4 | import react from 'eslint-plugin-react';
5 | import tseslint from 'typescript-eslint';
6 | import elbrusConfig from '@elbrus/eslint-config';
7 | import elbrusPlugin from '@elbrus/eslint-plugin';
8 | import fsdLayers from 'eslint-plugin-fsd-layers';
9 | import reactRefresh from 'eslint-plugin-react-refresh';
10 |
11 | export default tseslint.config(
12 | { ignores: ['dist'] },
13 | {
14 | extends: [
15 | js.configs.recommended,
16 | ...elbrusConfig,
17 | tseslint.configs.stylisticTypeChecked,
18 | tseslint.configs.strictTypeChecked,
19 | ],
20 | files: ['**/*.{ts,tsx}'],
21 | languageOptions: {
22 | ecmaVersion: 2020,
23 | globals: globals.browser,
24 | parserOptions: {
25 | projectService: true,
26 | tsconfigRootDir: import.meta.dirname,
27 | },
28 | },
29 | plugins: {
30 | 'react-hooks': reactHooks,
31 | 'react-refresh': reactRefresh,
32 | 'fsd-layers': fsdLayers,
33 | '@elbrus': elbrusPlugin,
34 | },
35 | rules: {
36 | ...reactHooks.configs.recommended.rules,
37 |
38 | // Общие правила
39 | '@elbrus/prefer-for-of': 'error',
40 | 'fsd-layers/no-import-from-top': 'error',
41 | 'class-methods-use-this': 'warn',
42 | 'no-console': 'off',
43 | 'default-param-last': 'off',
44 | 'consistent-return': 'warn',
45 | 'no-void': 'off',
46 | 'no-param-reassign': 'off',
47 | '@typescript-eslint/switch-exhaustiveness-check': 'error',
48 | '@typescript-eslint/no-non-null-assertion': 'warn',
49 | '@typescript-eslint/no-misused-promises': [
50 | 'error',
51 | {
52 | checksVoidReturn: {
53 | attributes: false,
54 | },
55 | },
56 | ],
57 | '@typescript-eslint/no-confusing-void-expression': [
58 | 'error',
59 | {
60 | ignoreArrowShorthand: true,
61 | ignoreVoidOperator: true,
62 | },
63 | ],
64 |
65 | // Возвращаемые значения функций
66 | '@typescript-eslint/explicit-function-return-type': [
67 | 'error',
68 | {
69 | allowExpressions: true,
70 | allowTypedFunctionExpressions: true,
71 | allowHigherOrderFunctions: true,
72 | allowDirectConstAssertionInArrowFunctions: true,
73 | allowConciseArrowFunctionExpressionsStartingWithVoid: true,
74 | allowFunctionsWithoutTypeParameters: false,
75 | },
76 | ],
77 |
78 | // Правила работы с типами
79 | '@typescript-eslint/consistent-type-definitions': ['warn', 'type'],
80 | '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
81 | '@typescript-eslint/consistent-type-exports': [
82 | 'error',
83 | {
84 | fixMixedExportsWithInlineTypeSpecifier: true,
85 | },
86 | ],
87 | },
88 | },
89 | {
90 | plugins: {
91 | react,
92 | },
93 | rules: {
94 | ...react.configs.recommended.rules,
95 | ...react.configs['jsx-runtime'].rules,
96 | 'react/no-array-index-key': 'error',
97 | },
98 | },
99 | );
100 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/elbrus.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
51 |
--------------------------------------------------------------------------------