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

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

Related

Serving Svelte MPA with nested components via go webserver

I want create a multi-page application where individual sites are constructed from Svelte components. The pages are constructed from a template engine and served via a go server.
I followed a written & youtube tutorial, that instructed me to add the customElement compiler option, modified main.js to import the respective svelte components, setup go server and template engine.
svelte({
compilerOptions: {
// enable run-time checks when not in production
dev: !production,
customElement: true,
}
}),
This is the index.html
{{define "body"}}
<td-explorer></td-explorer>
{{end}}
Here is the Svelte Component:
// Explorer.svelte
<script>
import {Tile} from "carbon-components-svelte";
</script>
<svelte:options tag="td-explorer"/>
<div>
<p>asdf</p>
<Tile></Tile>
</div>
Here is the handler that renders the template:
func IndexPage(w http.ResponseWriter, r *http.Request) {
base := filepath.Join("./backend/server/webserver/templates", "base.html")
index := filepath.Join("./backend/server/webserver/templates", "index.html")
tmpl, _ := template.ParseFiles(base, index)
tmpl.ExecuteTemplate(w, "base", nil)
}
The site is served as expected. All static resources are reachable.
The problem is that as soon as the customElement component td-explorer contains another component (such as <Tile> which is part of a ui library), the server merely shows a blank page. If I remove this nested component, our td-explorer gets rendered as expected, showing 'asdf'.

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

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
}

Multiple files using template.ParseFiles in golang

For example.go, I have
package main
import "html/template"
import "net/http"
func handler(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("header.html", "footer.html")
t.Execute(w, map[string] string {"Title": "My title", "Body": "Hi this is my body"})
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
In header.html:
Title is {{.Title}}
In footer.html:
Body is {{.Body}}
When going to http://localhost:8080/, I only see "Title is My title", and not the second file, footer.html. How can I load multiple files with template.ParseFiles? What's the most efficient way to do this?
Thanks in advance.
Only the first file is used as the main template. The other template files need to be included from the first like so:
Title is {{.Title}}
{{template "footer.html" .}}
The dot after "footer.html" passes the data from Execute through to the footer template -- the value passed becomes . in the included template.
There is a little shortcoming in user634175's method: the {{template "footer.html" .}} in the first template must be hard coded, which makes it difficult to change footer.html to another footer.
And here is a little improvement.
header.html:
Title is {{.Title}}
{{template "footer" .}}
footer.html:
{{define "footer"}}Body is {{.Body}}{{end}}
So that footer.html can be changed to any file that defines "footer", to make different pages

Resources