最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Multiple Build Folders (multiple clients, mulitask, multiple targets) using Grunt (Yeoman) - Stack Overflow

programmeradmin2浏览0评论

I am building a project right now that will be a webapp (browser runnable) and a Phonegap app (iOS & Android). Although my project, theoretically, could use the same dist folder that my Yeoman generated, Grunt tasks build production ready code by running grunt build. I would like to run something like grunt build_web, grunt build_ios, and grunt build_android, to build out production code for each platform individually. Or grunt build:web, grunt build:ios, grunt build:android. This way, I could customize some of the loaded scripts, images, etc each with their own build directives.

So, should I go through my Gruntfile copying and pasting all of by dist and build directives responsibly? Or, is there a best practice for this? (tried this, didn't work)

Yeoman folks, is this possible?

Here is my current Gruntfile.js in case it would be useful to see.

'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']
            },
            pass: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['pass: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'
                }]
            }
        },
        pass: {
            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_ponents',
                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: .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
                    // 
                    //generateSourceMaps: true,
                    // required to support SourceMaps
                    // .html#sourcemapments
                    preserveLicenseComments: false,
                    useStrict: true,
                    wrap: true
                    //uglify2: {} // 
                }
            }
        },
        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,
                    // 
                    //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_ponents/modernizr/modernizr.js',
            outputFile: '<%= yeoman.dist %>/bower_ponents/modernizr/modernizr.js',
            files: [
                '<%= yeoman.dist %>/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/styles/{,*/}*.css',
                '!<%= yeoman.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },
        concurrent: {
            server: [
                'pass',
                'coffee:dist',
                'copy:styles'
            ],
            test: [
                'coffee',
                'copy:styles'
            ],
            dist: [
                'coffee',
                'pass',
                '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'
    ]);
};

I am building a project right now that will be a webapp (browser runnable) and a Phonegap app (iOS & Android). Although my project, theoretically, could use the same dist folder that my Yeoman generated, Grunt tasks build production ready code by running grunt build. I would like to run something like grunt build_web, grunt build_ios, and grunt build_android, to build out production code for each platform individually. Or grunt build:web, grunt build:ios, grunt build:android. This way, I could customize some of the loaded scripts, images, etc each with their own build directives.

So, should I go through my Gruntfile copying and pasting all of by dist and build directives responsibly? Or, is there a best practice for this? (tried this, didn't work)

Yeoman folks, is this possible?

Here is my current Gruntfile.js in case it would be useful to see.

'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']
            },
            pass: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['pass: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'
                }]
            }
        },
        pass: {
            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_ponents',
                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./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./yeoman/grunt-usemin/issues/30
                    //generateSourceMaps: true,
                    // required to support SourceMaps
                    // http://requirejs/docs/errors.html#sourcemapments
                    preserveLicenseComments: false,
                    useStrict: true,
                    wrap: true
                    //uglify2: {} // https://github./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./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_ponents/modernizr/modernizr.js',
            outputFile: '<%= yeoman.dist %>/bower_ponents/modernizr/modernizr.js',
            files: [
                '<%= yeoman.dist %>/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/styles/{,*/}*.css',
                '!<%= yeoman.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },
        concurrent: {
            server: [
                'pass',
                'coffee:dist',
                'copy:styles'
            ],
            test: [
                'coffee',
                'copy:styles'
            ],
            dist: [
                'coffee',
                'pass',
                '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'
    ]);
};
Share Improve this question edited Aug 27, 2013 at 3:17 Jarrod asked Aug 26, 2013 at 17:25 JarrodJarrod 3963 silver badges19 bronze badges 1
  • Thx for posting your file. I didn't get the modernizr-devFile option. Now it works! :P – escapedcat Commented Sep 12, 2013 at 3:01
Add a ment  | 

2 Answers 2

Reset to default 3

There's really no best practice out there beside what's remended for PG 3. For multiple clients, you may want to modify your gruntjs. This is my project structure, where assets folder contain data for different clients:

And here is my gruntjs file. It use ImageMagik to create all the necessary launcher icons. Build and deploy for over the air installation. You get the idea...

/***
 * 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/[email protected]'
                        }]
                };
                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/[email protected]'
                        }]
                };
                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/[email protected]'
                        }]
                };
                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/[email protected]'
                        }]
                };
                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.yourpany.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 mandStart = '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 mand = 'chmod 777 dobuild && ./dobuild "' + chainConfig.AppleProductName + '" ' + chain + ' ' + process.env.BUILD_NUMBER + ' "' + chainConfig.AppleBundleSeedID + '.' + chainConfig.id + '"';
        grunt.log.debug('ios build:' + mand);

        if (isMacOS) {
            gruntConfig.exec[key] = {
                cmd: mand,
                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');
};

Basically, it drop all the native and merges into out/clientorchainid folder to do the build for each client. Then it copy the build result into beta-assets/clientorchainid folder to prep for remote deployment.

Build is a list of other tasks. You could do something like this (coffescript):

grunt.registerTask "build", [
    "clean:dist",
    "jade:html",
    "clientTemplates",
    "useminPrepare",
    "concurrent:dist",
    "copy:prerequire",
    "requirejs",
    "cssmin",
    "concat",
    "uglify",
    "copy:dist",
    "rev",
    "usemin"
]

That way you can deifne custom tasks and custom builds, etc.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论