Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用Grunt(Yeoman)的多个构建文件夹(多个客户端、多个任务、多个目标)_Javascript_Node.js_Cordova_Gruntjs_Yeoman - Fatal编程技术网

Javascript 使用Grunt(Yeoman)的多个构建文件夹(多个客户端、多个任务、多个目标)

Javascript 使用Grunt(Yeoman)的多个构建文件夹(多个客户端、多个任务、多个目标),javascript,node.js,cordova,gruntjs,yeoman,Javascript,Node.js,Cordova,Gruntjs,Yeoman,我现在正在构建一个项目,它将是一个webapp(浏览器可运行)和一个Phonegap应用(iOS和Android)。虽然从理论上讲,我的项目可以使用我的生成的dist文件夹,但通过运行grunt build任务build生产就绪代码。我想运行类似于grunt build\u web,grunt build\u ios,以及grunt build\u android,分别为每个平台构建生产代码。或者grunt-build:web,grunt-build:ios,grunt-build:androi

我现在正在构建一个项目,它将是一个webapp(浏览器可运行)和一个Phonegap应用(iOS和Android)。虽然从理论上讲,我的项目可以使用我的生成的
dist
文件夹,但通过运行
grunt build
任务
build
生产就绪代码。我想运行类似于
grunt build\u web
grunt build\u ios
,以及
grunt build\u android
,分别为每个平台构建生产代码。或者
grunt-build:web
grunt-build:ios
grunt-build:android
。通过这种方式,我可以自定义一些加载的脚本、图像等,每个脚本、图像等都有自己的构建指令

那么,我是否应该负责地通过
dist
build
指令复制和粘贴所有Grunfile文件?或者,有没有最佳实践?(试过这个,没用)

约曼人,这可能吗

这是我当前的Gruntfile.js,以防看到

'use strict';
var LIVERELOAD_PORT = 35729;
var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT});
var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {
    // show elapsed time at the end
    require('time-grunt')(grunt);
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);

    // configurable paths
    var yeomanConfig = {
        app: 'app',
        dist: '../www'
    };

    grunt.initConfig({
        yeoman: yeomanConfig,
        watch: {
            coffee: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
                tasks: ['coffee:dist']
            },
            coffeeTest: {
                files: ['test/spec/{,*/}*.coffee'],
                tasks: ['coffee:test']
            },
            compass: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['compass:server', 'autoprefixer']
            },
            styles: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
                tasks: ['copy:styles', 'autoprefixer']
            },
            livereload: {
                options: {
                    livereload: LIVERELOAD_PORT
                },
                files: [
                    '<%= yeoman.app %>/*.html',
                    '.tmp/styles/{,*/}*.css',
                    '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
                    '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
                ]
            }
        },
        connect: {
            options: {
                port: 9000,
                // change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, yeomanConfig.app)
                        ];
                    }
                }
            },
            test: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, 'test'),
                            mountFolder(connect, yeomanConfig.app)
                        ];
                    }
                }
            },
            dist: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, yeomanConfig.dist)
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                path: 'http://localhost:<%= connect.options.port %>'
            }
        },
        clean: {
            options: {
                force: true
            },
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%= yeoman.dist %>/*',
                        '!<%= yeoman.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                '<%= yeoman.app %>/scripts/{,*/}*.js',
                '!<%= yeoman.app %>/scripts/vendor/*',
                'test/spec/{,*/}*.js'
            ]
        },
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://localhost:<%= connect.options.port %>/index.html']
                }
            }
        },
        coffee: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/scripts',
                    src: '{,*/}*.coffee',
                    dest: '.tmp/scripts',
                    ext: '.js'
                }]
            },
            test: {
                files: [{
                    expand: true,
                    cwd: 'test/spec',
                    src: '{,*/}*.coffee',
                    dest: '.tmp/spec',
                    ext: '.js'
                }]
            }
        },
        compass: {
            options: {
                sassDir: '<%= yeoman.app %>/styles',
                cssDir: '.tmp/styles',
                generatedImagesDir: '.tmp/images/generated',
                imagesDir: '<%= yeoman.app %>/images',
                javascriptsDir: '<%= yeoman.app %>/scripts',
                fontsDir: '<%= yeoman.app %>/styles/fonts',
                importPath: '<%= yeoman.app %>/bower_components',
                httpImagesPath: '/images',
                httpGeneratedImagesPath: '/images/generated',
                httpFontsPath: '/styles/fonts',
                relativeAssets: false
            },
            dist: {
                options: {
                    generatedImagesDir: '<%= yeoman.dist %>/images/generated'
                }
            },
            server: {
                options: {
                    debugInfo: true
                }
            }
        },
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/styles/',
                    src: '{,*/}*.css',
                    dest: '.tmp/styles/'
                }]
            }
        },
        // not used since Uglify task does concat,
        // but still available if needed
        /*concat: {
            dist: {}
        },*/
        requirejs: {
            dist: {
                // Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
                options: {
                    // `name` and `out` is set by grunt-usemin
                    baseUrl: yeomanConfig.app + '/scripts',
                    optimize: 'none',
                    // TODO: Figure out how to make sourcemaps work with grunt-usemin
                    // https://github.com/yeoman/grunt-usemin/issues/30
                    //generateSourceMaps: true,
                    // required to support SourceMaps
                    // http://requirejs.org/docs/errors.html#sourcemapcomments
                    preserveLicenseComments: false,
                    useStrict: true,
                    wrap: true
                    //uglify2: {} // https://github.com/mishoo/UglifyJS2
                }
            }
        },
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/{,*/}*.js',
                        '<%= yeoman.dist %>/styles/{,*/}*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}',
                        '<%= yeoman.dist %>/styles/fonts/{,*/}*.*'
                    ]
                }
            }
        },
        useminPrepare: {
            options: {
                dest: '<%= yeoman.dist %>'
            },
            html: '<%= yeoman.app %>/index.html'
        },
        usemin: {
            options: {
                dirs: ['<%= yeoman.dist %>']
            },
            html: ['<%= yeoman.dist %>/{,*/}*.html'],
            css: ['<%= yeoman.dist %>/styles/{,*/}*.css']
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/images',
                    src: '{,*/}*.{png,jpg,jpeg}',
                    dest: '<%= yeoman.dist %>/images'
                }]
            }
        },
        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/images',
                    src: '{,*/}*.svg',
                    dest: '<%= yeoman.dist %>/images'
                }]
            }
        },
        cssmin: {
            // This task is pre-configured if you do not wish to use Usemin
            // blocks for your CSS. By default, the Usemin block from your
            // `index.html` will take care of minification, e.g.
            //
            //     <!-- build:css({.tmp,app}) styles/main.css -->
            //
            // dist: {
            //     files: {
            //         '<%= yeoman.dist %>/styles/main.css': [
            //             '.tmp/styles/{,*/}*.css',
            //             '<%= yeoman.app %>/styles/{,*/}*.css'
            //         ]
            //     }
            // }
        },
        htmlmin: {
            dist: {
                options: {
                    /*removeCommentsFromCDATA: true,
                    // https://github.com/yeoman/grunt-usemin/issues/44
                    //collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeAttributeQuotes: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true*/
                },
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>',
                    src: '*.html',
                    dest: '<%= yeoman.dist %>'
                }]
            }
        },
        // Put files not handled in other tasks here
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= yeoman.app %>',
                    dest: '<%= yeoman.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.{webp,gif}',
                        'styles/fonts/{,*/}*.*'
                    ]
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },
        modernizr: {
            devFile: '<%= yeoman.app %>/bower_components/modernizr/modernizr.js',
            outputFile: '<%= yeoman.dist %>/bower_components/modernizr/modernizr.js',
            files: [
                '<%= yeoman.dist %>/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/styles/{,*/}*.css',
                '!<%= yeoman.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },
        concurrent: {
            server: [
                'compass',
                'coffee:dist',
                'copy:styles'
            ],
            test: [
                'coffee',
                'copy:styles'
            ],
            dist: [
                'coffee',
                'compass',
                'copy:styles',
                'imagemin',
                'svgmin',
                'htmlmin'
            ]
        },
        bower: {
            options: {
                exclude: ['modernizr']
            },
            all: {
                rjsConfig: '<%= yeoman.app %>/scripts/main.js'
            }
        }
    });

    grunt.registerTask('server', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'open', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload',
            'open',
            'watch'
        ]);
    });

    grunt.registerTask('test', [
        'clean:server',
        'concurrent:test',
        'autoprefixer',
        'connect:test',
        'mocha'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'requirejs',
        'concat',
        'cssmin',
        'uglify',
        'modernizr',
        'copy:dist',
        'rev',
        'usemin'
    ]);

    grunt.registerTask('default', [
        'jshint',
        'test',
        'build'
    ]);
};
“严格使用”;
var LIVERELOAD_PORT=35729;
var lrnippet=require('connect-livereload')({port:livereload_port});
var mountFolder=函数(连接,目录){
返回connect.static(require('path').resolve(dir));
};
//#全球化
//出于性能原因,我们只降低了一个级别:
//'test/spec/{,*/}*.js'
//如果要递归匹配所有子文件夹,请使用此选项:
//“test/spec/***.js”
module.exports=函数(grunt){
//在末尾显示经过的时间
要求(“时间咕噜”)(咕噜);
//加载所有grunt任务
要求('load-grunt-tasks')(grunt);
//可配置路径
var yeomanConfig={
应用程序:“应用程序”,
地区:“../www”
};
grunt.initConfig({
约曼:约曼图,
观察:{
咖啡:{
文件:['/scripts/{,*/}*.coffee'],
任务:['coffee:dist']
},
咖啡测试:{
文件:['test/spec/{,*/}*.coffee'],
任务:[“咖啡:测试”]
},
指南针:{
文件:['/styles/{,*/}*{scss,sass}'],
任务:['compass:server','autoprefixer']
},
风格:{
文件:['/styles/{,*/}*.css'],
任务:['copy:styles','autoprefixer']
},
利弗雷罗德:{
选项:{
利弗雷洛德:利弗雷洛德港口
},
档案:[
“/*.html”,
“.tmp/styles/{,*/}*.css”,
“{.tmp,}/scripts/{,*/}*.js”,
“/images/{,*/}*{png,jpg,jpeg,gif,webp,svg}”
]
}
},
连接:{
选项:{
港口:9000,
//将此更改为“0.0.0.0”以从外部访问服务器
主机名:“localhost”
},
利弗雷罗德:{
选项:{
中间件:功能(连接){
返回[
小片段,
mountFolder(连接“.tmp”),
mountFolder(连接,yeomanConfig.app)
];
}
}
},
测试:{
选项:{
中间件:功能(连接){
返回[
mountFolder(连接“.tmp”),
安装文件夹(连接“测试”),
mountFolder(连接,yeomanConfig.app)
];
}
}
},
地区:{
选项:{
中间件:功能(连接){
返回[
mountFolder(连接,yeomanConfig.dist)
];
}
}
}
},
开放式:{
服务器:{
路径:'http://localhost:'
}
},
清洁:{
选项:{
原力:对
},
地区:{
档案:[{
多特:没错,
src:[
“.tmp”,
'/*',
“!/.git*”
]
}]
},
服务器:'.tmp'
},
jshint:{
选项:{
jshintrc:“.jshintrc”
},
全部:[
“Gruntfile.js”,
“/scripts/{,*/}*.js”,
“!/scripts/vendor/*”,
'test/spec/{,*/}*.js'
]
},
摩卡咖啡:{
全部:{
选项:{
run:是的,
网址:['http://localhost:/index.html']
}
}
},
咖啡:{
地区:{
档案:[{
是的,
cwd:“/scripts”,
src:“{,*/}*.coffee”,
目标:'.tmp/scripts',
分机:'.js'
}]
},
测试:{
档案:[{
是的,
cwd:“测试/规范”,
src:“{,*/}*.coffee”,
目的地:'.tmp/spec',
分机:'.js'
}]
}
},
指南针:{
选项:{
sassDir:“/styles”,
cssDir:“.tmp/styles”,
generatedImagesDir:'.tmp/images/generated',
imagesDir:“/images”,
javascriptsDir:“/scripts”,
fontsDir:“/styles/fonts”,
导入路径:'/bower_components',
/***
 * Package script for MobileStore
 ***/

'use strict';

// require package.json:
/*
{
  "name": "MobileStore",
  "version": "1.0.1",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.0",
    "grunt-contrib-clean": "~0.4.1",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-exec": "~0.4.2",
    "grunt-string-replace": "~0.2.4",
    "grunt-image-resize": "~0.2.0"
  }
}
*/
module.exports = function(grunt) {
    var isMacOS = grunt.file.isDir('/etc');

    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var myConfig = {
        dest: 'out/',
        platforms: ['ios', 'android'], 
        chains: [11,52,75,119,129,224,229,235],
        chainConfig: {},
        baseDir: __dirname + '/'
    };
    var chainid = grunt.option('chainid');
    if (chainid) {
        myConfig.chains = [chainid];
    }

    // set up grunt
    var gruntConfig = {
        clean: {
          build: ['out', 'beta-assets']
        },
        copy: {},
        exec: {},
        "string-replace": {},
        image_resize: {}
    };

    // first thing to do is clean
    var packageConfig = ['clean'];

    // duplicate source to the chain
    // copy from platforms/(android/ios) to out/chainid/(android/ios)
    myConfig.chains.forEach(function(chain) {
        myConfig.platforms.forEach(function(platform) {
            var key = 'setup_' + platform + chain;

            // any platform is fine, we're just preping chainConfig
            if (platform == 'android')
            {
                myConfig.chainConfig[chain] = require('./YourCompany.Mobile/assets/' + chain + '/build.json');
            }

            gruntConfig.copy[key] = {
                files: [
                  {
                    expand: true,
                    cwd: 'YourCompany.Mobile/platforms/' + platform + '/', 
                    src: ['./**'], 
                    dest: 'out/' + chain + '/' + platform + '/'
                  }
                ]
            };

            packageConfig.push('copy:' + key);
        });
    });

    // override the device resource (icon, splash, etc..)
    // copy from assets/chainid/device/(android/ios) to out/chainid/(android/ios)
    myConfig.chains.forEach(function(chain) {
        myConfig.platforms.forEach(function(platform) {
            var key = 'device_resource_' + platform + chain;
            var srcArt = 'YourCompany.Mobile/assets/' + chain + '/device/AndroidArtwork.png';

            var dest = 'out/' + chain + '/' + platform + '/MobileStore/';
            if (platform == 'android') 
            {
                dest += 'res/';
            }
            else if (platform == 'ios') {
                dest += 'MobileStore/';
            }

            gruntConfig.copy[key] = {
                files: [
                  {
                    expand: true,
                    cwd: 'YourCompany.Mobile/assets/' + chain + '/device/' + platform + '/', 
                    src: ['./**'], 
                    dest: dest
                  }
                ]
            };

            packageConfig.push('copy:' + key);

            // do image manipulations
            // Use AnroidArtwork.png
            if (platform == 'android') {
                gruntConfig.image_resize[key + '_36'] = {
                        options: {
                            width: 36,     
                            height: 36,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'drawable-ldpi/icon.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_36');

                gruntConfig.image_resize[key + '_48'] = {
                        options: {
                            width: 48, 
                            height: 48,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'drawable-mdpi/icon.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_48');

                gruntConfig.image_resize[key + '_72'] = {
                        options: {
                            width: 72, 
                            height: 72,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'drawable-hdpi/icon.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_72');

                gruntConfig.image_resize[key + '_96'] = {
                        options: {
                            width: 96,  
                            height: 96,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'drawable-xhdpi/icon.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_96');

                gruntConfig.image_resize[key + '_default'] = {
                        options: {
                            width: 96,  
                            height: 96,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'drawable/icon.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_default');
            }
            else if (platform == 'ios') {
                gruntConfig.image_resize[key + '_57'] = {
                        options: {
                            width: 57,  
                            height: 57,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'Resources/icons/Icon.png'
                        }]
                };

                packageConfig.push('image_resize:' + key + '_57');

                gruntConfig.image_resize[key + '_114'] = {
                        options: {
                            width: 114,  
                            height: 114,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'Resources/icons/Icon@2x.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_114');

                gruntConfig.image_resize[key + '_72'] = {
                        options: {
                            width: 72, 
                            height: 72,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'Resources/icons/Icon-72.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_72');

                gruntConfig.image_resize[key + '_144'] = {
                        options: {
                            width: 144,  
                            height: 144,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'Resources/icons/Icon-72@2x.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_144');

                gruntConfig.image_resize[key + '_29'] = {
                        options: {
                            width: 29,  
                            height: 29,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest + 'Resources/icons/Icon-Small.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_29');

                gruntConfig.image_resize[key + '_58'] = {
                        options: {
                            width: 58, 
                            height: 58,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'Resources/icons/Icon-Small@2x.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_58');

                gruntConfig.image_resize[key + '_50'] = {
                        options: {
                            width: 50,  
                            height: 50,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'Resources/icons/Icon-Small-50.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_50');

                gruntConfig.image_resize[key + '_100'] = {
                        options: {
                            width: 100,   
                            height: 100,
                            overwrite: true
                        },
                        files: [{
                            src: srcArt,
                            dest: dest  + 'Resources/icons/Icon-Small-50@2x.png'
                        }]
                };
                packageConfig.push('image_resize:' + key + '_100');

                gruntConfig.image_resize[key + '_1024'] = {
                    options: {
                        width: 1024,
                        height: 1024,
                        overwrite: true,
                        upscale: true
                    },
                    files: [{
                        src: srcArt,
                        dest: dest + 'Resources/iTunesArtwork'
                    }]
                };
                packageConfig.push('image_resize:' + key + '_1024');

                // setup images for ota deploy
                gruntConfig.image_resize[key + '_512x'] = {
                    options: {
                        width: 512,
                        height: 512,
                        overwrite: true,
                        upscale: true
                    },
                    files: [{
                        src: srcArt,
                        dest: dest + '../iTunesArtwork.png'
                    }]
                };
                packageConfig.push('image_resize:' + key + '_512x');

                gruntConfig.image_resize[key + '_57x'] = {
                    options: {
                        width: 57,
                        height: 57,
                        overwrite: true
                    },
                    files: [{
                        src: srcArt,
                        dest: dest + '../Icon.png'
                    }]
                };
                packageConfig.push('image_resize:' + key + '_57x');
            }
        });
    });

    // copy assets to www folder
    // copy from www to out/chainid/...
    myConfig.chains.forEach(function(chain) {
        myConfig.platforms.forEach(function(platform) {
            var key = 'content_' + platform + chain;
            var dest = 'out/' + chain + '/' + platform + '/MobileStore/';
            if (platform == 'android') 
            {
                dest += 'assets/www/';
            }
            else if (platform == 'ios') {
                dest += 'www/';
            }

            gruntConfig.copy[key] = {
                files: [
                  {
                    expand: true,
                    cwd: 'YourCompany.Mobile/www/', 
                    src: ['./**'], 
                    dest: dest
                  }
                ]
            };

            packageConfig.push('copy:' + key);
        });
    });

    // copy assets override
    // copy from assets/chainid/www to out/chainid/...
    myConfig.chains.forEach(function(chain) {
        myConfig.platforms.forEach(function(platform) {
            var key = 'content_override_' + platform + chain;
            var dest = 'out/' + chain + '/' + platform + '/MobileStore/';
            if (platform == 'android') 
            {
                dest += 'assets/www/';
            }
            else if (platform == 'ios') {
                dest += 'www/';
            }

            gruntConfig.copy[key] = {
                files: [
                  {
                    expand: true,
                    cwd: 'YourCompany.Mobile/assets/' + chain + '/www/', 
                    src: ['./**'], 
                    dest: dest
                  }
                ]
            };

            packageConfig.push('copy:' + key);
        });
    });

    // copy phonegap merges
    // copy from merges to out/chainid/...
    myConfig.chains.forEach(function(chain) {
        myConfig.platforms.forEach(function(platform) {
            var key = 'phonegap_override_' + platform + chain;
            var dest = 'out/' + chain + '/' + platform + '/MobileStore/';
            if (platform == 'android') 
            {
                dest += 'assets/www/';
            }
            else if (platform == 'ios') {
                dest += 'www/';
            }

            gruntConfig.copy[key] = {
                files: [
                  {
                    expand: true,
                    cwd: 'YourCompany.Mobile/merges/' + platform, 
                    src: ['./**'], 
                    dest: dest
                  }
                ]
            };

            packageConfig.push('copy:' + key);
        });
    });

    // doing beta assets deployment
    myConfig.chains.forEach(function (chain) {
        var key = 'content_beta_assets_' + chain;
        var src = 'out/' + chain + '/ios/MobileStore/www/';

        gruntConfig.copy[key] = {
            files: [
              {
                  expand: true,
                  cwd: src,
                  src: ['./**'],
                  dest: 'beta-assets/' + chain + '/www/'
              }
            ]
        };

        packageConfig.push('copy:' + key);

        // override cordova file
        gruntConfig.copy[key + '_pg'] = {
            files: [
              {
                  expand: true,
                  cwd: 'YourCompany.Mobile/www/',
                  src: ['./cordova.js'],
                  dest: 'beta-assets/' + chain + '/www/'
              }
            ]
        };

        packageConfig.push('copy:' + key + '_pg');

    });

    // doing android(ant) build
    myConfig.chains.forEach(function (chain) {
        var key = 'android_build_' + chain;

        var dest = 'out/' + chain + '/android/MobileStore/';
        var destFolder = './out/' + chain + '/';
        // use previous chainConfig to perform text replace
        gruntConfig["string-replace"][key + '_prep'] = {
            files: [
                  {
                    expand: true,
                    cwd: 'out/' + chain + '/', 
                    src: ['./**/**.java', './**/**.xml', './**/**.plist', './**/**.m'],
                    dest: 'out/' + chain + '/'
                  }
            ],
            options: {
              replacements: [
                {
                    pattern: /(net.yourcompany.MobileStore)+/ig,
                    replacement: myConfig.chainConfig[chain].id
                },
                {
                    pattern: /(AppleBundleSeedID)+/ig,
                    replacement: myConfig.chainConfig[chain].AppleBundleSeedID
                },
                {   pattern: '<string name="app_name">MobileStore</string>',
                    replacement: '<string name="app_name">' + myConfig.chainConfig[chain].ApplicationName + '</string>'
                }
              ]
            }
        };

        packageConfig.push('string-replace:' + key + '_prep');

        // do build
        gruntConfig.exec[key] = {
            cmd: 'ant clean && ant debug',
            cwd: dest,
            env: process.env
        };

        packageConfig.push('exec:' + key);

    });

    // doing xcode build
    myConfig.chains.forEach(function(chain) {
        var key = 'ios_build_' + chain;
        var chainConfig = myConfig.chainConfig[chain];
        var dest = myConfig.baseDir + 'out/' + chain + '/ios/MobileStore/';
        var buildDir = dest + 'Build/Products/Release-iphoneos/';
        var commandStart = 'export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/opt/local/bin:/opt/local/sbin:/sbin:/usr/local/bin:/Users/Shared/ImageMagick-6.8.6:$PATH" &&'
        var command = 'chmod 777 dobuild && ./dobuild "' + chainConfig.AppleProductName + '" ' + chain + ' ' + process.env.BUILD_NUMBER + ' "' + chainConfig.AppleBundleSeedID + '.' + chainConfig.id + '"';
        grunt.log.debug('ios build:' + command);

        if (isMacOS) {
            gruntConfig.exec[key] = {
                cmd: command,
                cwd: dest,
                exitCode: 0
            };
            packageConfig.push('exec:' + key);
        }

        // prep apk for deployment
        gruntConfig.copy['android_build_' + chain + '_apk'] = {
            options: {
                processContent: false
            },
            files: [
                {
                    expand: true,
                    flatten: true,
                    src: ['out/' + chain + '/android/MobileStore/bin/MobileStore-debug.apk'],
                    dest: 'beta-assets/' + chain + '/',
                    filter: 'isFile'
                }
            ]
        };

        packageConfig.push('copy:' + 'android_build_' + chain + '_apk');

        // prep ipa for ios deploy
        gruntConfig.copy['ios_build_' + chain + '_ipa'] = {
            options: {
                processContent: false
            },
            files: [
                {
                    expand: true,
                    flatten: true,
                    src: ['out/' + chain + '/ios/MobileStore/Build/**.ipa'],
                    dest: 'beta-assets/' + chain + '/',
                    filter: 'isFile'
                }
            ]
        };

        packageConfig.push('copy:' + 'ios_build_' + chain + '_ipa');

        // drop plist
        gruntConfig.copy['ios_build_' + chain + '_plist'] = {
            options: {
                processContent: false
            },
            files: [
                {
                    expand: true,
                    flatten: true,
                    src: ['out/' + chain + '/ios/MobileStore/Build/**.plist'],
                    dest: 'beta-assets/' + chain + '/',
                    filter: 'isFile'
                }
            ]
        };

        packageConfig.push('copy:' + 'ios_build_' + chain + '_plist');

        // drop html
        gruntConfig.copy['ios_build_' + chain + '_html'] = {
            options: {
                processContent: false
            },
            files: [
                {
                    expand: true,
                    flatten: true,
                    src: ['out/' + chain + '/ios/MobileStore/Build/install.html'],
                    dest: 'beta-assets/' + chain + '/',
                    filter: 'isFile'
                }
            ]
        };

        packageConfig.push('copy:' + 'ios_build_' + chain + '_html');

        // drop png
        gruntConfig.copy['ios_build_' + chain + '_png'] = {
            options: {
                processContent: false
            },
            files: [
                {
                    expand: true,
                    flatten: true,
                    src: ['out/' + chain + '/ios/MobileStore/*.png'],
                    dest: 'beta-assets/' + chain + '/',
                    filter: 'isFile'
                }
            ]
        };

        packageConfig.push('copy:' + 'ios_build_' + chain + '_png');
    });


    grunt.initConfig(gruntConfig);
    grunt.registerTask('package', packageConfig);

    // Default task.
    grunt.registerTask('default', 'package');
};
grunt.registerTask "build", [
    "clean:dist",
    "jade:html",
    "clientTemplates",
    "useminPrepare",
    "concurrent:dist",
    "copy:prerequire",
    "requirejs",
    "cssmin",
    "concat",
    "uglify",
    "copy:dist",
    "rev",
    "usemin"
]