2019独角兽企业重金招聘Python工程师标准>>>
在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 pathactiveTheme, err := database.RetrieveActiveTheme()if err != nil {return err}currentThemePath := filepath.Join(filenames.ThemesFilepath, *activeTheme)// Create watchererr = 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 databaseerr = 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 databaseerr = 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 compiledif _, 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] = helperreturn 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)
做最终编译。
模板编译方面更细节的东西我就没什么兴趣了,大家有兴趣可以自己研究下,欢迎交流^_^