geeeger / blog

https://loofp.com
1 stars 0 forks source link

如何将fis3 smarty模板使用js渲染出来 #16

Open geeeger opened 4 years ago

geeeger commented 4 years ago

首先,理论上是可以转的,自己是写不动解析器,所以直接找网上的开源库折腾.

声明:仅作为参考实验,未高度完成。

需要的材料

由于jsmart的组织形式,需要rewrite一些原型链内容

示例配置(注意,仅支持了1层文件路径)

var fs = require('fs')
var path = require('path')
var root = process.cwd()

var template = './detail.tpl'

var TemplateMapConfig = {
    'h5common/layout/base.tpl': './mbase.tpl',
    '../../../layout/base.tpl': './base.tpl'
}

module.exports = {
    template: path.join(root, template),
    options: {
        // Left delimiter.
        ldelim: '{%',
        // Right delimiter.
        rdelim: '%}',
        // Whether to skip tags in open brace { followed by white space(s) and close brace } with white space(s) before.
        autoLiteral: true,
        // If user wants debug to be enabled.
        debugging: true,
        // Escape html??
        escapeHtml: false
    },
    protoRewrites: {
        getTemplate: function (name) {
            if (name in TemplateMapConfig) {
                name = TemplateMapConfig[name]
            }
            return fs.readFileSync(path.join(process.cwd(), name), {encoding: 'utf-8'})
        },
        getFile: function (name) {
            if (name.startsWith('http')) {
                // bug: windows curl returns is difference with linux
                return require('child_process').execFileSync('curl', ['--silent', name], {encoding: 'utf8', maxBuffer: Infinity})
            }
            if (name in TemplateMapConfig) {
                name = TemplateMapConfig[name]
            }
            return fs.readFileSync(path.join(process.cwd(), name), {encoding: 'utf-8'})
        },
        getJavascript: function (name) {
            throw new Error('No Javascript for ' + name)
        },
        getConfig: function (name) {
            return fs.readFileSync(path.join(process.cwd(), name), {encoding: 'utf-8'})
        }
    },
    plugins: [
        // 补充完fis smarty plugins
        ['modifier', 'f_escape_xml', function (x) {
            return x.replace(/[&<>'"]/g, function (a) {
                return {
                    '&': '&amp;',
                    '<': '&lt;',
                    '>': '&gt;',
                    '\'': '&#39;',
                    '"': '&quot;'
                }[a]
            })
        }],
        ['modifier', 'f_escape_callback', function (callback, len = 50) {
            callback = callback.substr(0, len);
            callback = callback.replace(/[^\w\.]/, '')
            callbackSplit = callback.split('.')
            var first = callbackSplit[0].toLowerCase()
            if (['window', 'document', 'alert', 'location'].indexOf(first) !== -1) {
                return false
            }
            return callback
        }],
        ['modifier', 'f_escape_data', function (x) {
            return x.replace(/[&<>"'\n\r/\\]/g, function (a) {
                return {
                    '&': '&amp;',
                    '<': '&lt;',
                    '>': '&gt;',
                    '\'': '\\&#39;',
                    '"': '\\&quot;',
                    '\\': '\\\\',
                    '\n': '\\n',
                    '\r': '\\r',
                    '/': '\\/'
                }[a]
            })
        }],
        ['modifier', 'f_escape_event', function (x) {
            return x.replace(/[&<>"'\n\r/\\]/g, function (a) {
                return {
                    '&': '&amp;',
                    '<': '&lt;',
                    '>': '&gt;',
                    '\'': '\\&#39;',
                    '"': '\\&quot;',
                    '\\': '\\\\',
                    '\n': '\\n',
                    '\r': '\\r',
                    '/': '\\/'
                }[a]
            })
        }],
        ['modifier', 'f_escape_js', function (x) {
            return x.replace(/["'\n\r/\\]/g, function (a) {
                return {
                    '\'': '\\x27;',
                    '"': '\\x22',
                    '\\': '\\\\',
                    '\n': '\\n',
                    '\r': '\\r',
                    '/': '\\/'
                }[a]
            })
        }],
        ['modifier', 'f_escape_path', function (x, type = 'urlpathinfo') {
            switch (type) {
                case 'urlpathinfo':
                    return x.replace(/%3A/g,':').replace(/%2F/g,'/');
                case 'url':
                    return encodeURIComponent(x)
                default:
                    return x;
            }
        }],
        ['block', 'html', function (params, content, data, repeat) {
            var result = '<html '
            for (var k in params) {
                if (params.hasOwnProperty(k) && k !== '__get') {
                    result += k + '=' + '"' + params[k] + '" '
                }
            }
            // if setFramework
            // todo
            result += '>\r\n' + content + '\r\n'
            return result + '</html>'
        }],
        ['function', 'require', function (params) {
            var name = params.__get('name')
            return `<script src="${name}">//resource</script>`
        }],
        ['block', 'head', function (params, content, data, repeat) {
            return '<head>\r\n' + content + '\r\n<!--[FIS_CSS_LINKS_HOOK]-->\r\n<!--[FIS_CSS_STYLE_HOOK]-->\r\n</head>'
        }],
        ['block', 'body', function (params, content, data, repeat) {
            return '<body>\r\n' + content + '\r\n<!--[FIS_FRAMEWORK_HOOK]-->' + '\r\n<!--[FIS_JS_SCRIPT_HOOK]-->\r\n</body>'
        }]
    ],
    vars: {
        jsConfig: '""',
        result: {
            page: {}
        }
    }
}

示例app.js

var fs = require('fs');
var jSmart = require('jsmart');
var path = require('path');
var rootDir = process.cwd()

var configPath = path.join(rootDir, 'jsmart.config.js')

var config = {}

if (fs.existsSync(configPath)) {
    config = require(configPath)
} else {
    throw new Error('jsmartConfig is not found!')
}

var tpl = fs.readFileSync(config.template, {encoding: 'utf-8'});

if (config.protoRewrites) {
    for (var key in config.protoRewrites) {
        jSmart.prototype[key] = config.protoRewrites[key]
    }
}

if (config.plugins) {
    config.plugins.forEach(item => {
        jSmart.prototype.registerPlugin.apply(jSmart.prototype, item)
    })
}

var compiledTemplate = new jSmart(tpl, config.options);

var output = compiledTemplate.fetch(config.vars);

fs.writeFileSync('detail.html', output, {encoding: 'utf-8'})

console.log(output);