diff --git a/README.md b/README.md index 9853a05..308ca0c 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,6 @@ useminPrepare: { } } ``` - * to customize the generated configuration via post-processors: ```js @@ -253,6 +252,38 @@ useminPrepare: { } ``` +* to have multiple profiles with custom options: + +```js +useminPrepare: { + dist: { + src: 'index.html', + options: { + dest: 'dist', + flow: { + steps: { + js: ['concat', 'uglify'], + css: ['cssmin'] + }, + post: {} + } + } + }, + dev: { + src: 'index.html', + options: { + dest: 'app', + flow: { + steps: { + js: ['concat'], + }, + post: {} + } + } + } +} +``` + The given steps or post-processors may be specified as strings (for the default steps and post-processors), or as an object (for the user-defined ones). #### User-defined steps and post-processors diff --git a/tasks/usemin.js b/tasks/usemin.js index 4914b2d..b790c59 100644 --- a/tasks/usemin.js +++ b/tasks/usemin.js @@ -6,7 +6,7 @@ var chalk = require('chalk'); // - a dedicated one for the furnished target // - a general one // - the default one -var getFlowFromConfig = function (config, target) { +var getFlowFromOptions = function (options, target) { var Flow = require('../lib/flow'); var flow = new Flow({ steps: { @@ -15,13 +15,13 @@ var getFlowFromConfig = function (config, target) { }, post: {} }); - if (config.options && config.options.flow) { - if (config.options.flow[target]) { - flow.setSteps(config.options.flow[target].steps); - flow.setPost(config.options.flow[target].post); + if (options && options.flow) { + if (options.flow[target]) { + flow.setSteps(options.flow[target].steps); + flow.setPost(options.flow[target].post); } else { - flow.setSteps(config.options.flow.steps); - flow.setPost(config.options.flow.post); + flow.setSteps(options.flow.steps); + flow.setPost(options.flow.post); } } return flow; @@ -164,7 +164,7 @@ module.exports = function (grunt) { .writeln('Going through ' + grunt.verbose.wordlist(this.filesSrc) + ' to update the config') .writeln('Looking for build script HTML comment blocks'); - var flow = getFlowFromConfig(grunt.config('useminPrepare'), this.target); + var flow = getFlowFromOptions(options, this.target); var c = new ConfigWriter(flow, { root: root, diff --git a/test/test-usemin.js b/test/test-usemin.js index cf6afe6..975963e 100644 --- a/test/test-usemin.js +++ b/test/test-usemin.js @@ -382,6 +382,35 @@ describe('useminPrepare', function () { assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/plugins.js')]); }); + it('should update the config (HTML) for mutilple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html' + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var concat = grunt.config('concat'); + + assert.ok(concat); + assert.ok(concat.generated.files); + assert.equal(concat.generated.files.length, 2); + + assert.equal(concat.generated.files[1].dest, path.normalize('.tmp/concat/scripts/plugins.js')); + assert.equal(concat.generated.files[1].src.length, 13); + assert.equal(concat.generated.files[0].dest, path.normalize('.tmp/concat/styles/main.min.css')); + assert.equal(concat.generated.files[0].src.length, 1); + + var uglify = grunt.config('uglify'); + + assert.equal(uglify.generated.files[0].dest, path.normalize('dist/scripts/plugins.js')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/plugins.js')]); + }); + it('should use alternate search dir if asked to', function () { grunt.log.muted = true; grunt.config.init(); @@ -402,6 +431,27 @@ describe('useminPrepare', function () { assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/foo.js')]); }); + it('should use alternate search dir if asked to for multiple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html' + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/alternate_search_path.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var concat = grunt.config('concat'); + assert.ok(concat); + assert.equal(concat.generated.files[0].dest, path.normalize('.tmp/concat/scripts/foo.js')); + assert.deepEqual(concat.generated.files[0].src, [path.normalize('build/scripts/bar.js'), path.normalize('build/scripts/baz.js')]); + + var uglify = grunt.config('uglify'); + assert.equal(uglify.generated.files[0].dest, path.normalize('dist/scripts/foo.js')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/foo.js')]); + }); it('output config for subsequent tasks should be relative to observed file', function () { grunt.log.muted = true; @@ -424,6 +474,29 @@ describe('useminPrepare', function () { assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/foo.js')]); }); + it('output config for subsequent tasks should be relative to observed file for multiple flows for multiple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'build/index.html' + } + }); + grunt.file.mkdir('build'); + grunt.file.copy(path.join(__dirname, 'fixtures/relative_path.html'), 'build/index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var concat = grunt.config('concat'); + assert.ok(concat); + assert.equal(concat.generated.files[0].dest, path.normalize('.tmp/concat/scripts/foo.js')); + assert.equal(concat.generated.files[0].src.length, 2); + + var uglify = grunt.config('uglify'); + assert.equal(uglify.generated.files[0].dest, path.normalize('dist/scripts/foo.js')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/foo.js')]); + }); + describe('absolute path', function () { // This is an interesting test case: root file is foo, html file is in foo/build and js // sources in foo/scripts @@ -477,6 +550,27 @@ describe('useminPrepare', function () { assert.equal(uglify.generated.files[0].dest, path.normalize('foo/scripts/plugins.js')); assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/plugins.js')]); + }); + + it('should take dest option into consideration for multiple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + dest: 'foo' + } + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var uglify = grunt.config('uglify'); + assert.equal(uglify.generated.files[0].dest, path.normalize('foo/scripts/plugins.js')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('.tmp/concat/scripts/plugins.js')]); + }); it('should take staging option into consideration', function () { grunt.log.muted = true; @@ -498,6 +592,28 @@ describe('useminPrepare', function () { }); + it('should take staging option into consideration for multiple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + staging: 'foo' + } + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var concat = grunt.config('concat'); + var uglify = grunt.config('uglify'); + assert.equal(concat.generated.files[0].dest, path.normalize('foo/concat/styles/main.min.css')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('foo/concat/scripts/plugins.js')]); + + }); + it('should take staging option into consideration', function () { grunt.log.muted = true; grunt.config.init(); @@ -517,6 +633,27 @@ describe('useminPrepare', function () { }); + it('should take staging option into consideration for multiple flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + staging: 'foo' + } + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var uglify = grunt.config('uglify'); + assert.equal(uglify.generated.files[0].dest, path.normalize('dist/scripts/plugins.js')); + assert.deepEqual(uglify.generated.files[0].src, [path.normalize('foo/concat/scripts/plugins.js')]); + + }); + it('should have configurable flow', function () { grunt.log.muted = true; grunt.config.init(); @@ -548,6 +685,38 @@ describe('useminPrepare', function () { }); + it('should have multiple configurable flows', function () { + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + flow: { + steps: { + js: ['uglifyjs'] + }, + post: {} + } + } + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var uglify = grunt.config('uglify'); + var concat = grunt.config('concat'); + + assert.equal(concat, null); + assert.ok(uglify); + + assert.equal(uglify.generated.files.length, 1); + var files = uglify.generated.files[0]; + + assert.equal(files.dest, path.normalize('dist/scripts/plugins.js')); + }); + it('should have configurable flow per target', function () { grunt.log.muted = true; grunt.config.init(); @@ -576,10 +745,8 @@ describe('useminPrepare', function () { assert.equal(uglify.generated.files.length, 1); var files = uglify.generated.files[0]; assert.equal(files.dest, path.normalize('dist/scripts/plugins.js')); - }); - it('should allow use to furnish new steps of the flow', function () { var copy = { name: 'copy', @@ -619,6 +786,47 @@ describe('useminPrepare', function () { assert.equal(copyCfg.generated.files[0].dest, path.normalize('dist/scripts/plugins.js')); }); + it('should allow use to furnish new steps of the multiple flow', function () { + var copy = { + name: 'copy', + createConfig: function (context, block) { + var cfg = {}; + var files = {}; + var inFiles = []; + context.inFiles.forEach(function (file) { + inFiles.push(path.join(context.inDir, file)); + }); + files.dest = path.join(context.outDir, block.dest); + files.src = inFiles; + cfg.files = [files]; + return cfg; + } + }; + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + flow: { + steps: { + js: [copy] + }, + post: {} + } + } + } + }); + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var copyCfg = grunt.config('copy'); + + assert.ok(copyCfg); + assert.equal(copyCfg.generated.files[0].dest, path.normalize('dist/scripts/plugins.js')); + }); + it('should allow to post configure generated steps', function () { var concatPostConfig = { @@ -658,4 +866,46 @@ describe('useminPrepare', function () { assert.equal(options.foo, 'bar'); }); + + it('should allow to post configure generated steps', function () { + + var concatPostConfig = { + name: 'concat', + createConfig: function (context) { + var generated = context.options.generated; + generated.options = { + foo: 'bar' + }; + } + }; + + grunt.log.muted = true; + grunt.config.init(); + grunt.config('useminPrepare', { + dev: { + src: 'index.html', + options: { + flow: { + steps: { + js: ['concat'] + }, + post: { + js: [concatPostConfig] + } + } + } + } + }); + + grunt.file.copy(path.join(__dirname, 'fixtures/usemin.html'), 'index.html'); + grunt.task.run('useminPrepare:dev'); + grunt.task.start(); + + var concatCfg = grunt.config('concat'); + var options = concatCfg.generated.options; + + assert.ok(options); + assert.equal(options.foo, 'bar'); + + }); });