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
相关推荐
程序媛-徐师姐17 分钟前
Java 基于SpringBoot+vue框架的老年医疗保健网站
java·vue.js·spring boot·老年医疗保健·老年 医疗保健
余道各努力,千里自同风1 小时前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave1 小时前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟1 小时前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
chusheng18402 小时前
Java项目-基于SpringBoot+vue的租房网站设计与实现
java·vue.js·spring boot·租房·租房网站
游走于计算机中摆烂的2 小时前
启动前后端分离项目笔记
java·vue.js·笔记
幼儿园的小霸王3 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
码蜂窝编程官方3 小时前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
乐闻x4 小时前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化