自动在Go HTML模板中生成资产修订文件名

huangapple go评论93阅读模式
英文:

Automatic asset revision filenames in Go HTML templates

问题

我正在寻求关于在Go HTML模板中自动包含带版本号的文件名的实现的帮助。例如,在我的模板中,头部有这样的内容:

<link rel="stylesheet" href="{{ .MyCssFile }}" />

样式表本身有一个来自gulp脚本gulp-rev的MD5哈希附加到名称中:

stylesheet-d861367de2.css

这样做的目的是确保浏览器能够获取到新的更改,同时允许缓存。以下是Django中的一个示例实现,以便更好地解释:

https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#manifeststaticfilesstorage

StaticFilesStorage存储后端的一个子类,它通过将文件内容的MD5哈希附加到文件名上来存储它处理的文件名。例如,文件css/styles.css也将保存为css/styles.55e7cbb9ba48.css。

这种存储的目的是在某些页面仍然引用这些文件的情况下继续提供旧文件,例如因为它们被您或第三方代理服务器缓存。此外,如果您想要为部署的文件应用远期过期标头以加快后续页面访问的加载时间,这将非常有帮助。

现在我想知道如何在Go中最好地实现这一点?我打算使用内置的file server来提供文件。

我目前的想法是:

  • 循环检查目录中最新的样式表文件。听起来很慢。
  • 进行某种重定向/重写,将文件重定向到一个通用命名的文件(例如,请求file.css时提供file-hash.css)。
  • 让Go自己管理资源命名,附加哈希或时间戳。
  • 也许最好使用nginx或其他工具来处理这个问题?
英文:

I'm looking for help on implementing something that automatically includes versioned filenames in a Go HTML template. For example, in my template I have something like this in the head:

&lt;link rel=&quot;stylesheet&quot; href=&quot;{{ .MyCssFile }}&quot; /&gt;

The stylesheets themselves have a chunk of MD5 hash appended to the name from a gulp script called gulp-rev

stylesheet-d861367de2.css

The purpose is to ensure new changes are picked up by browsers, but also allow caching. Here is an example implementation in Django for a better explanation:

https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#manifeststaticfilesstorage

> A subclass of the StaticFilesStorage storage backend which stores the file names it handles by appending the MD5 hash of the file’s content to the filename. For example, the file css/styles.css would also be saved as css/styles.55e7cbb9ba48.css.
>
>The purpose of this storage is to keep serving the old files in case some pages still refer to those files, e.g. because they are cached by you or a 3rd party proxy server. Additionally, it’s very helpful if you want to apply far future Expires headers to the deployed files to speed up the load time for subsequent page visits.

Now I'm wondering how to best pull this off in Go? I intend to serve the files from the built in file server.

My current thoughts are:

  • Have a loop that checks for the newest stylesheet file in a directory. Sounds slow.
  • Do some kind of redirect/rewrite to a generically named file (as in file.css is served on a request to file-hash.css).
  • Have Go manage the asset naming itself, appending the hash or timestamp.
  • Maybe its better handled with nginx or something else?

答案1

得分: 3

编写一个模板函数来解析名称。以下是一个示例模板函数:

func resolveName(p string) (string, error) {
    i := strings.LastIndex(p, ".")
    if i < 0 {
        i = len(p)
    }
    g := p[:i] + "-*" + p[i:]
    matches, err := filepath.Glob(g)
    if err != nil {
        return "", err
    }
    if len(matches) != 1 {
        return "", fmt.Errorf("%d matches for %s", len(matches), p)
    }
    return matches[0], nil
}

在模板中注册为函数"resolveName"后,可以按如下方式在模板中使用:

<link rel="stylesheet" href="{{ .MyCssFile | resolveName }}" />

此函数在每次渲染模板时解析文件名。更聪明的函数可能会在解析名称时缓存名称,或者在启动时遍历目录树以预先构建缓存。

playground示例

英文:

Write a template function to resolve the name. Here's an example template function:

func resolveName(p string) (string, error) {
  i := strings.LastIndex(p, &quot;.&quot;)
  if i &lt; 0 {
	i = len(p)
  }
  g := p[:i] + &quot;-*&quot; + p[i:]
  matches, err := filepath.Glob(g)
  if err != nil {
	return &quot;&quot;, err
  }
  if len(matches) != 1 {
	return &quot;&quot;, fmt.Errorf(&quot;%d matches for %s&quot;, len(matches), p)
  }
  return matches[0], nil
}

and here's how to use it in a template when registered as the function "resolveName":

&lt;link rel=&quot;stylesheet&quot; href=&quot;{{ .MyCssFile | resolveName }}&quot; /&gt;

<kbd>playground example</kbd>

This function resolves the name of the file every time the template is rendered. A more clever function might cache names as they are resolved or walk the directory tree at startup to prebuild a cache.

答案2

得分: 0

我知道这个库有点老了,但也许这个库可以帮到你。它允许收集和哈希静态文件,并且还有一个函数可以将文件路径从原始位置反转到哈希位置:

staticFilesPrefix := "/static/"
staticFilesRoot := "output/dir"

storage := NewStorage(staticFilesRoot)
err := storage.LoadManifest()

funcs := template.FuncMap{
    "static": func(relPath string) string {
        return staticFilesPrefix + storage.Resolve(relPath)
    },
}
tmpl := template.Must(
    template.New("").Funcs(funcs).ParseFiles("templates/main.tpl")
)

现在你可以在模板中像这样调用 static 函数 {{static "css/style.css"}}。这个调用将被转换为 /static/css/style.d41d8cd98f00b204e9800998ecf8427e.css

英文:

I knew it's too old, but maybe this library will help you. It allows to collect and hash static files. Also it has function to reverse file path from the orignal location to the hashed location:

staticFilesPrefix := &quot;/static/&quot;
staticFilesRoot := &quot;output/dir&quot;

storage := NewStorage(staticFilesRoot)
err := storage.LoadManifest()

funcs := template.FuncMap{
    &quot;static&quot;: func(relPath string) string {
        return staticFilesPrefix + storage.Resolve(relPath)
    },
}
tmpl := template.Must(
    template.New(&quot;&quot;).Funcs(funcs).ParseFiles(&quot;templates/main.tpl&quot;)
)

Now you can call static function in templates like this {{static &quot;css/style.css&quot;}}. The call will be converted to /static/css/style.d41d8cd98f00b204e9800998ecf8427e.css.

huangapple
  • 本文由 发表于 2016年1月2日 01:54:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/34558551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定