手把手教你用 React 和 Go 部署全栈项目

手把手教你用 React 和 Go 部署全栈项目

在本指南中,我们将学习如何结合使用 React (通过 Vite) 构建前端用户界面,并使用 Go (Golang) 创建一个高效的后端服务来提供静态文件。这种架构非常适合构建单页应用 (SPA),其中前端负责所有 UI 逻辑,而后端则提供数据和静态资源。

所有源码可以在这里找到:github.com/yincongcyin...

前端部分:使用 React (Vite)

我们将使用 Vite 来快速启动一个 React 项目。Vite 是一个现代化的前端构建工具,提供极速的开发体验和优化的生产构建。

1. 创建 React 项目

首先,打开你的终端或命令行工具,运行以下命令来创建一个新的 React 项目:

Bash

sql 复制代码
npm create vite@latest my-react-app -- --template react
  • npm create vite@latest: 这是一个 npm 命令,用于使用最新版本的 Vite 创建一个新项目。
  • my-react-app: 这是你的项目文件夹的名称。你可以将其替换为你喜欢的任何名称。
  • --template react: 这告诉 Vite 使用 React 模板来初始化项目。

2. 进入项目目录

项目创建完成后,你需要进入到新创建的项目目录中:

Bash

bash 复制代码
cd my-react-app

3. 安装依赖

在项目目录中,安装项目所需的全部 Node.js 依赖:

Bash

复制代码
npm install

这会根据 package.json 文件中的定义安装所有必要的库。

4. 构建前端静态文件

当你准备好部署前端应用时,你需要将其构建为生产就绪的静态文件。运行以下命令:

Bash

arduino 复制代码
npm run build

此命令将会在项目根目录下创建一个 dist 文件夹,其中包含所有优化的 HTML、CSS 和 JavaScript 文件。这些文件就是你的前端应用的静态资产。

5. 移动前端静态文件到目标路径

为了让 Go 后端能够提供这些静态文件,你需要将 dist 文件夹中的内容移动到 Go 项目可以访问的位置。假设你的 Go 项目在 my-react-app 的父目录中,并且 Go 项目的静态文件目录名为 test,你可以使用以下命令:

Bash

bash 复制代码
mv dist/* ../../test
  • mv dist/*: 将 dist 目录下的所有文件和文件夹移动。
  • ../../test: 这是目标路径,表示从当前目录向上两级,然后进入名为 test 的目录。请根据你的实际项目结构调整此路径。

后端部分:使用 Go 提供静态文件

Go 后端将负责托管前端的静态文件,并在所有非静态文件请求时提供 index.html,这对于单页应用至关重要。

Go 项目结构

确保你的 Go 项目中有一个名为 test 的文件夹,用于存放 React 构建后的静态文件。例如:

go 复制代码
your-go-project/
├── main.go
└── test/
    ├── index.html
    ├── assets/
    └── ... (其他 React 构建的文件)

Go 代码解析

以下是你的 Go 后端代码,我们将逐一解释其关键部分:

Go

go 复制代码
package main

import (
	"bytes"
	"embed"
	"io/fs"
	"net/http"
	"time"
)

//go:embed test/*
var staticFiles embed.FS
  • //go:embed test/* : 这是一个 Go 编译器的指令。它告诉编译器将 test 目录下的所有文件和子目录嵌入到最终编译的二进制文件中。这意味着你的 Go 应用运行时,不再需要外部的 test 文件夹,所有的前端静态文件都打包在 Go 可执行文件中。
  • var staticFiles embed.FS : 声明一个 embed.FS 类型的变量 staticFiles,它将存储嵌入的文件系统。

Go

scss 复制代码
func View() http.HandlerFunc {
	distFS, _ := fs.Sub(staticFiles, "test")

	staticHandler := http.FileServer(http.FS(distFS))

	return func(w http.ResponseWriter, r *http.Request) {
		if fileExists(distFS, r.URL.Path[1:]) {
			staticHandler.ServeHTTP(w, r)
			return
		}

		fileBytes, err := fs.ReadFile(distFS, "index.html")
		if err != nil {
			http.Error(w, "index.html not found", http.StatusInternalServerError)
			return
		}

		reader := bytes.NewReader(fileBytes)
		http.ServeContent(w, r, "index.html", time.Now(), reader)
	}
}
  • func View() http.HandlerFunc : 定义了一个返回 http.HandlerFunc 的函数,这将作为 HTTP 请求的处理程序。
  • distFS, _ := fs.Sub(staticFiles, "test") : 创建一个 fs.FS 接口的子集,使其只暴露 test 目录下的文件。这是因为 embed 会将 test 本身作为根目录的一部分嵌入,所以我们需要一个子集来正确地提供文件。
  • staticHandler := http.FileServer(http.FS(distFS)) : 创建一个标准的 Go http.FileServer,它会从 distFS 中查找和提供文件。
  • if fileExists(distFS, r.URL.Path[1:]) : 对于每个传入的请求,它首先检查请求的路径(去除开头的 /)是否对应一个实际存在于嵌入文件系统中的文件。
  • staticHandler.ServeHTTP(w, r) : 如果文件存在,就由 staticHandler 来处理并返回该文件。
  • fileBytes, err := fs.ReadFile(distFS, "index.html") : 如果请求的路径不是一个具体的文件(例如,用户直接访问 / 或刷新了应用的内部路由),则尝试读取 index.html。这对于单页应用至关重要,因为 React 路由通常在客户端处理,所有路由都应该返回 index.html
  • http.ServeContent(w, r, "index.html", time.Now(), reader) : 将 index.html 的内容作为响应返回给客户端。

Go

go 复制代码
func fileExists(fsys fs.FS, path string) bool {
	f, err := fsys.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()
	info, err := f.Stat()
	if err != nil || info.IsDir() {
		return false
	}
	return true
}
  • fileExists 函数: 这是一个辅助函数,用于检查给定路径的文件是否存在且不是一个目录。

Go

go 复制代码
func main() {
	http.Handle("/", View())

	err := http.ListenAndServe(":18888", nil)
	if err != nil {
		panic(err)
	}
}
  • http.Handle("/", View()) : 将根路径 (/) 的所有请求都交给 View() 函数返回的处理器处理。
  • http.ListenAndServe(":18888", nil) : 启动 HTTP 服务器,监听 18888 端口。nil 表示使用默认的 ServeMux

运行 Go 后端

在 Go 项目的根目录下(与 main.go 文件同级),运行以下命令来启动 Go 服务器:

Bash

go 复制代码
go run main.go

现在,你的 Go 后端将会在 http://localhost:18888 监听请求,并提供你的 React 前端应用。


部署流程总结

  1. 开发 React 前端 : 在 my-react-app 目录中进行 React 开发,并使用 npm run dev 进行本地开发和测试。
  2. 构建 React 前端 : 准备部署时,运行 npm run build 生成生产就绪的静态文件到 dist 目录。
  3. 移动静态文件 : 将 dist 目录中的内容移动到 Go 项目的 test 目录。
  4. 运行 Go 后端 : 在 Go 项目目录中运行 go run main.go 或构建 Go 可执行文件并运行。

通过这个设置,你就可以拥有一个高效且易于部署的全栈应用程序。

相关推荐
蚂蚁背大象36 分钟前
Rust 所有权系统是为了解决什么问题
后端·rust
子玖2 小时前
go实现通过ip解析城市
后端·go
Java不加班2 小时前
Java 后端定时任务实现方案与工程化指南
后端
心在飞扬3 小时前
RAG 进阶检索学习笔记
后端
Moment3 小时前
想要长期陪伴你的助理?先从部署一个 OpenClaw 开始 😍😍😍
前端·后端·github
Das1_3 小时前
【Golang 数据结构】Slice 底层机制
后端·go
得物技术3 小时前
深入剖析Spark UI界面:参数与界面详解|得物技术
大数据·后端·spark
古时的风筝3 小时前
花10 分钟时间,把终端改造成“生产力武器”:Ghostty + Yazi + Lazygit 配置全流程
前端·后端·程序员
Cache技术分享3 小时前
340. Java Stream API - 理解并行流的额外开销
前端·后端