Serving Svelte MPA with nested components via go webserver - go

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'.

Related

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.

does ui router not work in jade?

I am setting up a simple crud app. However, I am not sure what is going on with ui-router. I read that you should use html tags so I tried this as well. Here is my code.
app.js
app.get('/templates/:templateid',indexController.getTemplate);
index controller
var indexController = {
index: function(req, res) {
res.render('index');
},
getTemplate:function(res,req){
res.render('templates/' + req.params.templateid);
}
};
module.exports = indexController;
Here is my main.js
var app = angular.module('myApp',['ui.router']);
app.config(function($stateProvider,$urlProvider){
$stateProvider('home',{
url:'/home',
templateUrl:'templates/home.jade',
controller: 'HomeController'
})
})
app.controller('HomeController',function($scope){
console.log('home is here');
})
My index.jade shows as so
extends layout
block content
h1 Lets Get Cruddy
<div ui-view></div>
I have called ng-app in my layout. This should be fairly simple right?
The router only interprets html
you should point the template url to the compiled html file so
templateUrl:'templates/home.html
that's if templates/home.jade compiles to templates/home.html
As Dr Manhattan said, AngularJS does not render a Jade file, however, if you have a server side language such as NodeJS, you can change view engine to Jade.
For simplicity sake, I would also recommend creating a NodeJS application with Express so you can create a route that will render the view and take advantage of the simplicity of Jade.
Add the following to your App.js file in your NodeJS application:
app.set('view engine', 'jade');
In your NodeJS route, you will add something like this:
var router = express.Router();
// index.js
// http://www.yourdomain.com/ is the path to this route
router.get('/', function(req, res, next) {
res.render('home', {
title: 'Express'
});
});
In your main.js file, you will change the templateURL to the following:
templateUrl:'/',
Jade will render the template to HTML and make it readable for AngularJS.

Print parts of a web-page's source in Golang like PHP

I'm trying to generate a web page in Go lang. I'm currently using the Goji framework ( http://goji.io ) and I want to generate all of the heads and parts of the body of the web-page, but then I want some of the content to be written based on results from the code.
For example as in PHP, one can write HTML, js, or CSS and then in the PHP tags, write the code which is interpreted there.
How can I write my html, css, and js and then have Golang code within it that is complied and executed as the page is rendered?
As mentioned in issue 13, use Go html/template package.
i.e.
// Shorthand
type M map[string]interface{}
func viewHandler(c web.C, w http.ResponseWriter, r *http.Request) {
title := c.URLParams["title"]
p, err := loadPage(title)
if err != nil {
...
}
// do other things
template.ExecuteTemplate(w, "results.html", M{
"title": title,
"results": results,
"pagination": true,
}
}
results.html
{{range .Results }}
<h1>{{ Result.Name }}</h1>
<p>{{ Result.Body }}</p>
{{ end }}
Using a template is also recommended in zenazn/goji/example/main.go.
elithrar also references in the comments the "Writing Web Applications article, section The html/template package" for more.

Resources