Gin 打包vue或react项目输出文件到程序二进制文件

Gin 打包vue或react项目输出文件到程序二进制文件

  • 背景
  • 解决方案
    • [1. 示例目录结构](#1. 示例目录结构)
    • [2. 有如下问题要解决:](#2. 有如下问题要解决:)
    • [3. 方案探索](#3. 方案探索)
  • 效果

背景

前后端分离已成为行业主流,vuereact等项目生成的文件独立在一个单独目录,与后端项目无关。

实际部署中,通常前面套一个nginx,根据请求返回静态资源或者代理到后端go服务上。

安装配置一套环境繁琐,加上有时需要部署在windows上,希望借助go的夸平台编译运行+embed嵌入文件能力,实现单个文件部署即可。
Created with Raphaël 2.3.0 用户请求 nginx 是否是静态资源? dist目录文件 go-app yes no

nginx配置样例

config 复制代码
server {
    listen 80;
    root /usr/share/nginx/html;
    location / {
        try_files $uri $uri/index.html /index.html;
    }
    location /api {
        proxy_pass http://localhost/to-go-app-server;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   X-Real-IP         $remote_addr;
    }
}

解决方案

1. 示例目录结构

  • app.go为代码文件,同dist一个目录
  • app-server为编译后的单个exe
复制代码
.
├── app.go
├── app-server
└── dist
    ├── assets
    │   ├── index-43d6e8d0.css
    │   └── index-f5e49ae2.js
    ├── CNAME
    ├── element-plus-logo-small.svg
    ├── favicon.svg
    ├── index.html
    └── vite.svg

2. 有如下问题要解决:

  • http://exmpale.com/跟路由如何定向到dist/index.html
  • http://exmpale.com/xx.svg 以及 http://exmpale.com/assets/xxxxx.js 这些动态路由如何生成
  • http://exmpale.com/正常业务路由与上面静态文件路由冲突如何处理

3. 方案探索

经过参考gin官方github.com/gin-contrib/static的插件,找出以下简单有效的解决方案

  • 使用embed将整个文件夹嵌入
  • 所有请求增加一个中间件, 判断embed.FS总是否存在url中路径的文件
  • 存在使用http.fileserver处理,并中断处理链
  • 不存在处理正常的逻辑
go 复制代码
package main

import (
	"embed"
	"io/fs"
	"net/http"

	"github.com/gin-gonic/gin"
)

//go:embed dist
var dist embed.FS

func main() {
	r := gin.Default()
	r.Use(ServerStatic("dist", dist))

	r.GET("/ping", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "pong")
	})
	r.Run("localhost:81")
}

/*
假设vue/react项目输出文件夹名字为dist,拷贝到该go文件所在目录下
注意"dist"前后不能有 /
r.Use(ServerStatic("dist", dist))
*/
func ServerStatic(prefix string, embedFs embed.FS) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 去掉前缀
		fsys, err := fs.Sub(embedFs, prefix)
		if err != nil {
			panic(err)
		}
		fs2 := http.FS(fsys)
		f, err := fs2.Open(ctx.Request.URL.Path)
		if err != nil {
			// 判断文件不存在,退出交给其他路由函数
			ctx.Next()
			return
		}
		defer f.Close()
		http.FileServer(fs2).ServeHTTP(ctx.Writer, ctx.Request)
		ctx.Abort()
	}
}

效果

  • 访问http://localhost:81/ 返回的是vue页面
  • 访问http://localhost:81/ping 返回的是逻辑处理结果pong
相关推荐
小信丶13 小时前
解决 pnpm dev 报错:系统禁止运行脚本的问题
前端·vue.js·windows·npm
苏打水com14 小时前
第十六篇:Day46-48 前端安全进阶——从“漏洞防范”到“安全体系”(对标职场“攻防实战”需求)
前端·javascript·css·vue.js·html
前端无涯14 小时前
react组件(2)---State 与生命周期
前端·react.js
AY呀14 小时前
Vite:现代前端构建工具的革命与实战指南
前端·vue.js·vite
重铸码农荣光14 小时前
用AI把猫主子变成冰球猛将?我搞了个“宠物拟人化”神器,结果……它真敢打!
vue.js·低代码·coze
前端无涯14 小时前
react组件(3)---组件间的通信
前端·react.js
前端无涯14 小时前
react组件(1)---从入门到上手
react.js·前端框架
hid5588453615 小时前
深度学习之噬菌体特异性蛋白质预测:代码实现与解析
gin
m0_7400437316 小时前
3、Vuex-Axios-Element UI
前端·javascript·vue.js
风止何安啊16 小时前
一场组件的进化脱口秀——React从 “类” 到 “hooks” 的 “改头换面”
前端·react.js·面试