beego中使用fis
Tag beego, fis, on by view 9040

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