前段时间接触到了fis,后来发现它正是我所寻找的一类前端工具。之前在byvoid大神的博客上看到前端html源码中引用的js和css都是在文件名后面附加了随机串。如/css/style-882e60051fc11fd2558e888585fc3950.css
。我感觉这个做法应该有他的深意。接触fis后才知道,文件md5映射之后可以在服务器端开启静态文件永久缓存,如此一来可以最大化利用浏览器的缓存机制,起到加快页面加载速度节省流量的效果。由于md5映射的文件名是唯一的,所以不用担心缓存导致的前端问题。这一技术在许多其他的网站上也有用到,例如百度、twitter等,其中fis就是出自百度,据fis文档介绍,其中某些创意是受twitter启发的。
最近一直在用beego做项目,于是打算将fis的md5映射机制迁移到beego上来,fis官网文档上介绍了fis在go web的实现demo,不过它是基于martini框架的,在多番查阅文档后,我觉得若是抛开模版内的资源文件自动打包这一功能单纯实现md5映射,我能够自己将其在beego上实现。
fis中带md5映射的前端资源全部记录于map.json文件中,fis项目编译后会自动生成map.json文件,示例如下
{
"res": {
"js/global.js": {
"uri": "/static/js/global_f39ad61.js",
"type": "js"
},
"js/user.js": {
"uri": "/static/js/user_42dbc3b.js",
"type": "js"
},
"octicons/octicons.scss": {
"uri": "/static/octicons/octicons_1b828d3.css",
"type": "css"
},
"sass/index.scss": {
"uri": "/static/css/index_b855d1c.css",
"type": "css"
},
"sass/login.scss": {
"uri": "/static/css/login_c8abcc0.css",
"type": "css"
},
"sass/register.scss": {
"uri": "/static/css/register_b76a400.css",
"type": "css"
},
"sass/style.scss": {
"uri": "/static/css/style_462f7a1.css",
"type": "css"
}
},
"pkg": {}
}
这其中"res"项就是资源映射表,"js/global.js"以及"js/global.js"等是编译前的文件,即fis项目源文件,而"/static/js/global_f39ad61.js"以及"/static/octicons/octicons_1b828d3.css"等是编译后的文件,网站应当加载编译后的文件,而编译后的文件名是变动的,每次修改源文件并编译后,编译后的文件名md5值便会变化,不过编译前的文件名是不变的,因此,思路是通过编译前文件名得到对应的编译后的文件名,然后加载到网页。beego实现如下:
在工具包utils里有
package utils
import (
"fmt"
"github.com/astaxie/beego"
"github.com/gogather/com"
"html/template"
)
// fis map
func Fis(key string) template.HTML {
var text string
content := loadMap()
json, _ := com.JsonDecode(content)
json = json.(map[string]interface{})["res"]
if fileMap, ok := json.(map[string]interface{}); !ok {
fmt.Println("map.json id illeage!")
} else {
for tmpKey, views := range fileMap {
uri, ok := views.(map[string]interface{})["uri"].(string)
if !ok {
fmt.Println("error in map.json")
}
fileType, ok := views.(map[string]interface{})["type"].(string)
if !ok {
fmt.Println("error in map.json")
}
if tmpKey == key {
if fileType == "css" {
text = `<link rel="stylesheet" href="` + uri + `">`
} else if fileType == "js" {
text = `<script src="` + uri + `"></script>`
}
}
}
}
return template.HTML(text)
}
// load map.json
func loadMap() string {
mapPath := beego.AppConfig.String("static_map")
mapContent := com.ReadFile(mapPath)
return mapContent
}
其中Fis函数便是由编译前的文件名查找编译后的文件名。接下来是注册模版函数
beego.AddFuncMap("asset", utils.Fis)
然后你就可以在模版中这样引入js或者css文件了
{{template "inc/header.tpl" .}}
{{asset "sass/login.scss"}}
<div class="info"> </div>
<div class="login">
<form action="/login">
<ul>
<li><label for="">用户名</label><input type="text" name="username" id=""></li>
<li><label for="">密码</label><input type="password" name="password" id=""></li>
<li class="login-btns">
<button class="btn">{{i18n "login"}}</button>
<a class="btn oauth-login" href="https://github.com/login/oauth/authorize?client_id={{.github_client_id}}&scope=user,public_repo" target="_blank"><span class="octicon octicon-logo-github"></span>登录</a>
</li>
</ul>
</form>
</div>
{{asset "js/user.js"}}
{{template "inc/footer.tpl" .}}
其中
{{asset "sass/login.scss"}}
便是引入"sass/login.scss"对应的编译后的css文件。
如此,便实现了利用fis的md5映射功能,现在可以放心开启js和css的强制缓存了。最后附上我自己的项目地址供大家借鉴https://github.com/duguying/ojsite 。