isv-zebra-page-generator
Version:
斑马页面(solution)生成器
265 lines (241 loc) • 10.5 kB
JavaScript
var fs = require('fs');
var path = require('path');
var Debug = require('debug');
var debug = Debug('zebra');
var debugMini = Debug('zebra:mini');
var debugError = Debug('zebra:error');
var debugExtra = Debug('zebra:extra');
var _ = require('lodash');
var request = require('sync-request');
var Client = require('isv-module-info');
var upxClient = Client.upxClient('production');
// 通过gitlab方式获取
// 例如:http://gitlab.alibaba-inc.com/zebra-solution/tb-rx/raw/master/build/index-native.xtpl
var URL_SOLUTION_BASE = 'http://gitlab.alibaba-inc.com/zebra-solution/${siteName}/raw/${branch}/build/${fileName}';
function readFileOrEmpty(path) {
try {
debugMini('=====> 读取 ' + path + '文件内容');
return fs.readFileSync(path, 'utf8');
} catch (err) {
debugError('=====> 读取 ' + path + '文件内容失败:', err);
return "";
}
}
function removeDeps(deps){ // 去除pc端公共的库引用,比如io等,因为这些都是通过 solution 引入了;
var str = JSON.stringify(deps); // 转换成str
var list = ['loader','node','util','dom','event-gesture','event-dom','event-custom','event','io','ua','querystring','promise','path','json','feature','base','attribute','anim','url','cookie','@ali/lib-promise/build/polyfillB'];
list.forEach(function(modName){
var reg = new RegExp('\"'+modName+'\"','g');
str = str.replace(reg,'\"\"');
});
debug('=====> 去除公共模块之后的依赖(字符串):',str);
debug('=====> 去除公共模块之后的依赖(json);',JSON.parse(str));
return JSON.parse(str);
}
function writeFileOrNone(path, data) {
fs.writeFile(path, data, 'utf8', function(err) {
if (err) {
console.log('=====> 写入数据到' + path + '失败:', err);
debugError('=====> 想要写入的数据:' + data);
return;
}
debugMini('=====> 已将数据写入到:' + path);
debug('=====> 文件内容:' + data);
});
}
// 计算同步执行callback所花费的时间
function calcTime(fn, msg) {
var oStart = new Date();
fn();
var oEnd = new Date();
console.log(msg, ':', (oEnd - oStart) / 1000, 's');
}
function parseOrFalse(str) {
var json = {}
try {
if (str.length) {
json = JSON.parse(str);
debugMini('=====> 将字符串解析成 JSON 成功');
debug('=====> 获得的 JSON 的内容:' + json);
return json;
} else {
return false;
}
} catch (err) {
debugError('=====> 将字符串解析成 JSON 失败:', err);
debugError('=====> 原字符串内容:' + str);
return false;
}
}
// 获取远程站点上的文件,如果不存在就在本地solution文件夹下获取
// siteName: 站点名字,比如 'tb-rx'
// fileName: 想要获取的文件
// isJsonFile: 是否是json文件
function getFileContent(siteName, branch, fileName, isJsonFile) {
var filePath = path.join(__dirname, 'solution', fileName);
var targetUrl = URL_SOLUTION_BASE.replace('${siteName}', siteName).replace('${branch}', branch).replace('${fileName}', fileName);
var res = request('GET', targetUrl);
var result = res.getBody().toString();
debug('=====> ' + targetUrl + '请求结果:', result);
var filePath = path.join(__dirname, 'solution', fileName);
// 如果解析失败,使用之前缓存的文件
// result = false;
if (!result) {
// 使用本地备用的
console.log('获取站点', siteName, '下的' + fileName + '失败,改用缓存文件:', filePath);
result = readFileOrEmpty(filePath);
if (!result) { // 如果读取不到本地文件内容,需要提示其重试
console.log('==== 本地缓存solution文件读取为空,将渲染失败,请重新dev !! ====');
}
debug('=====> 内置备用的' + fileName + '内容', result);
} else {
// 如果解析成功就缓存到本地文件
debug('=====> 获取站点', siteName, '下的' + fileName + '成功:', result);
writeFileOrNone(filePath, result);
}
// 如果是json文件,需要解析成json格式
if (isJsonFile) {
result = parseOrFalse(result);
}
return result;
}
// 根据配置获取xtpl模板的后缀
function getPageSuffix(runConfig) {
var suffix = ''; // 默认是无线页面
if (runConfig.terminalType === 'pc') {
suffix = '-pc';
} else if (runConfig.wh_ttid === 'native') {
suffix = '-native';
}
return suffix;
}
function getXtpl(siteName, branch, runConfig, seed, pageData) {
var modules = pageData.layout.modules; // 获取modules
var suffix = getPageSuffix(runConfig);
var xtplName = 'index' + suffix + '.xtpl';
// 获取xtpl文件
var xtpl = getFileContent(siteName, branch, xtplName);
// 貌似不能直接设置$zebra,自定义字段
xtpl = "{{set($zebra = $data.$zebra)}}{{set($pageData = $data.$pageData)}}" + xtpl;
// ======= kimi6 & kissy: 也需要替换 block("body") ======
var platform = pageData.platform && pageData.platform[0];
// console.log('44444,', platform, pageData.extraLib);
if (platform === 'pc' || (platform === 'mobile' && pageData.extraLib == 'null')) {
// console.log('5555', platform, pageData.extraLib);
var REG_PC_HTML = /\{{3}block\s*\(\"body\"\)\}{3}/g;
// 同时需要将 {{{block ("body")}}} 元素替换成 特定的 html片段
var htmlCode = '{{#each($zebra.components)}}<div class="module-wrap J_Mod {{name}}" data-spm="{{spmC}}" id="J_{{moduleId}}" data-name="{{name}}" data-group="{{group}}" data-version="{{version}}">{{{html}}}</div>{{/each}}';
xtpl = xtpl.replace(REG_PC_HTML, htmlCode);
// ===== end ======
}
// 如果是pc端的文件,默认引用资源文件 index-pc.js,本地调试需要临时替换成 index.js
if (runConfig.terminalType === 'pc') {
// 匹配模板的名字声明
var REG_PC = /\'\/index-pc\'/g;
xtpl = xtpl.replace(REG_PC, "'/index'"); // 替换成pc
} else if (runConfig.wh_ttid === 'native') { // 如果是native
var requires = [];
modules.forEach(function(mod) {
requires = requires.concat(seed.modules[mod.group + '/' + mod.name + '/index-native.xtpl'].requires);
});
var strReq = '';
_.uniq(requires).forEach(function(req) {
strReq += '{{require("' + req + '")}}';
});
var REG_NATIVE_SOURCE = /\{{3}sourceCode\}{3}/g;
xtpl = xtpl.replace(REG_NATIVE_SOURCE, strReq + '{{{sourceCode}}}'); // 替换成pc
debugMini('=====> 获取的依赖表:', strReq);
}
var HACK_REG = /set\(modName= /;
xtpl = xtpl.replace(HACK_REG, "set\(modName= 'upx/tb-mod/' + ");
return xtpl;
}
// 组装成斑马渲染参数
function zebraParams(seed, xtpl, zebraData) {
return {
"page": {
"templates": {
"index.xtpl": xtpl, //模板入口,必选
"seed.json": seed && JSON.stringify(seed)
}
},
"data": {
"$zebra": zebraData,
"page": zebraData.$pageData
},
"intranet": true //是否内网,默认true (可选)
}
}
// 重新装配用于斑马模块的渲染数据
// 主要是映射数据关系
function reassemble(pageData, runConfig) {
var isBaseUpx = !!pageData.guideName;
var newData = {};
newData.isLocal = true;
newData.spma = pageData.spmA;
newData.spmb = pageData.spmB;
newData.keywords = pageData.keywords && pageData.keywords.join(',');
newData.description = pageData.description;
newData.title = pageData.title;
newData.$pageData = {};
newData.components = pageData.layout.modules.map(function(mod) {
var newMod = {};
newMod.name = mod.name;
newMod.fullName = isBaseUpx ? ['upx', mod.group, mod.name].join('/') : [mod.group, mod.name].join('/');
newMod.version = mod.versionForZebra;
newMod.moduleId = "module_" + mod.id;
newMod.config = mod.attrs;
newMod.dataId = mod.id;
newMod.rmcId = mod.id;
newMod.html = mod.html;
newMod.group = mod.group;
newData.$pageData[mod.id] = mod.data;
// tce 相关配置
newMod.dataSourceType = mod.dataSourceType;
newMod.tceEntryPoint = mod.tceEntryPoint;
newMod.tceConfig = mod.tceConfig;
// 针对native,增加sourceCode字段,用于直接输出
if (runConfig.wh_ttid === 'native') {
var cwd = process.cwd(); // 获取当前工作目录
// native 缓存文件
var cacheDir = path.join(cwd, 'mod', mod.name, CACHE_DIR);
var targetNativePath = path.join(cacheDir, CACHE_SOURCE_NATIVE); // native 源码
var targetOriginPath = path.join(cacheDir, CACHE_SOURCE_ORIGIN); // index 源码
newMod.sourceCode = readFileOrEmpty(targetNativePath);
debugMini('=====> 读取缓存源码(打包后)路径', targetNativePath);
debug('=====> 读取到的打包文件内容:', newMod.sourceCode);
// 做一层兼容,如果读取不到 native 源码,就去读index源码
if (!newMod.sourceCode) {
console.log('从', targetNativePath, '读取到的内容为空,转而读取', targetOriginPath);
newMod.sourceCode = readFileOrEmpty(targetOriginPath);
debug('=====> 读取到的打包文件内容:', newMod.sourceCode);
}
}
return newMod;
});
newData.modules = _.clone(newData.components); // 用于native渲染的字段
return newData;
}
function getEndType(runConfig){
var endType = 'web';
if(runConfig.terminalType === 'pc'){
endType = 'pc';
} else if(runConfig.wh_ttid === 'native') {
endType = 'native';
}
return endType;
}
module.exports = {
readFileOrEmpty: readFileOrEmpty,
writeFileOrNone: writeFileOrNone,
calcTime: calcTime,
getFileContent: getFileContent,
getPageSuffix: getPageSuffix,
upxClient: upxClient,
getXtpl: getXtpl,
zebraParams: zebraParams,
reassemble: reassemble,
getEndType: getEndType,
parseOrFalse: parseOrFalse,
removeDeps: removeDeps
}