generator-clam
Version:
A Clam generator for Yeoman
472 lines (423 loc) • 11.5 kB
JavaScript
var path = require('path'),
fs = require('fs'),
os = require('os'),
exec = require('child_process').exec;
module.exports = function (grunt) {
var file = grunt.file;
var task = grunt.task;
var pathname = path.basename(__dirname);
var files = doWalk('./src/');
// files.js 存储项目中的所有js文件
// file.css 存储项目中的所有css文件
// file.less 存储项目中所有less文件
// ======================= 配置每个任务 ==========================
grunt.initConfig({
pkg: grunt.file.readJSON('abc.json'),
// 配置默认分支
currentBranch: 'master',
/**
* 对页面进行清理
*/
clean: {
build: {
src: 'build/*'
}
},
/**
* 将src目录中的KISSY文件做编译打包,仅做合并,源文件不需要指定名称
* KISSY.add(function(S){});
*
* @link https://github.com/daxingplay/grunt-kmc
*
* 如果需要只生成依赖关系表,不做合并,源文件必须指定名称,比如
* KISSY.add('group/project/file',function(S){});
* 并在kmc.options中增加两个参数:
* depFilePath: 'build/mods.js',
* comboOnly: true,
*/
kmc: {
options: {
packages: [
{
name: '<%= pkg.name %>',
path: '../',
charset:'utf-8'
}
],
map: [['<%= pkg.name %>/src/', '<%= pkg.name %>/']]
},
main: {
files: [
{
// 这里指定项目根目录下所有文件为入口文件,自定义入口请自行添加
expand: true,
cwd: 'src/',
src: [ '**/*.js', '!Gruntfile.js'],
dest: 'build/'
}
]
}
// 若有新任务,请自行添加
/*
simple-example: {
files: [
{
src: "a.js",
dest: "build/index.js"
}
]
}
*/
},
/**
* 将css文件中引用的本地图片上传CDN并替换url
*/
mytps: {
options: {
argv: "--inplace"
},
all: [ 'src/**/*.css']
},
/**
* CSS-Combo
* combo项目中所有css,通过@import "other.css"; 来处理依赖关系
*/
css_combo: {
options: {
paths: './'
},
main: {
files: [
{
expand: true,
cwd:'src',
src: ['**/*.css'],
dest: 'build/',
ext: '.css'
}
]
}
},
/**
* YUIDoc
* 对build目录中的js文件生成文档,放入doc/中
*/
/*
yuidoc: {
compile: {
name: 'generator-clam',
description: 'A Clam generator for Yeoman',
options: {
paths: 'build/',
outdir: 'doc/'
}
}
},
*/
/**
* 将LESS编译为CSS
* @link https://github.com/gruntjs/grunt-contrib-less
*/
less: {
options: {
paths: './'
},
main: {
files: [
{
expand: true,
cwd:'src/',
src: ['**/*.less'],
dest: 'build/',
ext: '.css'
}
]
}
},
/**
* 对JS文件进行压缩
* @link https://github.com/gruntjs/grunt-contrib-uglify
*/
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd HH:MM:ss") %> */\n',
beautify: {
ascii_only: true
}
},
main: {
files: [
{
expand: true,
cwd: 'build/',
src: ['**/*.js', '!*-min.js'],
dest: 'build/',
ext: '-min.js'
}
]
}
},
/**
* 对CSS 文件进行压缩
* @link https://github.com/gruntjs/grunt-contrib-cssmin
*/
cssmin: {
main: {
files: [
{
expand: true,
cwd: 'build/',
src: ['**/*.css', '!*-min.css'],
dest: 'build/',
ext: '-min.css'
}
]
}
},
watch: {
'js': {
files: [ 'src/**/*.js' ],
tasks: [ 'kmc', 'uglify' ]
},
'css':{
files: [ 'src/**/*.css' ],
tasks: [ 'copy','cssmin' ]
},
'less': {
files: [ 'src/**/*.less'],
tasks: ['less', 'cssmin']
}
},
/**
* 发布命令。
*/
exec: {
tag: {
command: 'git tag publish/<%= currentBranch %>'
},
publish: {
command: 'git push origin publish/<%= currentBranch %>:publish/<%= currentBranch %>'
},
commit:{
command: function(msg){
var command = 'git commit -m "' + grunt.config.get('currentBranch') + ' - ' + grunt.template.today("yyyy-mm-dd HH:MM:ss") + ' ' + msg + '"';
return command;
}
},
add: {
command: 'git add .'
},
prepub: {
command: 'git push origin daily/<%= currentBranch %>:daily/<%= currentBranch %>'
},
grunt_publish: {
command: 'grunt default:publish'
},
grunt_prepub:{
command: function(msg){
return 'grunt default:prepub:' + msg;
}
},
new_branch: {
command: 'git checkout -b daily/<%= currentBranch %>'
}
},
// 拷贝文件
copy : {
main: {
files:[
{
// src: files.js,
expand:true,
src: ['**/*.js','**/*.css'],
dest: 'build/',
cwd:'src/',
filter: 'isFile'
}
]
}
}
// 合并文件
/*
concat: {
dist: {
src: ['from.css'],
dest: 'build/to.css'
}
}
*/
});
// ======================= 载入使用到的通过NPM安装的模块 ==========================
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-css-combo');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-watch');
//grunt.loadNpmTasks('grunt-kissy-template');
grunt.loadNpmTasks('grunt-kmc');
//grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-exec');
grunt.loadNpmTasks('grunt-contrib-copy');
//grunt.loadNpmTasks('grunt-contrib-concat');
//grunt.loadNpmTasks('grunt-contrib-yuidoc');
grunt.loadNpmTasks('grunt-mytps');
// ======================= 注册Grunt 各个操作 ==========================
/**
* 正式发布
*/
grunt.registerTask('publish', 'clam publish...', function() {
task.run('exec:grunt_publish');
});
grunt.registerTask('pub', 'clam publish...', function() {
task.run('exec:grunt_publish');
});
/**
* 预发布
*/
grunt.registerTask('prepub', 'clam pre publish...', function(msg) {
task.run('exec:grunt_prepub:' + (msg || ''));
});
/**
* 监听修改
*/
grunt.registerTask('listen', 'clam watch ...', function() {
task.run('watch');
});
/*
* 获取当前库的信息
**/
grunt.registerTask('info', 'clam info...', function() {
var abcJSON = {};
try {
abcJSON = require(path.resolve(process.cwd(), 'abc.json'));
console.log('\n'+abcJSON.repository.url);
} catch (e){
console.log('未找到abc.json');
}
});
/*
* 获取当前最大版本号,并创建新分支
**/
grunt.registerTask('newbranch', 'clam newBranch...', function(type, msg) {
var done = this.async();
exec('git branch -a;git tag', function(err, stdout, stderr, cb) {
var r = getBiggestVersion(stdout.match(/\d+\.\d+\.\d+/ig));
if(!r){
r = '0.0.1';
} else {
r[2]++;
r = r.join('.');
}
grunt.log.write(('新分支:daily/' + r).green);
grunt.config.set('currentBranch', r);
task.run(['exec:new_branch']);
done();
});
});
// ======================= 注册Grunt主流程 ==========================
return grunt.registerTask('default', 'clam running ...', function(type, msg) {
var done = this.async();
// 获取当前分支
exec('git branch', function(err, stdout, stderr, cb) {
var reg = /\*\s+daily\/(\S+)/,
match = stdout.match(reg);
if (!match) {
grunt.log.error('当前分支为 master 或者名字不合法(daily/x.y.z),请切换到daily分支'.red);
grunt.log.error('创建新daily分支:grunt newbranch'.yellow);
return;
}
grunt.log.write(('当前分支:' + match[1]).green);
grunt.config.set('currentBranch', match[1]);
done();
});
// 构建和发布任务
if (!type) {
task.run(['clean:build', 'mytps','copy', 'kmc', 'uglify', 'css_combo' ,'less',, 'cssmin'/*'concat','yuidoc', 'copy', 'clean:mobile'*/]);
} else if ('publish' === type || 'pub' === type) {
task.run(['exec:tag', 'exec:publish']);
} else if ('prepub' === type) {
task.run(['exec:add','exec:commit:' + msg]);
task.run(['exec:prepub']);
}
});
// ======================= 辅助函数 ==========================
// 遍历当前目录的文件
function walk(uri, files) {
var stat = fs.lstatSync(uri);
if (stat.isFile() && !/(build|node_modules|demo|doc|\.git|\.+)[\\|\/]/i.test(uri) && !/grunt.+/i.test(uri)) {
switch (path.extname(uri)) {
case '.css':
files.css.push(uri);
break;
case '.js':
files.js.push(uri);
break;
case '.less':
files.less.push(uri);
break;
case '.scss':
files.scss.push(uri);
break;
default:
files.other.push(uri);
}
}
if (stat.isDirectory()) {
fs.readdirSync(uri).forEach(function(part) {
walk(path.join(uri, part), files);
});
}
}
// 得到文件结构的数据结构
function doWalk(rootDir) {
var files = {
css: [],
less: [],
scss: [],
js: [],
other: [] // 暂时没用
};
walk(rootDir, files);
return files;
}
function getBiggestVersion(A){
var a = [];
var b = [];
var t = [];
var r = [];
if(!A){
return [0,0,0];
}
for(var i= 0;i< A.length;i++){
if(A[i].match(/^\d+\.\d+\.\d+$/)){
var sp = A[i].split('.');
a.push([
Number(sp[0]),Number(sp[1]),Number(sp[2])
]);
}
}
var r = findMax(findMax(findMax(a,0),1),2);
return r[0];
}
// a:二维数组,index,比较第几个
// return:返回保留比较后的结果组成的二维数组
function findMax(a,index){
var t = [];
var b = [];
var r = [];
for(var i = 0;i<a.length;i++){
t.push(Number(a[i][index]));
}
var max = Math.max.apply(this,t);
for(var i = 0;i<a.length;i++){
if(a[i][index] === max){
b.push(i);
}
}
for(var i = 0;i<b.length;i++){
r.push(a[b[i]]);
}
return r;
}
};