Приложение на React c нуля до деплоя с помощью Cursor
Самое популярное приложение после Hello World на react — это личный планировщик задач Todolist и мы не будем сильно оригинальничать и напишем его с нуля на react. Разместим приложение в docker контейнере и поможет нам в этом Cursor AI IDE, а точнее сделает все за нас.
Разрабатывать приложение будем в ОС Windows 10, упакуем в docker контейнер и после разместим на хостинге.
Установим Node.js на Windows, для этого скачаем и установим Node.js LTS, проверим установку командой:
node -v
Если установка прошла успешно, в терминале отобразится установленная версия Node.js, теперь установим Create React App:
npm install -g create-react-app
При получении ошибки UnauthorizedAccess
в терминале
Откройте PowerShell от имени администратора
Проверьте Текущую Политику Выполнения
Get-ExecutionPolicy
Если он показывает «Ограничено», вам нужно его изменить.
Установите Политику выполнения на Неограниченную
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Проверьте изменение: запустите этот cmd
enter code here
Повторите попытку выполнения команды npx
npx create-react-app .
Запустим приложение 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 |
ERROR in src/App.tsx:49:5
TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.
47 |
48 | return (
> 49 |
| ^^^^^^^^^^^^^^^^^^^^^
50 |
51 | Todo List
52 |
| ^^^^^^
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 |
| ^^^^^^^^^^^^^^^^^^
> 12 |
| ^^^^^^^^^^^
> 13 |
| ^^^^^^^^^^^^^^^^^^^^^^
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, но сделаем, как нам подсказал наш помощник и войдем на сервер по ssh и введм следующие команды по очереди:

# Build the image
docker build -t todolist .
# Run the container
docker run -p 80:80 todolist
Контейнер запущен:

Проверим в portainer собранный docker образ и контейнер:

Видим, что наш контейнер работает:


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

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