从嵌入文件夹调用JS、CSS和IMG资源的Golang实践

从嵌入文件夹调用JS、CSS和IMG资源的Golang实践 借助新的 embed 包,我能够嵌入我的文件,并按如下方式调用我的模板:

// inner/embed.go

package inner

import (
	"embed"
)

// Content 是我们的静态 Web 服务器内容。
//go:embed configuration template layout
var Content embed.FS //  以 '.' 或 '_' 开头的文件会被排除


// web/Bayan.go
package web

import (
	"fmt"
	"hasan/embed/inner"
	"html/template"
	"log"
	"net/http"
	"os"

	"gopkg.in/yaml.v2"
)

// Config ...
type Config struct {
	Server struct {
		Port string `yaml:"port"`
		Host string `yaml:"host"`
	} `yaml:"server"`
	Database struct {
		Username string `yaml:"user"`
		Password string `yaml:"pass"`
	} `yaml:"database"`
}

func processError(err error) {
	fmt.Println(err)
	os.Exit(2)
}
func readFile(cfg *Config, lang string) {
	data, err := inner.Content.ReadFile("configuration/bayan-" + lang + ".yml")
	if err != nil {
		log.Fatal(err)
	}
	// fmt.Println(string(data))
	err = yaml.Unmarshal([]byte(data), &cfg)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	fmt.Printf("%+v\n", cfg)
	fmt.Printf("%+v\n", cfg.Database.Username)
}

// Bayan ...
func Bayan(w http.ResponseWriter, r *http.Request) {
	var cfg Config
	var lng string
	lang, err := r.Cookie("language")
	if err != nil {
		lng = "ar"
	} else {
		lng = lang.Value
	}
	readFile(&cfg, lng)

	var tmpl *template.Template

	tmpl, err = template.ParseFS(inner.Content, "layout/layout.html", fmt.Sprint("template/bayan-", lng, ".html"))
	if err != nil {
		fmt.Println(err)
	}

	//tmpl, err := template.New("").ParseFiles(fmt.Sprint("template/bayan-en.html"), "base.html")
	//tmpl, err := template.ParseFiles(fmt.Sprint(http.FS(inner.Content), "/layout/layout.html"))
	// or
	//tmpl := template.Must(template.ParseFiles("layout/layout.html"))

	//tmpl.Execute(w, "data goes here, this is Hasan")
	tmpl.ExecuteTemplate(w, "base", "hi")
	if err != nil {
		fmt.Println(err)
	}
}


// main.go
package main

import (
	"fmt"
	"hasan/embed/inner"
	"hasan/embed/web"
	"net/http"

	_ "embed"

	"github.com/zserge/lorca"
)

func main() {
	port := "8090"
	go func() {
		http.HandleFunc("/bayan", web.Bayan)
		http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(inner.Content))))
		http.ListenAndServe(":"+port, nil)
	}()
	// Start UI
	ui, err := lorca.New("http://localhost:8090/bayan", "", 1200, 800)
	if err != nil {
		fmt.Println("error:", err)
	}
	defer ui.Close()

	<-ui.Done()
}

我的嵌入文件位于 inner 文件夹中,结构如下:

enter image description here

我的问题是,如何在模板中调用 JavaScriptCSSimg 文件。 例如,现在如何替换模板中的 <link href="/styles/fontawesome-free-5.15.2-web/css/all.css" rel="stylesheet">


更多关于从嵌入文件夹调用JS、CSS和IMG资源的Golang实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于从嵌入文件夹调用JS、CSS和IMG资源的Golang实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中通过embed包嵌入静态资源后,可以通过http.FileServer提供静态文件服务。以下是具体实现示例:

// main.go中修改静态文件路由配置
func main() {
    port := "8090"
    go func() {
        http.HandleFunc("/bayan", web.Bayan)
        
        // 提供静态文件服务
        http.Handle("/styles/", http.StripPrefix("/styles/", 
            http.FileServer(http.FS(inner.Content))))
        http.Handle("/js/", http.StripPrefix("/js/", 
            http.FileServer(http.FS(inner.Content))))
        http.Handle("/img/", http.StripPrefix("/img/", 
            http.FileServer(http.FS(inner.Content))))
        
        http.ListenAndServe(":"+port, nil)
    }()
    // ... 其余代码不变
}

在模板中直接使用相对路径引用资源:

<!-- layout/layout.html -->
<!DOCTYPE html>
<html>
<head>
    <!-- 引用CSS文件 -->
    <link href="/styles/fontawesome-free-5.15.2-web/css/all.css" rel="stylesheet">
    <link href="/styles/main.css" rel="stylesheet">
</head>
<body>
    {{template "content" .}}
    
    <!-- 引用JavaScript文件 -->
    <script src="/js/main.js"></script>
    
    <!-- 引用图片 -->
    <img src="/img/logo.png" alt="Logo">
</body>
</html>

如果资源文件位于子目录中,需要确保embed指令包含所有相关目录:

// inner/embed.go
package inner

import (
    "embed"
)

//go:embed configuration template layout styles js img
var Content embed.FS

对于动态生成的模板路径,可以在模板函数中处理:

// web/Bayan.go中修改模板处理
func Bayan(w http.ResponseWriter, r *http.Request) {
    // ... 配置读取代码不变
    
    // 创建带自定义函数的模板
    funcMap := template.FuncMap{
        "static": func(path string) string {
            return "/" + path
        },
    }
    
    tmpl, err := template.New("").Funcs(funcMap).ParseFS(
        inner.Content, 
        "layout/layout.html", 
        fmt.Sprintf("template/bayan-%s.html", lng),
    )
    if err != nil {
        fmt.Println(err)
        return
    }
    
    tmpl.ExecuteTemplate(w, "base", nil)
}

然后在模板中使用自定义函数:

<!-- 在模板中 -->
<link href="{{static "styles/fontawesome-free-5.15.2-web/css/all.css"}}" rel="stylesheet">

如果需要处理版本控制或缓存问题,可以添加时间戳参数:

funcMap := template.FuncMap{
    "static": func(path string) string {
        // 添加构建时间戳作为查询参数
        return "/" + path + "?v=" + buildTimestamp
    },
}

确保文件系统结构匹配URL路径。如果资源文件位于styles/fontawesome-free-5.15.2-web/css/目录下,那么对应的URL路径就是/styles/fontawesome-free-5.15.2-web/css/all.css

回到顶部