Я уверен, что когда вы только начнете изучать веб-разработку с использованием стека MERN, у вас возникнут вопросы типа «Как это — создавать приложение с полным стеком?». Что такое frontend и backend? Как их соединить? Есть ли здесь какая-то магия? и т.д. Поэтому я пишу это руководство, чтобы ответить на ваши вопросы и показать вам, как построить веб-приложение полного стека.
Примечание
Цель этого руководства — предоставить вам высокоуровневый обзор того, что такое создание приложения полного стека, а не подробное объяснение технологий стека MERN.
Давайте начнем
Необходимые условия
- Базовое понимание технологий стека MERN.
- Установленный NodeJs
- Учетная запись MongoDB.
Проект
Чтобы не усложнять задачу и в то же время охватить больше концепций, мы создадим простой мини-проект. Мы создадим простое приложение для отслеживания продуктивности, в котором вы сможете записывать, какие действия вы выполнили в течение дня и за какое время. Таким образом, мы сможем увидеть, как мы тратим свое время. Также мы сможем увидеть все дела на главной странице.
- Исходный код
Как это работает?
- Вы вводите вид деятельности и количество времени, которое вы на него потратили.
- Затем данные передаются на бэкенд NodeJs.
- Эта информация будет храниться в базе данных MongoDB.
- Все виды деятельности отображаются на главной странице.
Мы знаем, что нам нужно сделать; теперь давайте выясним, как это сделать.
Фронтенд/клиент
Что такое фронтенд/клиентское приложение?
Клиентское приложение относится к фронтенду — части приложения полного стека. Клиент посылает запросы на сервер и получает ответы. Этот запрос может быть отправкой клиентом информации на сервер или запросом на получение информации. Клиент — это видимая часть приложения полного стека.
Давайте начнем с создания клиента.
- Создайте новую папку и обозначьте ее «productivity-app».
-
Создайте react-приложение под названием «client» с помощью create-react-app.
npx create-react-app client
-
Запустите ваш редактор кодирования/IDE и откройте проект.
-
Вот как будет выглядеть структура ваших папок.
. ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg ├── reportWebVitals.js └── setupTests.js
-
На данный момент нас интересуют только файлы
App.js
иApp.css
. -
Удалите весь существующий код из файлов
App.js
иApp.css
.
Давайте создадим компонент react. -
Добавьте компонент App в файл
App.js
.import "./App.css"; const App = () => { return <div>My App</div>; } export default App;
-
Приведенный выше код создает и отображает компонент App.
-
Выполните следующую команду в терминале и перейдите по адресу http://localhost:3000.
npm start
Спроектируйте приложение.
- Мы хотим, чтобы пользователь вводил название занятия, а также время, которое оно заняло. Затем мы отобразим все виды деятельности на главной странице.
-
Скопируйте и вставьте этот HTML-код в компонент App.
... <div className="app"> <header className="app-header"> <h1>Productivity Tracker</h1> <form> <div> <label htmlFor="activity">Activity:</label> <input type="text" id="activity" name="activity" autoComplete="off" /> </div> <div> <label htmlFor="time">Time Taken:</label> <input type="text" id="time" name="time" autoComplete="off" /> </div> <button type="submit">Add</button> </form> </header> <main className="app-main"> <h2>Today</h2> <ol> <li> Activity 1 - 3 hours</li> <li> Activity 2 - 10 min</li> <li> Activity 3 - 2 hours and 25 min</li> </ol> </main> </div> ...
-
Теперь наше приложение будет выглядеть следующим образом.
-
Теперь давайте добавим немного CSS. Скопируйте и вставьте код CSS из этого файла в файл
App.css
. -
Теперь наше приложение выглядит следующим образом.
Добавьте логику.
-
В настоящее время действия жестко закодированы. Давайте сохраним и будем использовать действия в состоянии.
... const [activities, setActivities] = useState([]); ... ... <main className="app-main"> <h2>Today</h2> {activities && activities.length > 0 ? ( <ol> {activities.map((activity) => ( <li key={activity._id}> {activity.name} - {activity.time} </li> ))} </ol> ) : ( <p>No activities yet</p> )} </main> ...
-
Но где мы возьмем наши активности? Как мы добавим деятельность в список?
-
Для обработки всего этого необходим бэкенд.
Бэкэнд/сервер
Бэкенд-компонент приложения полного стека часто называют сервером. Работа сервера заключается в постоянном получении запросов, реализации бизнес-логики и возврате результатов.
База данных
Прежде чем создавать сервер, давайте сначала создадим базу данных. Чтобы записывать и добавлять наши действия, нам нужна база данных. Мы можем использовать облачную базу данных вместо хостинга базы данных. MongoDB предлагает бесплатную облачную базу данных (атлас), которую можно использовать для небольших проектов/хобби.
- Войдите в свою учетную запись MongoDB.
- Создайте проект.
- Затем перейдите в раздел «Browse collections» и создайте базу данных. Для названия коллекции напишите «activities».
-
Нажмите на «Обзор», а затем во вкладке обзора нажмите на «CONNECT» -> «Подключить ваше приложение». Скопируйте строку подключения. Ваша строка подключения должна выглядеть следующим образом.
mongodb+srv://<username>:<password>@<clusterUrl>/<databaseName>?retryWrites=true&w=majority
-
Сохраните эту строку в безопасном месте.
Сервер
Теперь у нас есть база данных. Теперь давайте создадим логику нашего приложения и подключим ее к базе данных.
- Создайте папку под названием «Server» в папке вашего проекта.
- В терминале откройте папку и введите
npm init
. Заполните все данные. -
Установите следующие пакеты.
npm i express mongoose dotenv
- express: Используется для создания сервера.
- mongoose: Используется для работы с базой данных MongoDB
- dotenv: Используется для загрузки переменных окружения.
-
Создайте файл
.env
и сохраните вашу строку подключения в переменной под названием «MONGODB URI».MONGODB_URI=yourconnectionstring
-
Создайте файл
server.js
и вставьте этот код.const express = require("express"); const mongoose = require("mongoose"); const app = express(); /* Loading the environment variables from the .env file. */ require("dotenv").config(); const PORT = process.env.PORT || 5000; const MONGODB_URI = process.env.MONGODB_URI || "mongodb://localhost/todoapiDB"; /* Telling the application to use the express.json() middleware. This middleware will parse the body of any request that has a Content-Type of application/json. */ app.use(express.json()); /* This is a route handler. It is listening for a GET request to the root route of the application. When it receives a request, it will send back a response with the string "Hello World!". */ app.get("/", (req, res) => { res.send("Hello World!"); }); /* Connecting to the database and then starting the server. */ mongoose .connect(MONGODB_URI, { useNewUrlParser: true }) .then(() => { app.listen(PORT, console.log("Server stated on port 5000")); }) .catch((err) => { console.log(err); });
-
Выполните приведенную ниже команду и перейдите на сайт http://localhost:5000 в вашем браузере. Вы увидите что-то вроде этого. (Убедитесь, что у вас глобально установлен nodemon).
npm run dev
Это означает, что сервер успешно запущен.
-
Создайте модель схемы для хранения активности.
- Создайте папку под названием «models» и в ней создайте файл
activity.model.js
. Скопируйте и вставьте приведенный ниже код.
const mongoose = require("mongoose"); const Schema = mongoose.Schema; /* Creating a new schema for the activity model. */ const activitySchema = new Schema({ name: { type: String, required: true, }, time: { type: String, required: true, }, }); module.exports = mongoose.model("Activity", activitySchema);
- Создайте папку под названием «models» и в ней создайте файл
-
Реализуйте логику приложения в контроллерах.
- Создайте папку «controllers» и в ней создайте файл
activity.controller.js
. - Нам нужно реализовать две вещи — 1) Получить все активности для показа на главной странице и 2) Добавить активность.
const Activity = require("../models/activity.model"); /** * It's an async function that uses the Activity model to find all activities and then returns a status of 200 with the activities in the response body. */ const getActivities = async (req, res) => { try { const activities = await Activity.find(); res.status(200).json(activities); } catch (err) { res.status(500).json({ message: err.message }); } }; /** * It creates a new activity and saves it to the database. */ const addActivity = async (req, res) => { const activity = new Activity(req.body); try { const newActivity = await activity.save(); res.status(201).json(newActivity); } catch (err) { res.status(400).json({ message: err.message }); } }; module.exports = { getActivities, addActivity, };
- Создайте папку «controllers» и в ней создайте файл
-
Зарегистрируйте маршруты для обработки запросов.
- Создайте папку «routes» и в ней создайте файл
activity.route.js
. Скопируйте и вставьте приведенный ниже код.
const express = require("express"); const { getActivities, addActivity, } = require("../controllers/activity.controller"); const router = express.Router(); /* Creating a route for the get request. */ router.get("/activities", getActivities); /* Creating a route for the post request. */ router.post("/activity", addActivity); module.exports = router;
- Создайте папку «routes» и в ней создайте файл
-
Окончательная структура папки будет выглядеть следующим образом.
. ├── controllers │ └── activity.controller.js ├── models │ └── activity.model.js ├── routes │ └── activity.route.js ├── package-lock.json ├── package.json └── server.js
-
Используйте вышеуказанные маршруты в приложении.
- Откройте файл
server.js
и используйте зарегистрированные маршруты.
... const ActivityRouter = require("./routes/activity.route"); ... ... /* Telling the application to use the ActivityRouter for any requests that start with "/api". */ app.use("/api", ActivityRouter); ...
- Откройте файл
-
Теперь наш бэкенд полностью готов к работе; мы можем добавлять и получать данные. Давайте рассмотрим, как подключить бэкэнд к фронтэнду.
Подключение клиента и сервера
Подключить клиента и сервер несложно. Это так же просто, как добавить URL.
-
Перейдите в папку клиента и создайте файл
.env.local
. Вставьте URL-адрес бэкенда в переменную.REACT_APP_BACKEND_URL=http://localhost:5000/api
-
Перейдите в папку клиента и откройте
App.js
. Когда пользователь нажмет кнопку Add, мы должны сделать POST-запрос к серверу через маршрут/api/activity
.- Создайте функцию
handleSubmit()
и добавьте атрибутonSubmit
к элементу формы. -
В этой функции мы должны отправить запрос на сервер, передав в теле имя активности и время.
... const addActivity = async (event) => { event.preventDefault(); const newActivity = { name: event.target.activity.value, time: event.target.time.value, }; await fetch(`${process.env.REACT_APP_BACKEND_URL}/activity`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(newActivity), }); event.target.activity.value = ""; // sets input empty after clicking submit event.target.time.value = ""; // sets input empty after clicking submit window.location.reload(); // reloads the window after sending request }; ... ... <form onSubmit={addActivity}> ...
- Создайте функцию
-
Введите имя активности и время, затем отправьте запрос. (Убедитесь, что сервер также запущен.)
-
В консоли браузера появится сообщение об ошибке.
-
Доступ к серверу запрещен политикой CORS (Cross-Origin Resource Sharing), что означает, что ваш сервер не разрешает доступ к своим ресурсам. Мы можем избежать этой проблемы, используя пакет cors npm.
- Откройте папку сервера и установите пакет cors.
npm i cors
- Затем используйте этот пакет в
server.js
.
... const cors = require("cors"); ... ... /* Allowing the frontend to access the backend. */ app.use(cors()); ...
- Перезапустите сервер.
-
Попробуйте добавить активность. На этот раз все сработает.
-
Вы можете видеть данные, которые были добавлены в базу данных.
-
Теперь мы должны отобразить список недавно добавленных активностей.
- Мы должны отображать активности сразу после рендеринга компонента. Мы можем сделать это с помощью хука
useEffect()
. Получите данные с сервера и сохраните их в состоянии.
... /* Fetching the data from the backend and setting the state of activities to the data. */ useEffect(() => { const fetchData = async () => { const result = await fetch( `${process.env.REACT_APP_BACKEND_URL}/activities` ); const data = await result.json(); setActivities(data); }; fetchData(); }, []); ...
- Теперь вы можете увидеть все активности на главной странице.
- Мы должны отображать активности сразу после рендеринга компонента. Мы можем сделать это с помощью хука
Размещение полнофункционального приложения на хостинге
Перед хостингом мы должны сохранить секреты и избежать фиксации ненужных файлов/папок.
- Откройте папку сервера.
- Инициализируйте git, создайте файл
.gitignore
и вставьте в него следующее.
node_modules
.env
Бэкенд
Для бэкенда будет использоваться Heroku.
- Создайте репозиторий GitHub для серверного приложения и разместите в нем код сервера.
- Войдите в Heroku.
- Выберите «New» -> «Create new app».
- Дайте приложению имя, выберите регион, а затем нажмите «Создать приложение».
- Перейдите в «Настройки» -> «Конфигурационные параметры» -> «Раскрыть конфигурационные параметры» -> «Добавить переменные среды».
- Перейдите в раздел «Обзор» и выберите GitHub в качестве механизма развертывания. Если вы еще этого не сделали, зарегистрируйтесь на GitHub.
- Выберите свой репозиторий.
- Выберите «Enable Automatic Deploys», если вы хотите создавать развертывание каждый раз, когда вы фиксируете репозиторий. Наконец, нажмите «Deploy Branch».
- Запишите URL-адрес развернутого сайта.
Фронтенд
Netlify будет размещать нашу клиентскую/фронтенд часть.
- Создайте репозиторий GitHub для клиентского приложения и разместите в нем код клиента.
- Войдите в Netlify.
- Выберите «Добавить сайт».
- Выберите «GitHub».
- Дайте разрешение GitHub.
-
Выберите свой репозиторий.
-
В «Основных настройках сборки»,
- Для базового каталога — Оставьте пустым.
- Для команды сборки —
npm run build
. - Для каталога публикации — «build».
-
Выберите «Show advanced» -> «New variable» В поле key введите
REACT_APP_BACKEND_URL
и скопированный ранее URL бэкенда в поле value. В конце URL-адреса поставьте /api. -
Выберите «Развернуть сайт».
-
Вот и все! Откройте URL в браузере и получайте удовольствие 🎉🎉🎉.
Добавьте свои собственные функции и поделитесь URL в комментариях.
Читайте также:
- Поток построения полностекевого веб-приложения
- Различные способы соединения react frontend и node backend
Надеюсь, это дало вам представление о том, как разработать полнофункциональное MERN-приложение. Следите за мной, чтобы узнать больше 🚀🚀🚀.
Не забудьте подписаться на мою рассылку.
Спасибо!