Simple summary and sharing of this Go blog front-end development

Simple summary and sharing of this Go blog front-end development

Some netizens asked me to share, so I'll briefly talk about it.

Last updated 10/10/2022 9:41 AM
沙漠尽头的狼
10 min read
Category
More Languages
Tags
Go

Hello everyone, I am the Wolf at the End of the Desert.

Reason for writing this post

The frontend of this blog written in Go by the site owner is quite native, without using any framework. I originally planned to write a detailed post after refactoring, but a group member brought it up today, so I'll write a brief one.

Online access address: https://go.dotnet9.com

Homepage screenshot:

This article is very simple, so here is a table of contents:

  1. Go Basics
  2. Go Blog Building Reference
  3. Go Version Blog Source Code
  4. Future Plans

1. Go Basics

The above URL and PDF are suitable for building a foundation and reinforcing Go's basic syntax. The PDF file should not be the commercially available "Go Web Programming" (by Zheng Zhaoxiong, Singapore), but it is also quite good, explaining many web basics. It is likely a summary by an online expert and worth reading. Below is the PDF's table of contents:

Go web PDF

I recommend the above basic resources for those new to Go. Fundamentals are important.

2. Go Blog Building Reference

The refactored blog frontend template and Go version learning resources come from:

Video directory as follows:

码神之路B站视频教程目录

Screenshot of the blog post accompanying the video:

码神之路个人博客

The video is suitable for learning and hands-on practice, while the accompanying blog posts help verify code correctness. The frontend template accompanying the blog is shared in the Up主's group (group number [718840650]), and it is also uploaded in the site owner's code repository, but with some modifications different from the Up主's. Some personalized changes are as follows:

  • The site owner did not add frontend article editing: The Dotnet9 website already has a backend article management function, so there is overlap.
  • Different ORM choice: The site owner chose GORM.
  • The site owner directly calls the Dotnet9 website backend API for article search, without implementing a separate interface in Go: The Web API and frontend have clear responsibilities, and it also allows sharing with other client interfaces, e.g., the Razor Pages blog frontend also uses the same article search API.
  • Others.

3. Go Version Blog Source Code

As the title of the B站 Up主 [码神之路] video tutorial says: "Native Go Blog Practical Tutorial, a practice-level project tutorial, without using any framework, easy to understand", the emphasis is on native. After practice, the site owner found that the Up主's routing approach is similar to ASP.NET Core's Minimal APIs, though the former mainly writes Web (MVC) and the latter writes Web API. Comparing and learning with familiar technologies can deepen understanding. Below is a brief introduction to the Go version blog source code.

3.1 Entry

main.go is the program entry file, equivalent to ASP.NET Core's Program.cs. The file name can be modified as long as the first line of code is package main.

Full code as follows:

package main

import (
	"log"
	"net/http"
	"dotnet9.com/goweb/common"
	"dotnet9.com/goweb/router"
)

func init() {
	// Template loading: html files, e.g., homepage article list, category article list, header, footer, etc.
	common.LoadTemplate()
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}
	router.Router()
	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

The service binds IP and port hardcoded; it could be written in a configuration file. Doesn't it look similar to the following ASP.NET Core Minimal API:

var app = WebApplication.Create(args);

app.MapGet("/", () => "Hello World!");

app.Run("http://localhost:3000");

router.Router() is a simple encapsulation of routing (as below). It resembles app.MapGet("/", () => "Hello World!"); to some extent—like 8 out of 10?:

Go's simple routing encapsulation: router.go

package router

import (
	"net/http"
	"dotnet9.com/goweb/views"
	"dotnet9.com/goweb/api"
)

func Router() {
	http.HandleFunc("/", views.HTML.Index)
	http.HandleFunc("/c/", views.HTML.Category)
	http.HandleFunc("/p/", views.HTML.Detail)
	http.HandleFunc("/login", views.HTML.Login)
	http.HandleFunc("/api/v1/post", api.API.SaveAndUpdatePost)
	http.Handle("/resource/", http.StripPrefix("/resource/", http.FileServer(http.Dir("public/resource/"))))
}

The routing for the homepage code as follows:

./views/index.go

package views

import (
	"errors"
	"log"
	"net/http"
	"strconv"
	"dotnet9.com/goweb/common"
	"dotnet9.com/goweb/service"
)

func (*HTMLApi) Index(w http.ResponseWriter, r *http.Request) {
	// Business code here: read article list, bind template
}

3.n Template Binding

Skipping ORM usage etc., let's talk about template binding:

This is Go's article list template: ./template/layout/post-list.html

{{define "post-list"}}
<ul class="post-box">
  {{range $index, $elem := .Posts}}
  <li class="post-label">
    <a href="/p/{{$elem.Slug}}"><h2>{{$elem.Title}}</h2></a>
    <p>{{$elem.Description}}</p>
    <div class="post-action">
      <span>
        <i class="iconfont icon-yonghu"></i>
        &nbsp; {{$elem.Original}}
      </span>
      <span>
        <i class="iconfont icon-wenjianjia"></i>
        {{range $catIndex, $cat := $elem.Categories}}
        &nbsp;<a href="/c/{{$cat.Slug}}">{{$cat.Name}}</a>
        {{end}}
      </span>
      <span>
        <i class="iconfont icon-riqi"></i>
        &nbsp;{{$elem.CreationTime}}
      </span>
      <span>
        <i class="iconfont icon-yanjing"></i>
        &nbsp;{{$elem.ViewCount}}
      </span>
    </div>
  </li>
  {{end}}
</ul>
{{end}}

Compare with Razor Pages article list template binding:

@page
@inject IOptionsSnapshot<SiteOptions> SiteOptions
@using Dotnet9.Web.ViewModel.Commons
@model IndexModel
@{
    ViewData["Title"] = "首页";
}

<ul class="post-box">
    @if (Model.BlogPosts?.Any() == false)
    {
        <span>没有数据哦</span>
    }
    else
    {
        @foreach (var blogPost in Model.BlogPosts!)
        {
            <li class="post-label">
                <a href="@blogPost.CreationTime.ToString("/yyyy/dd")/@blogPost.Slug">
                    <h2>@blogPost.Title</h2>
                </a>
                <p>@blogPost.Description</p>
                <div class="post-action">
                    <span>
                        <i class="iconfont icon-yonghu"></i>
                        &nbsp; @(blogPost.Original.IsNullOrWhiteSpace() ? SiteOptions.Value.Owner : blogPost.Original)
                    </span>
                    <span>
                        <i class="iconfont icon-wenjianjia"></i>
                        &nbsp;
                        @foreach (var cat in blogPost.Categories)
                        {
                            <a href="/cat/@cat.Slug" title="@cat.Description">@cat.Name</a>
                        }
                    </span>
                    <span>
                        <i class="iconfont icon-riqi"></i>
                        &nbsp;@blogPost.CreationTime.ToString("yyyy-MM-dd")
                    </span>
                    <span>
                        <i class="iconfont icon-yanjing"></i>
                        &nbsp;@blogPost.ViewCount
                    </span>
                </div>
            </li>
        }
    }
</ul>

@await Html.PartialAsync("_PaginationPartial", new PaginationModel(Model.Current, Model.Pages, Model.Total, Model.PageSize, Model.PageCount))

Just a rough look:

  • Go template binding uses {{.object field}}, note the dot before.
  • Razor syntax binding uses @Model.object.

Languages are similar; if you're familiar with one tech stack, you can learn others by analogy.

3.n+1 Comments

Comments use the third-party interface Valine. We may develop our own later:

Valine - A fast, concise, and efficient backendless comment system.

Features

  • Fast
  • Secure
  • Emoji 😉
  • No backend implementation
  • Full MarkDown syntax support
  • Lightweight and easy to use
  • Article view count statistics v1.2.0+

Website screenshot:

Valine comment backend management:

4. Future Plans

Learning Go, or any new technology, requires not just studying but also finding opportunities to use it. Try to build a project you're interested in using Go, like a simple blog frontend. This will motivate you to learn more. Initially, try native development (without frameworks) to better understand the language's basic syntax.

When you need rapid business development and iteration, consider frameworks. The site owner has recently been interested in goframe:

GoFrame is a modular, high-performance, enterprise-level Go basic development framework. GoFrame is a general-purpose basic development framework, an enhanced extension of the Go standard library, containing common core basic development components. Its advantages include practicality, modularity, comprehensive documentation, rich modules, high ease of use, strong generality, and team-oriented design. If you want to build a business project in Go, whether small, medium, or large, GoFrame is your best choice. If you want to develop a Go component library, GoFrame's out-of-the-box, rich and powerful basic component library will also help you work efficiently. If you are a team leader, GoFrame's extensive documentation, detailed code comments, and active community members will greatly reduce your guidance costs, supporting rapid team onboarding, language transition, and capability improvement.

GoFrame official documentation: https://goframe.org/pages/viewpage.action?pageId=1114119

I'll use goframe to refactor this Go blog later, but of course, I need to finish developing the Razor Pages version first, including the backend…

End of this filler article (took 2 hours). As long as you're willing to spend time learning, there's nothing you can't learn. Just one word: go for it.

Keep Exploring

Related Reading

More Articles
Same tag 11/6/2024

Why My Blog Website Returned to Blazor

The development of the blog website has gone through many hardships, with nearly 10 versions including MVC, Vue, Go, etc. Now it has returned to Blazor and adopted static SSR, resulting in a significant speed increase and successful launch.

Continue Reading