在Journey源码分析二:整体启动流程
中提到了模板编译,这里详细说下启动流程
看下templates.Generate()
源码:
func Generate() error {
compiledTemplates.Lock()
defer compiledTemplates.Unlock()
// 首先清除模板(主题可能已经改变了)
compiledTemplates.m = make(map[string]*structure.Helper)
// 编译所有模板文件。
err := checkThemes()
if err != nil {
return err
}
// If the dev flag is set, watch the theme directory and the plugin directoy for changes
// TODO: It seems unclean to do the watching of the plugins in the templates package. Move this somewhere else.
if flags.IsInDevMode {
// Get the currently used theme path
activeTheme, err := database.RetrieveActiveTheme()
if err != nil {
return err
}
currentThemePath := filepath.Join(filenames.ThemesFilepath, *activeTheme)
// Create watcher
err = watcher.Watch([]string{currentThemePath, filenames.PluginsFilepath}, map[string]func() error{".hbs": Generate, ".lua": plugins.Load})
if err != nil {
return err
}
}
return nil
}
模板编译主要在checkThemes()
函数中:
func checkThemes() error {
// Get currently set theme from database
// 从数据库获取当前数据库
activeTheme, err := database.RetrieveActiveTheme()
if err != nil {
return err
}
currentThemePath := filepath.Join(filenames.ThemesFilepath, *activeTheme)
err = compileTheme(currentThemePath)
if err == nil {
return nil
}
// 如果当前主题编译失败,则尝试默认主题(promenade)
err = compileTheme(filepath.Join(filenames.ThemesFilepath, "promenade"))
if err == nil {
// Update the theme name in the database
err = methods.UpdateActiveTheme("promenade", 1)
if err != nil {
return err
}
return nil
}
// 如果默认主题也编译失败,则遍历所有可用的主题,选取第一个可用的。
allThemes := GetAllThemes()
for _, theme := range allThemes {
err = compileTheme(filepath.Join(filenames.ThemesFilepath, theme))
if err == nil {
// Update the theme name in the database
err = methods.UpdateActiveTheme(theme, 1)
if err != nil {
return err
}
return nil
}
}
return errors.New("Couldn't find a theme to use in " + filenames.ThemesFilepath)
}
看下compileTheme(currentThemePath)
源码:
func compileTheme(themePath string) error {
// 检查主题目录是否存在
if _, err := os.Stat(themePath); os.IsNotExist(err) {
return errors.New("Couldn't find theme files in " + themePath + ": " + err.Error())
}
err := filepath.Walk(themePath, inspectTemplateFile)
if err != nil {
return err
}
// Check if index and post templates are compiled
if _, ok := compiledTemplates.m["index"]; !ok {
return errors.New("Couldn't compile template 'index'. Is index.hbs missing?")
}
if _, ok := compiledTemplates.m["post"]; !ok {
return errors.New("Couldn't compile template 'post'. Is post.hbs missing?")
}
// Check if pagination and navigation templates have been provided by the theme.
// If not, use the build in ones.
if _, ok := compiledTemplates.m["pagination"]; !ok {
err = compileFile(filepath.Join(filenames.HbsFilepath, "pagination.hbs"))
if err != nil {
log.Println("Warning: Couldn't compile pagination template.")
}
}
if _, ok := compiledTemplates.m["navigation"]; !ok {
err = compileFile(filepath.Join(filenames.HbsFilepath, "navigation.hbs"))
if err != nil {
log.Println("Warning: Couldn't compile navigation template.")
}
}
return nil
}
上面代码的核心代码是err := filepath.Walk(themePath, inspectTemplateFile)
,该方法遍历主题目录中的文件,并调用inspectTemplateFile()
函数,看下inspectTemplateFile()
的源码:
func inspectTemplateFile(filePath string, info os.FileInfo, err error) error {
if !info.IsDir() && filepath.Ext(filePath) == ".hbs" {
err := compileFile(filePath)
if err != nil {
return err
}
}
return nil
}
如果filePath
是文件并且以.hbs
结尾则编译它。看下compileFile(filePath)
源码:
func compileFile(fileName string) error {
// 编译模板文件
helper, err := createTemplateFromFile(fileName)
if err != nil {
return err
}
// 将模板放入到全局变量compiledTemplates.m中去。
compiledTemplates.m[helper.Name] = helper
return nil
}
看下createTemplateFromFile(fileName)
源码:
func createTemplateFromFile(filename string) (*structure.Helper, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
fileNameWithoutExtension := helpers.GetFilenameWithoutExtension(filename)
// 如果同名的模板已经存在compiledTemplates.m字典中则报错。
if compiledTemplates.m[fileNameWithoutExtension] != nil {
return nil, errors.New("Error: Conflicting .hbs name '" + fileNameWithoutExtension + "'. A theme file of the same name already exists.")
}
helper := compileTemplate(data, fileNameWithoutExtension)
return helper, nil
}
该函数主要是读取模板文件,然后调用compileTemplate(data, fileNameWithoutExtension)
做最终编译。
模板编译方面更细节的东西我就没什么兴趣了,大家有兴趣可以自己研究下,欢迎交流^_^