Приложение на React c нуля до деплоя с помощью Cursor без строчки кода

от автора

Самое популярное приложение после Hello World на react — это личный планировщик задач Todolist и мы не будем сильно оригинальничать и напишем его с нуля на react. Разместим приложение в docker контейнере и поможет нам в этом Cursor AI IDE, а точнее сделает все за нас.

Разрабатывать приложение будем в ОС Windows 10, упакуем в docker контейнер и после разместим на хостинге.

Скачаем и установим Cursor IDE.

Установим Node.js на Windows, для этого скачаем и установим Node.js LTS, проверим установку командой:

node -v

Если установка прошла успешно, в терминале отобразится установленная версия Node.js, теперь инициализируем новый проект:

npm create vite@latest todolist -- --template react

При получении ошибки UnauthorizedAccess в терминале:

Скрытый текст
  1. Откройте PowerShell от имени администратора

  2. Проверьте Текущую Политику Выполнения

    Get-ExecutionPolicy

    Если он показывает «Ограничено», вам нужно его изменить.

  3. Установите Политику выполнения на Неограниченную

    Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

  4. Проверьте изменение: запустите этот cmd

    enter code here

  5. Повторите попытку выполнения команды

    npm create vite@latest todolist — —template react

Запустим приложение npm startв результате получим следующий вывод:

You can now view todolist in the browser.

Local: http://localhost:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

Мы запустили простейшее приложение на react, а значит подготовили рабочее окружение для разработки собственного приложения на react.

Начнем и озадачим чат, написав ему следующее:

После попытки запустить приложение я получил кучу ошибок

Скрытый текст
ERROR in src/App.tsx:1:33 TS7016: Could not find a declaration file for module 'react'. 'C:/Разработка/todolist/node_modules/react/index.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`   > 1 | import React, { useState } from 'react';       |                                 ^^^^^^^     2 | import './App.css';     3 |     4 | interface Todo { ERROR in src/App.tsx:31:24 TS7006: Parameter 'todo' implicitly has an 'any' type.     29 |     30 |   const handleToggleTodo = (id: number) => {   > 31 |     setTodos(todos.map(todo =>        |                        ^^^^     32 |       todo.id === id ? { ...todo, completed: !todo.completed } : todo     33 |     ));     34 |   }; ERROR in src/App.tsx:37:27 TS7006: Parameter 'todo' implicitly has an 'any' type.     35 |     36 |   const handleDeleteTodo = (id: number) => {   > 37 |     setTodos(todos.filter(todo => todo.id !== id));        |                           ^^^^     38 |   };     39 |     40 |   const filteredTodos = todos.filter(todo => { ERROR in src/App.tsx:40:38 TS7006: Parameter 'todo' implicitly has an 'any' type.     38 |   };     39 |   > 40 |   const filteredTodos = todos.filter(todo => {        |                                      ^^^^     41 |     if (filter === 'active') return !todo.completed;     42 |     if (filter === 'completed') return todo.completed;     43 |     return true; ERROR in src/App.tsx:46:39 TS7006: Parameter 'todo' implicitly has an 'any' type.     44 |   });     45 |   > 46 |   const remainingTasks = todos.filter(todo => !todo.completed).length;        |                                       ^^^^     47 |     48 |   return (     49 |     <div className="App"> ERROR in src/App.tsx:49:5 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     47 |     48 |   return (   > 49 |     <div className="App">        |     ^^^^^^^^^^^^^^^^^^^^^     50 |       <div className="container">     51 |         <h1>Todo List</h1>     52 |         <form onSubmit={handleAddTodo} className="todo-form"> ERROR in src/App.tsx:49:5 TS7016: Could not find a declaration file for module 'react/jsx-runtime'. 'C:/Разработка/todolist/node_modules/react/jsx-runtime.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react/jsx-runtime';`      47 |      48 |   return (   >  49 |     <div className="App">         |     ^^^^^^^^^^^^^^^^^^^^^   >  50 |       <div className="container">         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  51 |         <h1>Todo List</h1>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  52 |         <form onSubmit={handleAddTodo} className="todo-form">         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  53 |           <input         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  54 |             type="text"         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  55 |             value={inputValue}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  56 |             onChange={(e) => setInputValue(e.target.value)}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  57 |             placeholder="Add a new task..."         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  58 |             className="todo-input"         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  59 |           />         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  60 |           <button type="submit" className="add-button">Add</button>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  61 |         </form>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  62 |                  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  63 |         <div className="filters">         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  64 |           <button         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  65 |             className={`filter-button ${filter === 'all' ? 'active' : ''}`}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  66 |             onClick={() => setFilter('all')}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  67 |           >         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  68 |             All         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  69 |           </button>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  70 |           <button         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  71 |             className={`filter-button ${filter === 'active' ? 'active' : ''}`}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  72 |             onClick={() => setFilter('active')}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  73 |           >         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  74 |             Active         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  75 |           </button>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  76 |           <button         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  77 |             className={`filter-button ${filter === 'completed' ? 'active' : ''}`}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  78 |             onClick={() => setFilter('completed')}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  79 |           >         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  80 |             Completed         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  81 |           </button>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  82 |         </div>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  83 |         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  84 |         <div className="todo-stats">         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  85 |           {remainingTasks} {remainingTasks === 1 ? 'task' : 'tasks'} remaining         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  86 |         </div>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  87 |         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  88 |         <ul className="todo-list">         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  89 |           {filteredTodos.map(todo => (         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  90 |             <li key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  91 |               <span         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  92 |                 onClick={() => handleToggleTodo(todo.id)}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  93 |                 className="todo-text"         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  94 |               >         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  95 |                 {todo.text}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  96 |               </span>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  97 |               <button         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  98 |                 onClick={() => handleDeleteTodo(todo.id)}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  99 |                 className="delete-button"         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 100 |               >         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 101 |                 Delete         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 102 |               </button>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 103 |             </li>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 104 |           ))}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 105 |         </ul>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 106 |       </div>         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 107 |     </div>         | ^^^^^^^^^^^     108 |   );     109 | }     110 | ERROR in src/App.tsx:50:7 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     48 |   return (     49 |     <div className="App">   > 50 |       <div className="container">        |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^     51 |         <h1>Todo List</h1>     52 |         <form onSubmit={handleAddTodo} className="todo-form">     53 |           <input ERROR in src/App.tsx:51:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     49 |     <div className="App">     50 |       <div className="container">   > 51 |         <h1>Todo List</h1>        |         ^^^^     52 |         <form onSubmit={handleAddTodo} className="todo-form">     53 |           <input     54 |             type="text" ERROR in src/App.tsx:51:22 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     49 |     <div className="App">     50 |       <div className="container">   > 51 |         <h1>Todo List</h1>        |                      ^^^^^     52 |         <form onSubmit={handleAddTodo} className="todo-form">     53 |           <input     54 |             type="text" ERROR in src/App.tsx:52:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     50 |       <div className="container">     51 |         <h1>Todo List</h1>   > 52 |         <form onSubmit={handleAddTodo} className="todo-form">        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     53 |           <input     54 |             type="text"     55 |             value={inputValue} ERROR in src/App.tsx:53:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     51 |         <h1>Todo List</h1>     52 |         <form onSubmit={handleAddTodo} className="todo-form">   > 53 |           <input        |           ^^^^^^   > 54 |             type="text"        | ^^^^^^^^^^^^^^^^^^^^^^^   > 55 |             value={inputValue}        | ^^^^^^^^^^^^^^^^^^^^^^^   > 56 |             onChange={(e) => setInputValue(e.target.value)}        | ^^^^^^^^^^^^^^^^^^^^^^^   > 57 |             placeholder="Add a new task..."        | ^^^^^^^^^^^^^^^^^^^^^^^   > 58 |             className="todo-input"        | ^^^^^^^^^^^^^^^^^^^^^^^   > 59 |           />        | ^^^^^^^^^^^^^     60 |           <button type="submit" className="add-button">Add</button>     61 |         </form>     62 |          ERROR in src/App.tsx:56:24 TS7006: Parameter 'e' implicitly has an 'any' type.     54 |             type="text"     55 |             value={inputValue}   > 56 |             onChange={(e) => setInputValue(e.target.value)}        |                        ^     57 |             placeholder="Add a new task..."     58 |             className="todo-input"     59 |           /> ERROR in src/App.tsx:60:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     58 |             className="todo-input"     59 |           />   > 60 |           <button type="submit" className="add-button">Add</button>        |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     61 |         </form>     62 |              63 |         <div className="filters"> ERROR in src/App.tsx:60:59 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     58 |             className="todo-input"     59 |           />   > 60 |           <button type="submit" className="add-button">Add</button>        |                                                           ^^^^^^^^^     61 |         </form>     62 |              63 |         <div className="filters"> ERROR in src/App.tsx:61:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     59 |           />     60 |           <button type="submit" className="add-button">Add</button>   > 61 |         </form>        |         ^^^^^^^     62 |              63 |         <div className="filters">     64 |           <button ERROR in src/App.tsx:63:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     61 |         </form>     62 |            > 63 |         <div className="filters">        |         ^^^^^^^^^^^^^^^^^^^^^^^^^     64 |           <button     65 |             className={`filter-button ${filter === 'all' ? 'active' : ''}`}     66 |             onClick={() => setFilter('all')} ERROR in src/App.tsx:64:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     62 |              63 |         <div className="filters">   > 64 |           <button        |           ^^^^^^^   > 65 |             className={`filter-button ${filter === 'all' ? 'active' : ''}`}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 66 |             onClick={() => setFilter('all')}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 67 |           >        | ^^^^^^^^^^^^     68 |             All     69 |           </button>     70 |           <button ERROR in src/App.tsx:69:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     67 |           >     68 |             All   > 69 |           </button>        |           ^^^^^^^^^     70 |           <button     71 |             className={`filter-button ${filter === 'active' ? 'active' : ''}`}     72 |             onClick={() => setFilter('active')} ERROR in src/App.tsx:70:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     68 |             All     69 |           </button>   > 70 |           <button        |           ^^^^^^^   > 71 |             className={`filter-button ${filter === 'active' ? 'active' : ''}`}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 72 |             onClick={() => setFilter('active')}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 73 |           >        | ^^^^^^^^^^^^     74 |             Active     75 |           </button>     76 |           <button ERROR in src/App.tsx:75:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     73 |           >     74 |             Active   > 75 |           </button>        |           ^^^^^^^^^     76 |           <button     77 |             className={`filter-button ${filter === 'completed' ? 'active' : ''}`}     78 |             onClick={() => setFilter('completed')} ERROR in src/App.tsx:76:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     74 |             Active     75 |           </button>   > 76 |           <button        |           ^^^^^^^   > 77 |             className={`filter-button ${filter === 'completed' ? 'active' : ''}`}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 78 |             onClick={() => setFilter('completed')}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 79 |           >        | ^^^^^^^^^^^^     80 |             Completed     81 |           </button>     82 |         </div> ERROR in src/App.tsx:81:11 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     79 |           >     80 |             Completed   > 81 |           </button>        |           ^^^^^^^^^     82 |         </div>     83 |     84 |         <div className="todo-stats"> ERROR in src/App.tsx:82:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     80 |             Completed     81 |           </button>   > 82 |         </div>        |         ^^^^^^     83 |     84 |         <div className="todo-stats">     85 |           {remainingTasks} {remainingTasks === 1 ? 'task' : 'tasks'} remaining ERROR in src/App.tsx:84:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     82 |         </div>     83 |   > 84 |         <div className="todo-stats">        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^     85 |           {remainingTasks} {remainingTasks === 1 ? 'task' : 'tasks'} remaining     86 |         </div>     87 | ERROR in src/App.tsx:86:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     84 |         <div className="todo-stats">     85 |           {remainingTasks} {remainingTasks === 1 ? 'task' : 'tasks'} remaining   > 86 |         </div>        |         ^^^^^^     87 |     88 |         <ul className="todo-list">     89 |           {filteredTodos.map(todo => ( ERROR in src/App.tsx:88:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     86 |         </div>     87 |   > 88 |         <ul className="todo-list">        |         ^^^^^^^^^^^^^^^^^^^^^^^^^^     89 |           {filteredTodos.map(todo => (     90 |             <li key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>     91 |               <span ERROR in src/App.tsx:89:30 TS7006: Parameter 'todo' implicitly has an 'any' type.     87 |     88 |         <ul className="todo-list">   > 89 |           {filteredTodos.map(todo => (        |                              ^^^^     90 |             <li key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>     91 |               <span     92 |                 onClick={() => handleToggleTodo(todo.id)} ERROR in src/App.tsx:90:13 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     88 |         <ul className="todo-list">     89 |           {filteredTodos.map(todo => (   > 90 |             <li key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     91 |               <span     92 |                 onClick={() => handleToggleTodo(todo.id)}     93 |                 className="todo-text" ERROR in src/App.tsx:91:15 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     89 |           {filteredTodos.map(todo => (     90 |             <li key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>   > 91 |               <span        |               ^^^^^   > 92 |                 onClick={() => handleToggleTodo(todo.id)}        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 93 |                 className="todo-text"        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 94 |               >        | ^^^^^^^^^^^^^^^^     95 |                 {todo.text}     96 |               </span>     97 |               <button ERROR in src/App.tsx:96:15 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     94 |               >     95 |                 {todo.text}   > 96 |               </span>        |               ^^^^^^^     97 |               <button     98 |                 onClick={() => handleDeleteTodo(todo.id)}     99 |                 className="delete-button" ERROR in src/App.tsx:97:15 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.      95 |                 {todo.text}      96 |               </span>   >  97 |               <button         |               ^^^^^^^   >  98 |                 onClick={() => handleDeleteTodo(todo.id)}         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   >  99 |                 className="delete-button"         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   > 100 |               >         | ^^^^^^^^^^^^^^^^     101 |                 Delete     102 |               </button>     103 |             </li> ERROR in src/App.tsx:102:15 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     100 |               >     101 |                 Delete   > 102 |               </button>         |               ^^^^^^^^^     103 |             </li>     104 |           ))}     105 |         </ul> ERROR in src/App.tsx:103:13 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     101 |                 Delete     102 |               </button>   > 103 |             </li>         |             ^^^^^     104 |           ))}     105 |         </ul>     106 |       </div> ERROR in src/App.tsx:105:9 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     103 |             </li>     104 |           ))}   > 105 |         </ul>         |         ^^^^^     106 |       </div>     107 |     </div>     108 |   ); ERROR in src/App.tsx:106:7 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     104 |           ))}     105 |         </ul>   > 106 |       </div>         |       ^^^^^^     107 |     </div>     108 |   );     109 | } ERROR in src/App.tsx:107:5 TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.     105 |         </ul>     106 |       </div>   > 107 |     </div>         |     ^^^^^^     108 |   );     109 | }     110 | ERROR in src/index.tsx:1:19 TS7016: Could not find a declaration file for module 'react'. 'C:/Разработка/todolist/node_modules/react/index.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react';`   > 1 | import React from 'react';       |                   ^^^^^^^     2 | import ReactDOM from 'react-dom/client';     3 | import './index.css';     4 | import App from './App'; ERROR in src/index.tsx:2:22 TS7016: Could not find a declaration file for module 'react-dom/client'. 'C:/Разработка/todolist/node_modules/react-dom/client.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/react-dom` if it exists or add a new declaration (.d.ts) file containing `declare module 'react-dom/client';`     1 | import React from 'react';   > 2 | import ReactDOM from 'react-dom/client';       |                      ^^^^^^^^^^^^^^^^^^     3 | import './index.css';     4 | import App from './App';     5 | ERROR in src/index.tsx:11:3 TS7016: Could not find a declaration file for module 'react/jsx-runtime'. 'C:/Разработка/todolist/node_modules/react/jsx-runtime.js' implicitly has an 'any' type.   Try `npm i --save-dev @types/react` if it exists or add a new declaration (.d.ts) file containing `declare module 'react/jsx-runtime';`      9 |     10 | root.render(   > 11 |   <React.StrictMode>        |   ^^^^^^^^^^^^^^^^^^   > 12 |     <App />        | ^^^^^^^^^^^   > 13 |   </React.StrictMode>        | ^^^^^^^^^^^^^^^^^^^^^^     14 | ); 

Не придумал ничего лучше, как скормить их все в чат Cursor

и не поверите он все тут же поправил, после запуска открылось приложение:

и отчитался, что сделал

На этом у нас есть готовое приложение, которое можно улучшать и дорабатывать, давая команды ИИ, но приложение работает локально. Останавливаем терминал и оно отключилось.

Теперь наша задача перенести его в интернет. Для того, чтобы запустить приложение мы разворачивали окружение, которое нужно переносить на другой сервер в интернете, чтобы упростить задачу, будем использовать docker на продакт сервере.

Попросим чат сформировать dockerfile для создания докер образа, содержащий все необходимые команды для развертки аналогичного окружения в один клик.

Скрытый текст
# Build stage FROM node:18-alpine as build  WORKDIR /app  # Copy package files COPY package*.json ./  # Install dependencies RUN npm ci  # Copy source code COPY . .  # Build the application RUN npm run build  # Production stage FROM nginx:alpine  # Copy nginx configuration COPY nginx.conf /etc/nginx/conf.d/default.conf  # Copy built files from build stage COPY --from=build /app/build /usr/share/nginx/html  # Expose port 80 EXPOSE 80  # Start nginx CMD ["nginx", "-g", "daemon off;"] 

ИИ подготовил dockerfile и конфиг nginx.conf, осталось загрузить весь проект на GitHub, зарегистрировать хостинг, сбилдить образ и запустить контейнер с приложением. Звучит сложно, на самом деле все просто.

Не буду заострять внимание, как отправить проект в github, на самом деле много информации в интернете и все сводится к установке git локально и подключении удаленного репозитория в Cursor

Запушим и получим код проекта в репозитории Github.

Далее разворачиваем сервер, для пробы используем сервер за 1 рубль в dockerhosting.ru, на созданном инстансе уже установлен docker и portainer.

Выполним сборку образа и запуск контейнера. Сборку образа сделаем сделаем в portainer

В portainer перейдем в раздел images и кликнем Build a new image

Укажем наименование наименование todolist и путь репозиторию Github.

Кликаем Build the image и ждем, после проверяем, что новый образ появился

Запуск контейнера выполним, так как нам подсказал наш помощник, войдем на сервер по ssh, выполним команду:

docker run -p 80:80 todolist

Контейнер запущен:

Проверим в portainer, что наш контейнер работает:

Проверим наше приложение по IP адресу сервера в браузере:

На выходе получил готовое приложение ни разу не работая с react. Если интересно, могу попробовать продолжить «разработку приложения», разработав бэк и подключить его к базе данных.

Если будут вопросы, мой телеграм.


ссылка на оригинал статьи https://habr.com/ru/articles/905736/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *