UNPKG

mya-jinja

Version:

Support Jinja2 end template engine in mya

214 lines (183 loc) 6.51 kB
/** * mya jinja 解决方案 * @dependance: mya-server-jina fis-optimizer-jinja-xss */ const path = require('path'); const CLIEngine = require("eslint").CLIEngine; // 补全模版路径 function getFullTplPath(content, templatePublishPath) { // {% extends "path" %} -> {% extends "${templatePublishPath/path" %} content = content.replace(/({%\s*(?:extends|include)\s+["|'])(\S+)(["|'](?:.+?)%})/ig, function(match, p1, p2, p3) { if (p2.charAt(0) === '/') { return `${p1}${templatePublishPath}${p2}${p3}`; } else { return `${p1}${templatePublishPath}/${p2}${p3}`; } }); return content; } function tplPathProcessor(content, file, conf) { const templatePublishPath = fis.get('build.templatePublishPath'); return getFullTplPath(content, templatePublishPath); } // 支持 {% uri src="static/image/i18n/{{ _mya_locale }}/xxx.png" %} 动态路径,自动补充 namespace function dynamicPathFix(content, file, conf) { const ns = fis.get('namespace'); content = content.replace(/({%\s*uri\s+src\s*=\s*['"])(.+?)(['"]\s*%})/ig, function(match, left, uri, right) { if (uri.indexOf(ns + ':') === 0) { return `${left}${uri}${right}`; } else { return `${left}${ns}:${uri}${right}`; } }); return content; } function retMapPostpackager(ret) { const root = fis.project.getProjectPath(); const map = fis.file.wrap(path.join(root, fis.get('namespace') ? fis.get('namespace') + '-map.json' : 'map.json'));; map.setContent(JSON.stringify(ret.map, null, map.optimizer ? null : 4)); // ret.map 为静态资源映射表 ret.pkg[map.subpath] = map; } function lintES6(content, file, conf) { const options = { env: [ 'browser' ], useEslintrc: false, plugins: [ 'es' ], parserOptions: { ecmaVersion: 6 }, baseConfig: { extends: [ 'plugin:es/no-2015' ], }, rules: { 'es/no-rest-spread-properties': 'off', 'es/no-template-literals': 'off', 'es/no-block-scoped-functions': 'off' } }; const CLIEngine = require("eslint").CLIEngine; const cli = new CLIEngine(options); const jinjaReservedPattern = /\{(\{|#|%)(.*?)(\}|\1)\}/ig; let temp = content.replace(jinjaReservedPattern, function(match) { return 1 + new Array(match.length).join(0); }); const messages = cli.executeOnText(temp, file.basename); const errorReport = CLIEngine.getErrorResults(messages.results); if (errorReport && Array.isArray(errorReport) && errorReport.length) { errorReport[0].messages.forEach(messageObj => { process.stdout.write('\n ' + `${file.fullname}`.underline + '\n ' + 'ERROR'.red + ' ' + `${messageObj.message}`.yellow + ' ' + `${messageObj.ruleId}` + '\n'); }) process.exit(1); } return content; } module.exports = function(fis, opt) { fis.set('server.type', 'jinja'); fis.set('settings.parser.babel-7.x', { noSourceMaps: true }); fis.match('*.html', { // 仅 html 文件开启同名依赖,依赖同名 css/js useSameNameRequire: true, useCache: false }); fis.match('/(**.html)', { useMap: true, preprocessor: fis.plugin('extlang'), postprocessor: [ tplPathProcessor, dynamicPathFix, ], optimizer: [ fis.plugin('jinja-xss'), fis.plugin('html-minifier', { // 不处理自定义注释 ignoreCustomComments: [/^\s*(STYLE_PLACEHOLDER|SCRIPT_PLACEHOLDER|I18N_MAP_PLACEHOLDER)/], // 不处理 jinja2 语法 ignoreCustomFragments: [ /{#[\s\S]*?#}/, /{{[\s\S]*?}}/, /{%\s*script[\s\S]*?endscript\s*%}/, /{%[\s\S]*?%}/, ], }) ] }, true); fis.match('${namespace}-map.json', { release: '/template/mya_conf/$0' }); fis.match('::package', { postpackager: function createMap(ret) { retMapPostpackager(ret); } }); // deploy 不走 skip-packed 插件 fis.match('**', { deploy: fis.plugin('local-deliver') }); fis.match('/{component,page}/**/mock.json', { useCompile: false, rExt: 'json', release: false }); // 模板文件中的js不要使用 es6,因为模板文件可以传递变量,比如 init({{ rate|e }}),这种在编译时会报错 fis.match('/{component,page,common,*_common}/**.html:js', { lint: null, preprocessor: null, rExt: 'js', parser: lintES6, optimizer: null }); // 开发配置 const devRules = { '/test/api/(**.{json,js})': { useHash: false, isMod: false, useCompile: false, release: 'mock/${namespace}/api/$1' }, // 全局 mock 数据 '/test/page/mock.json': { useHash: false, release: 'mock/${namespace}/page/mock.json' }, // 就近维护mock数据(推荐) '/page/(**)/mock.json': { userHash: false, release: 'mock/${namespace}/page/$1/index.json' }, '/component/(**)/mock.json': { userHash: false, release: 'mock/${namespace}/component/$1/index.json' }, '::package': { postpackager: function createMap(ret) { retMapPostpackager(ret); } }, 'server.{page,mock,proxy}.conf': { preprocessor: function(content, file, conf) { const namespace = fis.get('namespace'); return content.replace(/(rewrite\s+\S+\s+)(\S+)/g, `$1/${namespace}$2`) }, release: '$0' }, 'server.conf': { release: 'server-conf/${namespace}.conf' } }; ['develop', 'mock', 'prod'].forEach(function(media) { Object.keys(devRules).forEach(function(key) { fis.media(media).match(key, devRules[key], true); // 防止规则被覆盖 }); }); if (opt && opt.i18n) { require('./plugin/i18n.js')(fis, opt, retMapPostpackager); } if (opt && opt.falcon) { require('./plugin/falcon.js')(fis, opt); } };