Golang correct filepath to serve css files - go

I have been reading and trying to serve css css files to my html page and nothing has been working . I have been reading this https://forum.golangbridge.org/t/serving-static-css-files/2051/10 to get a better understanding . My project structure is below
func WebRoutes(r *mux.Router) {
r.HandleFunc("/", Index)
// Trying to serve file here and it's not working
r.Handle("/web/content/desktop/", http.StripPrefix("/web/content/desktop/", http.FileServer(http.Dir("desktop"))))
// Below is the correct path since it finds the file
_, err := os.Stat(filepath.Join(".", "/web/content/desktop/", "page.css"))
if err != nil {
println(err.Error())
}
}
I am referencing the file from my html page like this
<link rel="stylesheet" type="text/css" href="/Web/Content/desktop/page.css">
Any suggestions would be great since I can't seem to get my CSS to work .

You're serving your static files with:
http.FileServer(http.Dir("desktop"))
But based on the screenshot the path on disk is not "desktop" but rather "Web/Content/desktop".
Keep in mind that given that you're already using StripPrefix, there's no reason to use the full path unless you want to. You could do:
r.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("web/content/desktop"))))
Which would change the URL to:
<link rel="stylesheet" type="text/css" href="/css/page.css">

Related

Is it possible to access template by full file path?

I am writing a dynamic website generator where templates are expected to be compiled dynamically (from a changing file system) and the file paths of the templates are important.
With the text/template engine in the Go standard library, you seem to only be able to import a template by filename and not filepath
<!-- templates/index.html -->
<head>
{{ template "head.html" }}
</head>
<!-- templates/partials/head.html -->
<meta />
package main
//go:embed templates
var templates embed.FS
func main() {
folder, _ := fs.Sub(templates , "templates")
tpl, err := template.ParseFS(folder, "index.html" "partials/head.html")
// ...
}
I would like to designate a file system as the root location (rather than manually picking files to include) for my templates and have the imports of templates resolved relative to the template file - using the file path specified in the import. (like EJS - see section "includes")
Is such a thing possible with the default template renderer?
e.g.
folder, _ := fs.Sub(templates , "templates")
tpl, err := template.ParseFS(folder)
<!-- templates/index.html -->
<head>
{{ template "/partials/head.html" }}
</head>

Handling url "/foobar/" replaces css <link>, and js <script> path beginnings with "/foobar/"

I'm trying to use the standard Go http package for my router.
In my main.go it starts:
func main() {
mux := http.NewServeMux()
fs := http.FileServer(http.Dir("static"))
handler := http.StripPrefix("/static/", fs)
mux.Handle("/static/", handler)
mux.HandleFunc("/my-example-url/", FooHandler)
}
inside FooHandler() I have some println()
func FooHandler(w http.ResponseWriter, r *http.Request) {
println("r.URL.Path->",r.URL.Path)
//more business logic
}
// output:
r.URL.Path-> /my-example-url/static/css/normalize.css
r.URL.Path-> /my-example-url/static/libs/xss.js
So the initial part of url should NOT be there (the /my-example-url/ part)
I think this only happends when I'm trying to serve an endpoint with trailing slash such as:
mux.Handle("/my-example-url/", handler)
My end goal is to get some resource based on the id I'm trying to pass in the url after the trailing slash for example:
http://localhost:3001/my-example-url/bb98610
In the html file, the one that's triggering the requests for the static resources, you are most probably using relative paths instead of absolute ones which causes the browser to append that relative path to the path already in the location bar.
For example:
<link href="static/css/normalize.css" rel="stylesheet">
will be turned, by the browser, into /my-example-url/static/css/normalize.css.
Instead you want to use (note the leading slash):
<link href="/static/css/normalize.css" rel="stylesheet">

Why my golang template is not picking the external javascript file?

I tried so many suggestions from stack overflow but none seems to work. I was not able to pick the external js file.
My main function:
package main
import(
"encoding/json"
"net/http"
"fmt"
"github.com/gorilla/mux"
"github.com/rs/cors"
"text/template"
)
func GetPeopleEndpoint(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/html")
t, _ := template.ParseFiles("index2.html")
t.Execute(w, nil)
}
func main() {
router := mux.NewRouter()
people = append(people, Person{ID: "1", Firstname: "Nic", Lastname: "Raboy", Address: &Address{City: "Dublin", State: "CA"}})
people = append(people, Person{ID: "2", Firstname: "Maria", Lastname: "Raboy"})
fmt.Println(people)
router.Handle("/files/", http.StripPrefix("/files/", http.FileServer(http.Dir("."))))
router.HandleFunc("/people", GetPeopleEndpoint)
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:3000"},
AllowCredentials: true,
})
// Insert the middleware
handler := c.Handler(router)
// handler := cors.Default().Handler(router)
http.ListenAndServe(":12345", handler)
}
All my files are in the same directory.
Here is my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
This is page2
<div id='newdiv'>
</div>
</body>
<script type="text/javascript" src="app2.js">
</script>
</html>
The error I'm getting is "GET http://localhost:12345/app2.js". I don't know where I'm doing the mistake.
This line:
router.Handle("/files/", http.StripPrefix("/files/", http.FileServer(http.Dir("."))))
Means that requests coming in for URLs under "/files/" will be served from files on disk in the current directory, with the "/files/" prefix removed.
So if you want a file in the current directory named app2.js, then the URL must be /files/app2.js.
router.Handle defines what handler will handle a given path. In this case, that path is /files/. Because of the trailing slash, the same handler will be used for all URLs beginning with /files/.
http.StripPrefix is a handler wrapper. It takes the incoming request, strips off the given prefix (in this case, /files/), removes it from the URL path, and then passes the request on to the handler passed to StripPrefix.
http.FileServer serves files out of a http.FileSystem, in this case provided by http.Dir. http.Dir exposes the files in a directory, in this case the current working directory (".").
So, in total: requests beginning with /files/, will have the /files/ part removed, then whatever is left, that file path will be looked for in the current working directory, and if it is found, it will be served. So, /files/app2.js will serve ./app2.js. Your HTML must reference /files/app2.js, not app.js.
Let's say you have directory structure:
<src-dir>
static
templates
...
And you map handler you're using http.StripPrefix
router.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
Update this line to-
<script type="text/javascript" src="/static/app2.js"></script>
Now you can access the file via http://localhost:12345/static/app2.js
Writing http.FileServer(http.Dir(".")) is generally a bad idea because it will expose not only your .js files but also you .go files, making you code visible via http requests. For example http://localhost:12345/main.go will make the browser deliver your source code as text.
The best practice should be to collect your static files (js, css, html...) in seperated directories, or just in one, like for example a "resources" package.
Try then with
http.Handle("/files/", http.StripPrefix("/files/", http.FileServer(http.Dir("resources"))))
This code will do the work and allow you to access all your files that are under /resources with the url prefix /files. For example:
http://localhost:12345/files/app2.js

Go How can I use JavaScript code on my html page

Problem: I have script src tag in my index.html page but on browser this script doesn't load ( actually it loads but looks like index.html file 0_0 see pictures below ). The question is: How can I use JavaScript code which is in different file ( myscripts.js ) on my html page ?
js file looks like html ( index.html ) file
During googling I found "solution" but I does not work completely like it should. I just added this line to viewHandler method :
http.ServeFile(w, r, r.URL.Path[1:])
After this, project started look like this:
index.html after adding line above
To sum up:
My goal is to show html page and use javascript function which are in scripts/ folder.
Project Structure :
-scripts
--myscripts.js
-templates
--index.html
server.go
Server.go :
func viewHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("listening . . .")
tpl.ExecuteTemplate(w, "index.html", nil)
}
func main() {
http.HandleFunc("/", viewHandler)
http.ListenAndServe(":8080", nil)
}
myscripts.js:
function clickFunc(){
console.log("clicked")
}
index.html:
<head>
<script type="text/javascript" src="scripts/myscripts.js"></script>
</head>
<body>
<button onclick="clickFunc()">Click me</button>
</body>
</html>
You should be able to serve static files from a specific directory using the http package.
For example:
func main() {
ScriptsDirectory := http.FileServer(http.Dir("scripts"))
http.Handle("/scripts", ScriptsDirectory)
log.Println("Listening at port 3000")
http.ListenAndServe(":3000", nil)
}
Will let you server the file directly from that directory.
From there you can reference the /scripts directory in your index.html page as is.
Here is also a tutorial where this technique is used.

Loading CSS files from a folder in Go

I'm trying to build a small web app, and I'd like to have all my CSS files in one folder, and have them load automatically on all web pages (sort of like the Rails asset pipeline).
I'm using this to serve the css files, but how would I get them to load with all pages?
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("/css/"))))
One solution is to make use of the html/template functionality, create all your pages to include the same section like below. I would however leave room to add tags to your head by leaving the in each of your pages.
{{define "page_template"}}
<head>
<title>My page template</title>
{{template "template_css"}}
<!-- page specific css if required -->
<link rel="stylesheet" type="text/css" href="/assets/additional.css" />
</head>
... etc ...
And the template_css:
{{define "template_css"}}
<link rel="stylesheet" type="text/css" href="/assets/allpages.css" />
{{end}}
A snippet of code for the template parsing
tp, err := template.ParseFiles("page_template.html", "template_css.tp")
err = tp.ExecuteTemplate(buf, "page_template", templateParameters)
I think it's easy to implement this simple asset pipeline feature, you can use path.filepath to walk through your css directory, read all the css files, generate a temp css file by join all lines together, then serve the client with the generated file
import (
"path/filepath"
"os"
"io/ioutil"
)
func Generate(path string) *os.File{
f,err := ioutil.TempFile("","all")
if err!=nil{
return nil
}
filepath.Walk(path,func(p string,info os.FileInfo,err error)error{
if err!=nil{
return err
}
if !info.IsDir(){
data,err := ioutil.ReadFile(info.Name())
if err!=nil{
return err
}
f.Write(data)
}
return err
})
return f
}

Resources