Привет, Хабр!
В современной веб-разработке перед разработчиком в основном стоит задача создать приложения, которые не только быстро загружаются, но и дают плавный пользовательский опыт. Сочетание Next.js и Go предлагает мощное решение для этой задачи.
Next.js, с его возможностями статической генерации и серверного рендеринга, позволяет создавать высокопроизводительные интерфейсы, которые легко оптимизируются для поисковых систем. Go, в свою очередь, дает надежный бэкенд, способный обрабатывать множество запросов одновременно.
В этой статье рассмотрим, как интеграция этих двух технологий может помочь вам построить динамические сайты.
Создание статического сайта на Next.js
Первым делом создадим новый проект с помощью команды create-next-app
.
Открываем терминал и выполняем следующую команду:
npx create-next-app my-static-site cd my-static-site
Эта команда создаст новую директорию my-static-site
, где будет располагаться проект. Далее переходим в эту директорию.
После инициализации проекта можно увидеть следующую структуру:
my-static-site/ ├── node_modules/ ├── public/ ├── styles/ │ └── Home.module.css ├── pages/ │ ├── api/ │ ├── _app.js │ ├── index.js └── package.json
-
public/: здесь можно хранить статические файлы, такие как изображения или шрифты.
-
styles/: папка для CSS-стилей вашего приложения.
-
pages/: это сердце приложения, где каждая JavaScript-файл соответствует маршруту. Например,
index.js
— это корневой маршрут, аapi/
— для API-роутов.
Теперь реализуем статическую генерацию с помощью методов getStaticProps
и getStaticPaths
.
Методы статической генерации
getStaticProps
: позволяет извлекать данные во время сборки, что означает, что страницы будут предгенерированы с данными. Это в чем-то улучшает SEO и скорость загрузки.
Пример использования getStaticProps
:
// pages/index.js export async function getStaticProps() { const res = await fetch('https://api.example.com/data'); const data = await res.json(); return { props: { data, }, }; } const Home = ({ data }) => { return ( <div> <h1>Статический сайт на Next.js</h1> <ul> {data.map(item => ( <li>{item.title}</li> ))} </ul> </div> ); }; export default Home;
Здесь делаем запрос к API и передаем данные в компонент в качестве пропсов.
getStaticPaths
: используется для динамической генерации страниц на основе параметров маршрута.
Пример использования getStaticPaths
:
// pages/posts/[id].js export async function getStaticPaths() { const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); const paths = posts.map(post => ({ params: { id: post.id.toString() }, })); return { paths, fallback: false }; } export async function getStaticProps({ params }) { const res = await fetch(`https://api.example.com/posts/${params.id}`); const post = await res.json(); return { props: { post, }, }; } const Post = ({ post }) => { return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> ); }; export default Post;
В этом примере генерируем страницы для каждого поста на основе данных из API. getStaticPaths
создает массив путей, а getStaticProps
получает данные для конкретного поста.
Следующий шаг — использование динамических маршрутов для загрузки данных. Для этого создадим API-роут, который будет возвращать данные, а затем интегрируем его в сайт.
Создадим файл pages/api/posts.js
:
// pages/api/posts.js export default async function handler(req, res) { const response = await fetch('https://api.example.com/posts'); const posts = await response.json(); res.status(200).json(posts); }
Теперь есть API, который возвращает список постов. Можно использовать его в приложении.
Чтобы загружать данные асинхронно, можно использовать fetch
в useEffect
в компоненте:
import { useEffect, useState } from 'react'; const DynamicContent = () => { const [posts, setPosts] = useState([]); useEffect(() => { const fetchData = async () => { const res = await fetch('/api/posts'); const data = await res.json(); setPosts(data); }; fetchData(); }, []); return ( <div> <h2>Динамические посты</h2> <ul> {posts.map(post => ( <li>{post.title}</li> ))} </ul> </div> ); }; export default DynamicContent;
Важно обрабатывать ошибки при работе с API. Можно использовать блоки try/catch
в функциях:
try { const res = await fetch('/api/posts'); if (!res.ok) throw new Error('Ошибка сети'); const data = await res.json(); setPosts(data); } catch (error) { console.error('Ошибка при загрузке данных:', error); }
Интеграция с Go: настройка серверной части
Добавим Gin в зависимости:
go get -u github.com/gin-gonic/gin
Теперь можно приступить к созданию API. Создаем файл main.go
и добавляем следующий код:
package main import ( "github.com/gin-gonic/gin" "net/http" ) type Post struct { ID string `json:"id"` Title string `json:"title"` Body string `json:"body"` } var posts = []Post{ {ID: "1", Title: "Post 1", Body: "This is the body of post 1."}, {ID: "2", Title: "Post 2", Body: "This is the body of post 2."}, } func main() { r := gin.Default() r.GET("/api/posts", getPosts) r.GET("/api/posts/:id", getPostByID) r.Run(":8080") // Запускаем сервер на порту 8080 } func getPosts(c *gin.Context) { c.JSON(http.StatusOK, posts) } func getPostByID(c *gin.Context) { id := c.Param("id") for _, post := range posts { if post.ID == id { c.JSON(http.StatusOK, post) return } } c.JSON(http.StatusNotFound, gin.H{"message": "post not found"}) }
Создали два маршрута: один для получения всех постов, а другой для получения поста по ID. Если пост не найден, возвращаем статус 404 и сообщение об ошибке.
Теперь, когда API готов, посмотрим, как обращаться к нему из приложения Next.js.
Предположим, нужно получить список постов. Открываем файл pages/index.js
Next.js приложения и добавляем следующий код:
import { useEffect, useState } from 'react'; const Home = () => { const [posts, setPosts] = useState([]); useEffect(() => { const fetchPosts = async () => { try { const res = await fetch('http://localhost:8080/api/posts'); if (!res.ok) throw new Error('Ошибка при получении данных'); const data = await res.json(); setPosts(data); } catch (error) { console.error('Ошибка:', error); } }; fetchPosts(); }, []); return ( <div> <h1>Посты</h1> <ul> {posts.map(post => ( <li>{post.title}</li> ))} </ul> </div> ); }; export default Home;
Не забываем обратить внимание на обработку ошибок при выполнении запроса. Если сервер возвращает ошибку, мы выводим сообщение в консоль. Это важно для отладки и информирования пользователя о проблемах.
Вместо встроенного fetch
можно использовать библиотеку Axios для выполнения HTTP-запросов. Установим Axios:
npm install axios
Затем изменяем код на следующий:
import axios from 'axios'; import { useEffect, useState } from 'react'; const Home = () => { const [posts, setPosts] = useState([]); useEffect(() => { const fetchPosts = async () => { try { const { data } = await axios.get('http://localhost:8080/api/posts'); setPosts(data); } catch (error) { console.error('Ошибка:', error); } }; fetchPosts(); }, []); return ( <div> <h1>Посты</h1> <ul> {posts.map(post => ( <li>{post.title}</li> ))} </ul> </div> ); }; export default Home;
Безопасность API — это очень важно. Один из простых способов — использовать токены JWT для аутентификации пользователей. Можно использовать пакет github.com/dgrijalva/jwt-go
для работы с JWT.
Для установки:
package main import ( "github.com/gin-gonic/gin" "net/http" ) type Post struct { ID string `json:"id"` Title string `json:"title"` Body string `json:"body"` } var posts = []Post{ {ID: "1", Title: "Post 1", Body: "This is the body of post 1."}, {ID: "2", Title: "Post 2", Body: "This is the body of post 2."}, } func main() { r := gin.Default() r.GET("/api/posts", getPosts) r.GET("/api/posts/:id", getPostByID) r.Run(":8080") // Запускаем сервер на порту 8080 } func getPosts(c *gin.Context) { c.JSON(http.StatusOK, posts) } func getPostByID(c *gin.Context) { id := c.Param("id") for _, post := range posts { if post.ID == id { c.JSON(http.StatusOK, post) return } } c.JSON(http.StatusNotFound, gin.H{"message": "post not found"}) }
Для обеспечения взаимодействия между Next.js приложением и API на Go, нужно настроить CORS. Это можно сделать с помощью встроенного middleware в Gin.
Добавляем следующую строку в main.go
:
r.Use(cors.Default())
Для этого потребуется установить пакет CORS:
go get -u github.com/gin-contrib/cors
Теперь API сможет обрабатывать запросы из Next.js приложения.
Не бойтесь экспериментировать с новыми функциями и расширять проект.
Освоить профессию Fullstack‑разработчика на JavaScript можно на специализации «Fullstack developer».
ссылка на оригинал статьи https://habr.com/ru/articles/845198/
Добавить комментарий