手把手教你用 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 可执行文件并运行。

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

相关推荐
why技术33 分钟前
也是出息了,业务代码里面也用上算法了。
java·后端·算法
白仑色2 小时前
完整 Spring Boot + Vue 登录系统
vue.js·spring boot·后端
ZhangApple4 小时前
微信自动化工具:让自己的微信变成智能机器人!
前端·后端
Codebee4 小时前
OneCode 3.0: 注解驱动的Spring生态增强方案
后端·设计模式·架构
bobz9654 小时前
kubevirt virtinformers
后端
LuckyLay4 小时前
Django专家成长路线知识点——AI教你学Django
后端·python·django
Java微观世界4 小时前
征服Java三大特性:封装×继承×多态+this/super高阶指南
后端
Java技术小馆4 小时前
RPC vs RESTful架构选择背后的技术博弈
后端·面试·架构
凌览5 小时前
因 GitHub 这个 31k Star 的宝藏仓库,我的开发效率 ×10
前端·javascript·后端