Golang ZIN引擎 - 像2025年一样编写HTML(无需框架)

Golang ZIN引擎 - 像2025年一样编写HTML(无需框架) 我一直在开发 ZIN Engine —— 一个轻量级服务器 + 模板引擎,它让我能够编写纯 .html 文件,同时仍然可以使用循环、API 数据、表单和动态内容等功能 —— 无需接触任何框架或构建步骤

它最初是我为了仅使用 HTML/CSS/JS 就能更快、更简洁地构建网站的个人解决方案 —— 现在我将其分享给社区,以探索它未来的发展方向。

:sparkles: 核心功能

  • 在端口 9001 上提供任何文件夹的服务(或在 NGINX 后使用)
  • 内置 sitemap.xmlrobots.txt.env.zinignore
  • 智能模板:使用 template.html 进行嵌套布局
  • 简洁的 URL:例如 /aboutabout.html
  • 变量渲染:{{ varName | "fallback" }}
  • 通过 zin.config 进行 URL 重写

:puzzle_piece: Zin 标签

  • <zin-time /> → 日期、时间、数学运算和时区格式化
  • <zin-include /> → 包含部分文件甚至 .md 文件
  • <zin-data /> → 从 MySQL、API、JSON、CSV、Google Sheets 加载数据
  • <zin-repeat /> → 遍历动态数据
  • <zin-form /> → 安全表单 + Google reCAPTCHA
  • 此外还有:<zin-set /><zin-random /><zin-crypto /> 等等

:light_bulb: 为何分享?

它仍在开发中,但对我来说已经可用且效果很好。不过,我希望改进其内部结构(特别是优化和解析)。如果你能试用它、找出问题、提出想法,或帮助塑造它的未来,我将不胜感激。

:link: ZIN Engine · GitHub

感谢你们所有的想法、建议或贡献 :raising_hands: 让我们保持纯 HTML 的强大。


更多关于Golang ZIN引擎 - 像2025年一样编写HTML(无需框架)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

仓库可见性已更新。最初分享时是私有的,现在应该没问题了。

更多关于Golang ZIN引擎 - 像2025年一样编写HTML(无需框架)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


那个链接无法访问。我想知道你的代码库是否不小心被设置成了私有。请尝试在未登录 GitHub 的浏览器中查看该链接,看看我们看到的是什么。

我看到一个充满表情符号的README文件,里面没有任何代码。我认为人们真正想问的问题是(假设你真的在某个地方建立了代码仓库):为什么要用这个而不是htmx?此外,Go语言的Reddit子版块最近充斥着由LLM编写的开源项目,所以我最近检查的首要事项之一就是确保项目有一些提交历史。你的代码在哪里?

感谢您的反馈。

ZIN 是我在业余时间开发的一个个人项目,因此进展比较缓慢。如果您感兴趣,核心仓库在这里是开放的:https://github.com/zin-engine/core。我通常会在迭代功能或内部实现时推送更新。

为什么选择这个而不是 htmx?

HTMX——我非常尊重它所做的事情。ZIN 采取了不同的方法,更侧重于使用 Go 实现服务器端的简洁性,无需构建步骤或额外的工具。它并非旨在取代任何东西,只是探索一个我发现有用的不同方向。

如果您有任何想法或建议,我很乐意听取。始终欢迎有益的反馈。

ZIN引擎的设计理念确实很吸引人,特别是在追求轻量化和开发效率的现代Web开发中。作为一个纯Go实现的服务器+模板引擎,它巧妙地平衡了静态HTML的简洁性和动态内容的需求。以下是我从Go语言实现角度的一些技术观察:

核心架构分析

从GitHub仓库看,ZIN采用典型的Go HTTP服务器架构,但模板解析部分有独特设计:

// 示例:ZIN风格的数据绑定实现思路
type ZinEngine struct {
    templates map[string]*template.Template
    dataSources map[string]DataSource
    config *ZinConfig
}

func (z *ZinEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 智能路由:/about → about.html
    path := z.resolvePath(r.URL.Path)
    
    // 动态数据注入
    data := z.gatherData(r)
    
    // 执行ZIN标签处理
    processed := z.processZinTags(path, data)
    
    // 渲染最终HTML
    z.renderTemplate(w, processed, data)
}

模板解析优化建议

当前版本可能面临的性能瓶颈在于模板解析。Go的text/template包虽然强大,但ZIN的扩展标签需要额外的解析层:

// 可能的优化方向:预编译ZIN标签
type CompiledTemplate struct {
    htmlTemplate *template.Template
    zinTags []ZinTag
    cacheKey string
}

func (z *ZinEngine) compileTemplate(path string) (*CompiledTemplate, error) {
    // 1. 解析原始HTML
    content, err := os.ReadFile(path)
    
    // 2. 提取ZIN标签(正则或自定义解析器)
    tags := z.extractZinTags(string(content))
    
    // 3. 转换为标准Go模板语法
    goTemplate := z.convertToGoTemplate(content, tags)
    
    // 4. 编译并缓存
    tpl, _ := template.New(path).Parse(goTemplate)
    
    return &CompiledTemplate{
        htmlTemplate: tpl,
        zinTags: tags,
        cacheKey: generateCacheKey(content),
    }, nil
}

数据源集成示例

<zin-data />标签的实现展示了Go在多数据源集成方面的优势:

// 统一数据源接口
type DataFetcher interface {
    Fetch(ctx context.Context, params map[string]string) (interface{}, error)
}

// MySQL数据源实现
type MySQLFetcher struct {
    db *sql.DB
}

func (m *MySQLFetcher) Fetch(ctx context.Context, params map[string]string) (interface{}, error) {
    query := params["query"]
    var results []map[string]interface{}
    
    rows, err := m.db.QueryContext(ctx, query)
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    
    cols, _ := rows.Columns()
    for rows.Next() {
        columns := make([]interface{}, len(cols))
        columnPtrs := make([]interface{}, len(cols))
        for i := range columns {
            columnPtrs[i] = &columns[i]
        }
        
        if err := rows.Scan(columnPtrs...); err != nil {
            return nil, err
        }
        
        row := make(map[string]interface{})
        for i, colName := range cols {
            val := columnPtrs[i].(*interface{})
            row[colName] = *val
        }
        results = append(results, row)
    }
    
    return results, nil
}

并发安全考虑

作为服务器引擎,并发处理是关键:

// 线程安全的模板缓存
type TemplateCache struct {
    sync.RWMutex
    templates map[string]*CompiledTemplate
    fileModTimes map[string]time.Time
}

func (tc *TemplateCache) Get(path string) (*CompiledTemplate, bool) {
    tc.RLock()
    defer tc.RUnlock()
    
    tpl, ok := tc.templates[path]
    return tpl, ok
}

func (tc *TemplateCache) RefreshIfNeeded(path string) error {
    info, err := os.Stat(path)
    if err != nil {
        return err
    }
    
    tc.Lock()
    defer tc.Unlock()
    
    if modTime, ok := tc.fileModTimes[path]; ok && modTime.Equal(info.ModTime()) {
        return nil // 无需刷新
    }
    
    // 重新编译模板
    // ... 编译逻辑
    tc.fileModTimes[path] = info.ModTime()
    return nil
}

性能优化点

  1. 模板预编译:将ZIN标签在启动时转换为标准Go模板
  2. 内存池:对于频繁创建的临时对象使用sync.Pool
  3. 响应压缩:集成gzip/brotli压缩中间件
  4. ETag支持:基于内容哈希的缓存验证
// 内存池示例
var bufferPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func processTemplate(path string) string {
    buf := bufferPool.Get().(*bytes.Buffer)
    buf.Reset()
    defer bufferPool.Put(buf)
    
    // 使用buf进行模板渲染
    // ...
    
    return buf.String()
}

ZIN引擎的核心价值在于它的"无框架"理念,这在Go生态中很有意义。Go的标准库已经足够强大,ZIN通过轻量级扩展使其更适合现代Web开发,同时保持了Go的编译型语言优势。项目的架构选择很合理,特别是在避免过度抽象方面做得很好。

回到顶部