介绍一下

LiveReload

livereload是一个非常好用的自动加载插件,通过监控文件改变,通过本地的一个websocket与前端页面实现实时同步自动刷新的效果。极大地方便了前端编辑的过程。

具体安装可使用可以参考官方网站

Jinja2

用过Django的同学想来对其模板引擎有所印象,当然由于Django的官方设计,他的模板引擎有很多设计性限制,所以Jinja2项目诞生了。这是一个在绝大多数地方都与Django原生模板引擎相似的独立模块,可以单独使用也可以替换Django的渲染组件,主要增强了Django模板组件的诸多限制性设计,诸如函数调用参数,过滤器参数限制等。同时也可以脱离引擎独立使用。

这里是他的官方网站

Sublime + LiveReload + Jinja2

Sublime上通过Package Control工具可以很轻松的安装LiveReload组件,通过pip也很容易就安装上Jinja2引擎。不过这两者之间如何合作使用就需要动一番心思了。

在LiveReload的Sublime插件上,原生自带了一些模块的自动渲染插件,具体可以在LiveReload: Enable/disable plug-ins中找到,那么很显然的一个想法自然就是按照类似的办法写一个Jinja2的渲染脚本了。

具体步骤

首先呢,进入Sublime菜单的Browse Packages,定向到LiveReload目录。直接拷贝LESSPlugin.py组件重命名为JinJa2Plugin.py

打开JinJa2Plugin.py代码,可以看到插件的接口设计还是非常清楚的,首先先修改一下里面两个类的名字(JinJa2Thread和JinJa2Preprocessor)和一些描述性信息,这里我们就把后缀改为.tmpl好了,输出目标为.html文件。

在JinJa2Thread.init()函数中,有一些获取参数的代码,我们这里就不需要了,因为Jinja2可以直接通过python调用,直接删掉原来的这一小段代码即可。

核心操作在JinJa2Thread.run()函数中,这个函数我们作如下修改:

    def run(self):
        ofile = open(self.dirname + "/" + self.filename.replace('.tmpl','.html'), 'w', encoding='utf-8')

        from jinja2 import Template
        from jinja2 import FileSystemLoader
        from jinja2.environment import Environment

        env = Environment()
        env.loader = FileSystemLoader(self.dirname)
        tmpl = env.get_template(self.filename)
        output = tmpl.render(name='John Doe')

        ofile.write(output)

        ofile.close()

        if (output):
            # print(output)
            self.on_compile()

简单解释一下,需要处理的文件名字就是self.filename,那么修改他的后缀到输出文件上,然后调用Jinja2的库,执行文件载入和渲染的步骤,这里我示例性地加了一个参数,当然这是无所谓的。目前的这个脚本并没有传递参数的功能,或许后续有需要会考虑加一下,那么现在就先不动了。

随后,获取到渲染输出后将其写入目标文件,并触发编译指令结束。

全部的代码如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import threading
import subprocess
import sys
import sublime
import sublime_plugin

# fix for import order

sys.path.append(os.path.join(sublime.packages_path(), 'LiveReload'))
LiveReload = __import__('LiveReload')
sys.path.remove(os.path.join(sublime.packages_path(), 'LiveReload'))


class JinJa2Thread(threading.Thread):

    def getLocalOverride(self):
        try:
            view_settings = sublime.active_window().active_view().settings()
            view_settings = view_settings.get('jinja2')
            if view_settings:
                return view_settings
            else:
                return {}
        except Exception:
            return {}

    def __init__(self, dirname, on_compile, filename):

        self.filename = filename

        ##TODO: Proper handler for this
        try:
            self.dirname = self.getLocalOverride.get('dirname') \
            or dirname.replace('\\', '/')
        except Exception as e:
            self.dirname = dirname.replace('\\', '/')
        self.stdout = None
        self.stderr = None
        self.on_compile = on_compile
        threading.Thread.__init__(self)

    def run(self):
        ofile = open(self.dirname + "/" + self.filename.replace('.tmpl','.html'), 'w', encoding='utf-8')

        from jinja2 import Template
        from jinja2 import FileSystemLoader
        from jinja2.environment import Environment

        env = Environment()
        env.loader = FileSystemLoader(self.dirname)
        tmpl = env.get_template(self.filename)
        output = tmpl.render(name='John Doe')

        ofile.write(output)

        ofile.close()

        if (output):
            # print(output)
            self.on_compile()

class JinJa2Preprocessor(LiveReload.Plugin, sublime_plugin.EventListener):

    title = 'JinJa2 Preprocessor'
    description = 'JinJa2 Compile and refresh page, when file is compiled'
    file_types = '.tmpl'
    this_session_only = True
    file_name = ''

    def on_post_save(self, view):
        self.original_filename = os.path.basename(view.file_name())

        if self.should_run(self.original_filename):
            self.file_name_to_refresh = \
                self.original_filename.replace('.tmpl', '.html')
            dirname = os.path.dirname(view.file_name())
            JinJa2Thread(dirname, self.on_compile, self.original_filename).start()

    def on_compile(self):
        print(self.file_name_to_refresh)
        settings = {
            'path': self.file_name_to_refresh,
            'apply_js_live': False,
            'apply_css_live': True,
            'apply_images_live': True,
            }
        self.sendCommand('refresh', settings, self.original_filename)