This article is a continuation of the previous one, where we built a simple Todo App backend with Golang.
If you are new to Go and would like an easy way to get your feet wet, check out my article on building a Simple Todo CRUD REST API with Go and MongoDB.
This guide focuses on generating HTML templates, serving static CSS and Javascript files in Go, setting up the Fronted app and connecting it to the backend.
As we've finished building the backend application, it's time to set up the front end, connect it to the backend, and create a full-stack web application.
This article lays the foundation for the upcoming one, where we will build a Todo Frontend App with the Fetch API and Vanilla JavaScript (with a TypeScript version available).
This Todo App has monolith architecture, indicating the Frontend and Backend share the same codebase.
We are using Go to create a simple web server service that will serve HTML, CSS and JavaScript files when you navigate to a localhost address.
Render HTML template in Go.
To render HTML templates in a Go application, we first need to parse them. Parsing means that Go can read the HTML template file we create, identify syntax and placeholder tokens, and then render the file as an HTML file.
The renderer package, which we use for handling API responses in the Golang backend todo app, provides a straightforward way to parse HTML templates. Under the hood, it uses the Go html/template package. However, you can use the default Go html/template package, depending on your preference.
ADD HTML Template
The HTML template contains code for a task input box and a submit button. The div with id "todos" is used to add todos retrieved from the backend API and display them dynamically in the todos div on the Frontend.
To add the HTML template,
- Create an “html” folder in your project’s root directory.
- Inside the folder, create an “index.html” file.
- Copy and paste the following code into the "index.html" file, or you can download the file from GitHub.
{{define "indexPage"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>To Do App - with html, css and Javascript</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css"
/>
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body>
<div class="container">
<div id="new-todo">
<input type="text" placeholder="Tasks to be done" />
<button type="button" id="submit">Add</button>
</div>
<div id="todos"></div>
</div>
</body>
</html>
{{end}}
In the code above, we define an HTML template named” indexPage”, which we will serve as the Response when a user navigates to our homepage.
We linked the CSS file to the index page, ensuring the HTML templates applied the styles correctly.
Add CSS File
To add the CSS file;
- Create a Static folder in the root directory. You can name this folder “public” or “assets” if you want.
- Inside the folder, create “style.css” file.
- Copy and paste the following code into the "style.css" file, or you can download the file from GitHub. (link to file on GitHub).
- Link the css file to “index.html” file. Make sure you have added the css link to the
<head>
tag in the index.html file
<head>
...
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
This is a basic styling I created for the Todo app frontend layout. Feel free to use this or the styles of your choice.
static/style.css
*,
*::before,
*::after {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background: linear-gradient(135deg, #8052ec, #d161ff);
}
.container{
border: 2px solid white;
width: 40%;
min-width: 450px;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
padding: 30px 40px;
}
#new-todo{
background-color: #fff;
padding: 30px 20px;
border-radius: 5px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
}
#new-todo input{
width: 70%;
height: 45px;
font-family: 'Poppins', Verdana, Geneva, Tahoma, sans-serif;
font-size: 15px;
border: 2px solid #d1d3d4;
padding: 12px;
color: #100f0f;
position: relative;
font-weight: 500;
border-radius: 5px;
}
#new-todo input:focus {
outline: none;
border-color: #8052ec;
}
#new-todo button {
position: relative;
float: right;
width: 20%;
height: 45px;
border-radius: 5px;
font-family: 'Poppins', Verdana, Geneva, Tahoma, sans-serif;
font-weight: 500;
font-size: 16px;
border: none;
background-color: #8052ec;
color: #fff;
cursor: pointer;
}
#todos {
background-color: #fff;
padding: 30px 20px;
margin-top: 10px;
border-radius: 10px;
width: 100%;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
position: relative;
}
.todo {
background-color: #fff;
height: 50px;
padding: 5px 10px;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2px solid #d1d3d4;
cursor: pointer;
}
.todo span{
font-family: 'Poppins', Verdana, Geneva, Tahoma, sans-serif;
font-size: 15px;
font-weight: 400;
}
.todo .actions {
height: 100%;
}
.todo button {
background-color: #8052ec;
color: #fff;
height: 100%;
width: 40px;
border-radius: 5px;
border: none;
cursor: pointer;
outline: none;
}
.completed{
text-decoration: line-through;
}
Your folder structure should look like this;
You can check the code on GitHub for reference
Parse HTML template
Now we have the HJTML and CSS files set up, let’s get Golang to display them. In your main.go
file, update the renderer
method in func init
by adding the HTML parsing option to rnd = renderer.New()
.
func init() {
rnd = renderer.New(
renderer.Options{
ParseGlobPattern: "html/*.html",
},
)
...
}
Here, we create a new renderer instance and set the ParseGlobPattern
option. This option allows us to look for files inside the HTML folder with the “.html” extension and render them as templates.
Now, update the homeHandler in main.go
file to return the content from the indexPage in the HTML template so that when a user makes a browser HTTP request to “localhost:9000/”, it returns the indexPage in the HTML template.
func homeHandler(rw http.ResponseWriter, r *http.Request) {
// filePath := "./README.md"
// err := rnd.FileView(rw, http.StatusOK, filePath, "readme.md")
err := rnd.HTML(rw, http.StatusOK, "indexPage", nil)
}
Here, I commented out the README.md
file that was being returned and replaced it with the "HTML" template renderer, as mentioned above.
Run go run main.go
to view the result.
Note: If you used my Go Todo Backend API tutorial, make sure to have your database up and running, otherwise the app will crash.
Serve Static CSS and JavaScript Files in Go.
After running main.go
and navigating to localhost:9000
. You notice that the HTML lacks CSS, and the URL returns a 404 error for the static files.
To fix this error, we must serve the static files to Go
by publishing the CSS
files.
To publish the static files, update func main
in main.go
and add the following code after where you defined middleware.Logger
and before where you specified the homehandler
to ensure that the static files are available when a user sends a request to localhost:9000
.
/main.go
// Serve static files
fs := http.FileServer(http.Dir("./static"))
router.Handle("/static/*", http.StripPrefix("/static/", fs))
In the code above, we use the file server handler http.fileServer
to serve static files from the ‘static’ directory on the server.
The router.Handle
method handles the route for serving static files. In this example, we use chi.Router
,so update accordingly to whatever router you are using. This setup specifies that any URL path request starting with “/static/”
should be handled by the ‘fs’ (file server ).
The http.StripPrefix
removes the ‘static’
prefix from the request URL, so instead of the request URL to be domain-name/static/static/style.css
, it will be domain-name/static/styles.css
.
Once you complete the setup, run go run main.go
and navigate to localhost:9000
in your web browser. You will see that the page has applied the styles, and the URL will return a 200 status ok
for the CSS and script file( if you added one ), indicating that the server has successfully served the static files.
JavaScript File
Adding a JavaScript file is no different from adding a CSS file. The process is exactly the same. Simply create a script.js
file inside the static
folder (or whichever folder name you used). After restarting the server, the JavaScript file will be picked up and served, just like the CSS file.css file.
Final Result
This is what the UI looks like with the styles applied;
TypeScript Configuration and Setup
If you're using vanilla JS, you can write the JavaScript code directly in the script
tag or a separate file.
But for TypeScript, It’s best to create a separate script.ts
file, compile it to JavaScript using the TypeScript compiler, and then import the resulting script.js
file into your HTML template.
Why? Because it was difficult to find compilers that could compile the Typescript in the <script>
tag in the HTML file, and I couldn't find one that worked well enough.
To add a TypeScript file, run this npm command to install Typescript globally.
npm install -g typescript
Then, check the installed version by running tsc --version
.
Create a tsconfig.json
file at your project's root and paste the configuration code into it. Adding the tsconfig.json
file is recommended for more precise code management and better code quality.
/tsconfig.json
{
"compilerOptions": {
"target": "es2017",
"module": "ESNext",
"sourceMap": true,
"strict": true,
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"allowUnreachableCode": false,
"strictFunctionTypes": true,
"noUnusedParameters": true,
"noImplicitReturns": true
}
}
Next, add a script.ts
file to the static
folder.
To compile the script.ts
file,
tsc static/script.ts
By default, TypeScript will output the compiled JavaScript file script.js
in the same folder as the TypeScript file. If you want to change this behaviour, you can add the "outDir"
option to the configuration. For example, setting "outDir": "dist"
will output the compiled file to the dist folder.
Don't forget to include script.js
as the script tag above </body>
tag source in your HTML code.
<script src="/static/script.js"></script>
Your folder structure should look like this;
To test, add a simple code to the script.ts
file (e.g. console.log(’hello’)
)and compile the ts file to test. If using a middleware logger, you should see the GET request
result on the terminal.
Now, you're all set to write and compile TypeScript code.
Get the complete code for HTML template setup and asset files on GitHub.
For TypeScript configuration, check out the file on GitHub.
Conclusion
In this continuation article, we learned how to generate HTML templates and serve static CSS and JavaScript files using Golang; we set up a Typescript configuration for people who would prefer to use it. Following the steps outlined in this guide, we can now render HTML templates, parse them, and serve static files.
With this basic setup, we are ready to build the Todo App Frontend with HTML, CSS, and Vanilla JavaScript or TypeScript, using the JavaScript Fetch API to consume the Todo backend API endpoints.
Recommended Reads
Top comments (0)