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

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

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

背景

前后端分离已成为行业主流,vuereact等项目生成的文件独立在一个单独目录,与后端项目无关。
实际部署中,通常前面套一个nginx,根据请求返回静态资源或者代理到后端go服务上。
安装配置一套环境繁琐,加上有时需要部署在windows上,希望借助go的夸平台编译运行+embed嵌入文件能力,实现单个文件部署即可。

Created with Raphaël 2.3.0 用户请求 nginx 是否是静态资源? dist目录文件 go-app yes no

nginx配置样例

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处理,并中断处理链
  • 不存在处理正常的逻辑
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
    Gin 打包vue或react项目输出文件到程序二进制文件_第1张图片

你可能感兴趣的:(gin,vue.js,react.js)