3

I have looked around and cannot find a solution for what I have in hands at the moment.

I have a go project I am setting up (deployed into a docker image) and I have some HTML templating that needs to be done. The templating part works well using the embed declaration, however the same does not seem to work for the files that the HTML requires, e.g., css files.

Here is a simple example I have setup in order to try to play with embed and see what is going wrong, but no luck.

Project directory

|
|- main.go
\- templates
  |- page.html
  \- static
    |- style.css
    \- stylesheets
      \- style.css (preferred location)

main.go

package main

import (
    "embed"
    "net/http"
    "simple-server/handlers"
)

//go:embed templates
var templatesFs embed.FS

//go:embed templates/static
var staticFiles embed.FS

func main() {
    http.Handle("/hello", handlers.HelloHandler{
        TemplatesFs: templatesFs,
    })

    http.Handle(
        "/static/",
        // the following works
        http.FileServer(http.Dir("./templates")),
        // the following does not work
        //http.StripPrefix("/static/", http.FileServer(http.FS(staticFiles))),
    )

    err := http.ListenAndServe(":8001", nil)
    if err != nil {
        panic(err)
    }
}

hello.go

package handlers

import (
    "embed"
    "fmt"
    "html/template"
    "net/http"
)

type HelloHandler struct {
    TemplatesFs embed.FS
}

func (h HelloHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    tmpl, err := template.ParseFS(h.TemplatesFs, "templates/page.html")
    if err != nil {
        fmt.Printf("failed to parse the template: %s", err)

        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    err = tmpl.ExecuteTemplate(w, "page.html", nil)
    if err != nil {
        fmt.Printf("failed to execute the template: %s", err)

        w.WriteHeader(http.StatusInternalServerError)
        return
    }
}

page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/style.css">
    <title>Session {{ .Number }}</title>
</head>
<body>
<div class="text">Page HTML template</div>
</body>
</html>

style.css

.text {
    color: #0088ff;
}

As per the comment on the main.go file, if the file is served through http.Dir, it works. But this is going to be served through a docker file, so I need the http.FileServer(http.FS(staticFiles)), however in doing so, the style.css file always returns a 404.

Am I missing something? What is it?

Many thanks in advance 👍

1 Answer 1

4

It is probably taking relative path corresponding to where is it created and NOT the root of your embedded filesystem. So I feel the issue is at http.FS(staticFiles)

May be you can first create a fileSystem rooted at templates/static, like following

staticFs, err := fs.Sub(staticFiles, "templates/static")
// Handle the err

and then do

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFs))))

Let me know if it works or not!

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, this does solve the issue. I had further issues which were related to the fact I was using Gorilla Mux on my project and that was the crux of it. This post which I only found today allowed me to solve all my problems. Marking this as the accepted answer since I was unaware the example I did at the time was not reflecting the entirety of my setup and it's not your fault.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.