mz-fis
Version:
A PHP i18n Framework based on FIS3
528 lines (461 loc) • 14.2 kB
JavaScript
//vi mz/index.js
var fis = require('fis3');
var lolcat = require('fis-lolcat');
var path = require('path');
var closest = require('closest-package');
var cloneObjectOrdered = function (obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
var temp = obj.constructor();
if (Array.isArray(obj)) {
[].concat(obj).sort().forEach(function (value, index) {
temp[index] = cloneObjectOrdered(value);
});
} else {
Object.keys(obj).sort().forEach(function (key) {
temp[key] = cloneObjectOrdered(obj[key]);
});
}
return temp;
}
fis.require.prefixes.unshift('mz');
fis.cli.name = 'mz';
fis.cli.info = require('./package.json');
/**
* 输出 mz 版本信息。
*
* ```
*
* __/\\\\____________/\\\\__/\\\\\\\\\\\\\\\_
* _\/\\\\\\________/\\\\\\_\////////////\\\__
* _\/\\\//\\\____/\\\//\\\___________/\\\/___
* _\/\\\\///\\\/\\\/_\/\\\_________/\\\/_____
* _\/\\\__\///\\\/___\/\\\_______/\\\/_______
* _\/\\\____\///_____\/\\\_____/\\\/_________
* _\/\\\_____________\/\\\___/\\\/___________
* _\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_
* _\///______________\///__\///////////////__
* ```
*
*/
fis.cli.version = function () {
var content = ['',
' v' + fis.cli.info.version,
''
].join('\n');
var logo = [
" /\\\\\\\\ /\\\\\\\\ /\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ",
" \\/\\\\\\\\\\\\ /\\\\\\\\\\\\ \\////////////\\\\\\ ",
" \\/\\\\\\//\\\\\\ /\\\\\\//\\\\\\ /\\\\\\/ ",
" \\/\\\\\\\\///\\\\\\/\\\\\\/ \\/\\\\\\ /\\\\\\/ ",
" \\/\\\\\\ \\///\\\\\\/ \\/\\\\\\ /\\\\\\/ ",
" \\/\\\\\\ \\/// \\/\\\\\\ /\\\\\\/ ",
" \\/\\\\\\ \\/\\\\\\ /\\\\\\/ ",
" \\/\\\\\\ \\/\\\\\\ /\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ",
" \\/// \\/// \\/////////////// ",
""
].join('\n');
if (fis.get('options.color') !== false) {
logo = lolcat(logo);
}
console.log(content + '\n' + logo);
};
var sets = {
'namespace': '',
'static': 'static',
'template': 'template',
'rewriteFilename': '',
'smarty': {
'left_delimiter': '<{',
'right_delimiter': '}>'
},
'browsers': ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1'],
'server': {
'rewrite': false,
'type': 'php',
'libs': '',
'clean': {
'include': '**.*',
'exclude': ''
}
}
};
fis.util.map(sets, function (key, value) {
fis.set(key, value);
});
fis.set('project.ignore', ['node_modules/**', 'output/**', '.git/**', '**/.svn/**', 'fis-conf.js', '**/_*', '_*/*']); // set 为覆盖不是叠加
fis.set('component.github.author', 'mz-components');
//addSameNameRequire 会用到
fis.set('project.ext', {
po: 'json',
scss: 'css'
});
//增加 ::image 的类型
fis.set('project.fileType.image', ['mp3', 'mp4', 'webm', 'flv']);
//增加 livereload 与 weinre 的本地 IP 限制
fis.config.set('livereload-iprule', '(?!127)*.*.*.*');
fis.config.set('weinre-iprule', '(?!127)*.*.*.*');
//模块化方案,本项目选中CommonJS方案(同样支持异步加载哈)
fis.hook('commonjs', {
});
//相对路径
fis.hook('relative');
fis.match('**/*.scss', {
rExt: '.css', // from .scss to .css
parser: [function (content, file, settings) {
var prependScss = [], appendScss = [];
//若指定 globalVarScss ,则所有 scss 文件自动 import 这个文件,通常用来定义全局 @mixin
var globalVarScss = fis.get('globalVarScss');
if (globalVarScss) {
prependScss.push('/*!' + globalVarScss + '*/');
prependScss.push('@import "' + globalVarScss + '";');
}
//自动 import 同目录同名 .custom.scss
var customFileExt = '.custom.scss';
if (fis.get('autoImportCustomScss')) {
if (fis.util.isFile(file.realpathNoExt + customFileExt)) {
var customFilename = file.filename + customFileExt;
appendScss.push('/*!' + customFilename + '*/');
appendScss.push('@import "' + customFilename + '";');
}
}
//自动 import 父级目录下与父级目录同名的 scss
if (fis.get('autoImportParentScss')) {
var parentDir = file.dirname.match(/^(.*\/([^\/]+))\/[^\/]+$/);
var parentFilename = parentDir[2] + '.scss';
if (fis.util.isFile(parentDir[1] + '/' + parentFilename)) {
prependScss.push('/*!' + parentFilename + '*/');
prependScss.push('@import "../' + parentFilename + '";');
}
var parentCustomFilename = parentDir[2] + customFileExt;
if (fis.get('autoImportCustomScss') && fis.util.isFile(parentDir[1] + '/' + parentCustomFilename)) {
prependScss.push('/*!' + parentCustomFilename + '*/');
prependScss.push('@import "../' + parentCustomFilename + '";');
}
}
content = prependScss.join('\n') + content;
content = content + appendScss.join('\n');
return content;
}, fis.plugin('node-sass', {
// fis-parser-node-sass option
})]
});
fis.match('*', {
useHash: false // md5 都关掉
// release: '/${static}/${namespace}/$0'
});
fis.match('*.html', {
postprocessor: fis.plugin('href-locate', {})
});
fis.match('*.tpl', {
parser: [
fis.plugin('partial'),
function (content, file, settings) {
return content.replace(/\{\{(?:(\w+)\:)?([\.\w]+)\}\}/g, function (str, func, arg) {
if (func) {
return fis[func](arg);
} else {
return fis.get(arg);
}
});
}],
preprocessor: [fis.plugin('extlang', {
'left_delimiter': sets.smarty.left_delimiter,
'right_delimiter': sets.smarty.right_delimiter
}), fis.plugin('components')],
postprocessor: [
fis.plugin('require-async', {
'left_delimiter': sets.smarty.left_delimiter,
'right_delimiter': sets.smarty.right_delimiter
}),
fis.plugin('href-locate', {
'left_delimiter': sets.smarty.left_delimiter,
'right_delimiter': sets.smarty.right_delimiter
})
],
optimizer: [
fis.plugin('smarty-xss'),
// fis.plugin('html-compress',{
// 'level' : 'strip',
// 'leftDelimiter' : sets.smarty.left_delimiter,
// 'rightDelimiter' : sets.smarty.right_delimiter
// })
],
useMap: true,
isMod: true,
useSameNameRequire: true,
release: '/${template}/${namespace}/$0'
});
fis.match('*.js', {
useSameNameRequire: true,
preprocessor: fis.plugin('components')
});
fis.match('/page/**.tpl', {
// 标记是否是个页面,向下兼容
extras: {
isPage: true
}
});
fis.match('/lang/(*).po', {
release: '/config/lang/${namespace}.$1.po',
rExt: '.json',
parser: fis.plugin('po', {
})
});
fis.match('/components/**', {
useMap: true,
release: '/${static}/${namespace}/$0'
});
fis.match('/components/**.{css,js}', {
isMod: true
});
fis.match('/components/**.{json,md}', {
release: false
});
fis.match('/${static}/(**)', {
release: '/${static}/${namespace}/$1'
});
fis.match('/widget/**', {
release: '/${static}/${namespace}/$0'
});
fis.match('/widget/**.{css,js}', {
isMod: true
});
fis.match('/widget/(**.tpl)', {
release: '/${template}/${namespace}/$0',
url: '${namespace}/widget/$1',
});
fis.match('/{plugin/**,smarty/**,php-simulation-env/**,smarty.conf,domain.conf,**.php}', {
useMap: false,
isMod: false,
release: '$0'
});
fis.match('/html/(**)', {
release: '/${static}/${namespace}/$1'
});
fis.match('*.html:js', {
preprocessor: fis.plugin('components')
});
fis.match('/server.conf', {
parser: [function (content, file, settings) {
content = content.replace(/(\^\S*)\{\{([\.\w]+)\}\}/g, function (a, b, c) {
return b + fis.get(c).replace(/\//g, '\\\/');
});
return content.replace(/\{\{([\.\w]+)\}\}/g, function (a, b, c) {
return fis.get(b);
});
}],
release: '/server-conf/${rewriteFilename}.conf'
});
// test & config
fis.match('/({test,config})/(**)', {
useMap: false,
release: '/$1/${namespace}/$2'
});
fis.match('${namespace}-map.json', {
release: '/config/$0'
});
fis.match('::package', {
prepackager: [
fis.plugin('widget-inline'),
fis.plugin('js-i18n', {
enable: true,
left_delimiter: sets.smarty.left_delimiter,
right_delimiter: sets.smarty.right_delimiter
})
],
postpackager: [require('./lib/livereload-target.js'), require('./lib/weinre-target.js'), function createMap(ret) {
if (fis.get('namespace')) {
var path = require('path');
var root = fis.project.getProjectPath();
var map = fis.file.wrap(path.join(root, fis.get('namespace') + '-map.json'));
var orderedMap = cloneObjectOrdered(ret.map);
if (Object.keys(ret.map.res).length) {
map.setContent(JSON.stringify(orderedMap, null, 2));
ret.pkg[map.subpath] = map;
}
}
}],
spriter: fis.plugin('csssprites')
});
//不用被mod
fis.match(/.*\.partial\.js$/, {
isMod: false
});
fis.match('/favicon.ico', {
useHash: false,
release: '$0'
}, true);
// 打包配置,packOrder设置匹配文件在包中的出现顺序,值越小越靠前,默认-1
fis.match('/static/lib/mod.js', { packOrder: -101 });
fis.match('{' + [
'/static/global/global.scss',
'/components/jquery/jquery.js',
'/components/zepto/zepto.js'
].join() + '}', {
packOrder: -100
});
fis.match('tracker.js', { packOrder: 100 });
// mz release prod 线上环境,sqa为测试环境
['prod', 'sqa'].forEach(function (_mediaName_) {
fis.media(_mediaName_)
.match('*.js', {
useHash: true,
optimizer: fis.plugin('uglify-js')
})
.match('*.{css,scss}', {
useHash: true,
useSprite: true,
optimizer: fis.plugin('clean-css')
})
.match('::image', {
useHash: true,
})
.match('*.png', {
useHash: true,
optimizer: fis.plugin('png-compress', {
type: 'pngquant',
})
})
.match('*.hd.png', {
useHash: true,
optimizer: false
})
.match('*.html', {
optimizer: fis.plugin('html-minifier')
})
.match('*.tpl', {
parser: [
fis.plugin('partial', { type: 'ssi' }),
function (content, file, settings) {
return content.replace(/\{\{(?:(\w+)\:)?([\.\w]+)\}\}/g, function (str, func, arg) {
if (func) {
return fis[func](arg);
} else {
return fis.get(arg);
}
});
}]
});
//这条配置与 hook-relative 一起用的时候有bug,所以开启relative就关掉压缩
});
//项目 fis-conf.js set完后再运行
fis.mount = function (config) {
if (typeof config === 'function') {
return config(fis);
} else if (!config) {
return;
} else {
for (var i in config) {
fis.set(i, config[i]);
}
}
//server.conf重命名
fis.set('rewriteFilename', fis.get('urlprefix') ? fis.get('namespace') + fis.get('urlprefix').replace(/\//g, '_') : fis.get('namespace'));
//autoprefixer
if (Array.isArray(config.browsers)) {
fis.match('**/*.scss', {
postprocessor: fis.plugin('autoprefixer', {
browsers: config.browsers
})
});
}
//若指定 globalVarScss ,则所有 scss 文件自动 import 这个文件,通常用来定义全局 @mixin
if (config.globalVarScss) {
if (!fis.util.isFile(fis.util(fis.project.getProjectPath(), config.globalVarScss))) {
fis.log.error('globalVarScss'.green + ' file not found: ' + config.globalVarScss);
}
}
//如果按相对路径发布
if (config.relative) {
fis.match('*.html', {
relative: true,
optimizer: null
})
.match('*.js', {
relative: true
})
.match('*.{css,scss}', {
relative: true
});
}
//enableLoader
if (config.enableLoader) {
fis.match('::package', {
// 分析 __RESOURCE_MAP__ 结构,来解决资源加载问题
postpackager: fis.plugin('loader', {
resourceType: 'commonJs',
processor: {
'.tpl': 'html',
'.html': 'html'
},
useInlineMap: true
})
});
}
//allInOne
if (config.allInOne) {
var allInOneFileBasename = typeof config.allInOne === "string" ? config.allInOne : '/static/aio';
if (!/^[\w\/]+$/.test(allInOneFileBasename)) {
fis.log.error('allInOne'.green + ' config should match pattern: /^[\\w\\/]+$/');
}
fis.match('*.js', {
packTo: allInOneFileBasename + '.js'
});
fis.match('*.{css,scss}', {
packTo: allInOneFileBasename + '.css'
});
}
//静态资源增加domain前缀
if (config.cdn) {
var cdnMatches = config.cdn.match(/^((?:https?\:)?\/\/)?.+$/);
var cdn = cdnMatches[1] ? cdnMatches[0] : '//' + cdnMatches[0];
['prod', 'sqa'].forEach(function (_mediaName_) {
fis.media(_mediaName_)
.match('*.js', {
domain: cdn,
relative: false
})
.match('*.{css,scss}', {
domain: cdn,
relative: false
})
.match('::image', {
domain: cdn,
relative: false
})
.match('*.html', {
relative: false
})
});
}
//如果指定目标编译目录,重置图片压缩策略
if (config.distPath) {
var rootProjectPath = closest.sync(fis.project.getProjectPath());
var distPath = path.join(path.dirname(rootProjectPath), config.distPath);
['prod', 'sqa'].forEach(function (_mediaName_) {
fis.media(_mediaName_)
.match('*.png', {
useHash: true,
optimizer: fis.plugin('png-compress', {
type: 'pngquant',
distPath: distPath
})
})
});
}
//设置环境变量
if (config.env && Array.isArray(config.env.keys)) {
var env = {};
for (var i = 0; i < config.env.keys.length; i++) {
if (process.env && process.env[config.env.keys[i]]) {
env[config.env.keys[i]] = process.env[config.env.keys[i]];
} else {
fis.log.error('invalid environment variable [' + config.env.keys[i].green + '] ');
}
}
fis.set('env', env);
}
}
module.exports = fis;