Go How can I use JavaScript code on my html page - go

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.

Related

Why doesn't template.ParseFiles() detect this error?

If I specify a non-existent template in my template file, the error is not detected by ParseFiles() but by ExecuteTemplate(). One would expect parsing to detect any missing templates. Detecting such errors during parsing could also lead to performance improvements.
{{define "test"}}
<html>
<head>
<title> test </title>
</head>
<body>
<h1> Hello, world!</h1>
{{template "doesnotexist"}}
</body>
</html>
{{end}}
main.go
package main
import (
"html/template"
"os"
"fmt"
)
func main() {
t, err := template.ParseFiles("test.html")
if err != nil {
fmt.Printf("ParseFiles: %s\n", err)
return
}
err = t.ExecuteTemplate(os.Stdout, "test", nil)
if err != nil {
fmt.Printf("ExecuteTemplate: %s\n", err)
}
}
10:46:30 $ go run main.go
ExecuteTemplate: html/template:test.html:8:19: no such template "doesnotexist"
10:46:31 $
template.ParseFiles() doesn't report missing templates, because often not all the templates are parsed in a single step, and reporting missing templates (by template.ParseFiles()) would not allow this.
It's possible to parse templates using multiple calls, from multiple sources.
For example if you call the Template.Parse() method or your template, you can add more templates to it:
_, err = t.Parse(`{{define "doesnotexist"}}the missing piece{{end}}`)
if err != nil {
fmt.Printf("Parse failed: %v", err)
return
}
The above code will add the missing piece, and your template execution will succeed and generate the output (try it on the Go Playground):
<html>
<head>
<title> test </title>
</head>
<body>
<h1> Hello, world!</h1>
the missing piece
</body>
</html>
Going further, not requiring all templates to be parsed and "presented" gives you optimization possibilities. It's possible there are admin pages which are never used by "normal" users, and are only required if an admin user starts or uses your app. In that case you can speed up startup and same memory by not having to parse admin pages (only when / if an admin user uses your app).
See related: Go template name

Golang correct filepath to serve css files

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">

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

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