前段时间接触到了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 。