UNPKG

generator-bat

Version:

BAT, the Backbone Application Template; a Yeoman generator collection created by marviq

1,363 lines (1,112 loc) 48.7 kB
## ## ==== ## ## Anatomy of a build: ## ## * The build's filesystem layout ## * Source directory: ## * src/ ## ## * Distribution artifacts' destination directory: ## * dist/ ## ## * Assembly directories: ## * dist/app/ - collects the app's build results ## * dist/doc/ - collects the app's code documentation ## ## * Source directory for per target-environment settings ## * settings/ ## ## * Tests and reports directories: ## * test/ ## * test-report/ ## ## * The build's distribution artifacts ## ## * The application ## * The application's code documentation ## ## * The build's target-environment: ## * local ## * testing ## * acceptance ## * production ## ## * The build parts: ## * app<@ if ( i18n ) { @> ## * i18n<@ } @> ## * style ## * target-environment settings ## * brief ## * bootstrap ## * documentation ## ## * The build's debugging mode: ## * debugging, - alias debug ## * non-debugging, - alias dist - note the overloading of the 'dist' term. ## ## * The build packing: ## * as-is ## * minified - alias uglified ## ## * The build's tests ## ## * The build tools. These almost map 1-to-1 on the npm-loaded grunt tasks: ## ## * browserify - for the app build part ## * clean ## * compass - for the style build part ## * compress - for the application and documentation build artifacts ## * copy ## * template - for the bootstrap build part ## * uglify ## * yuidoc - for the documentation build part ## ## The above all have to do with the actual assembly of the build. ## Apart from these, there are also: ## ## * Verification and testing: ## * coffeelint ## * coffee_jshint ## * karma & jasmine ## ## * Development support tools: ## * watch ## ## ## Note that the above factors are not entirely clear-cut: ## ## * The build's packing and build debugging-type are somewhat intertwined: ## ## * A debugging build implies as-is packing. ## * Minified packing implies a non-debugging build. ## ## * The build environment directly determines the default target-environment settings's build part's source. ## ## * The build's artifacts are an all-or-nothing deal, currently. ## ## * The build parts can be processed seperately, but some depend on others: ## * The bootstrap build part needs a brief. ## * The app build part will also trigger builds of the <@ if ( i18n ) { @>i18n, <@ } @>style, target-environment settings, brief, and bootstrap ## build parts. ## ## ## Mapping to grunt tasks and targets: ## ## As briefly indicated, the build tools map 1-to-1 onto the npm-loaded grunt tasks. ## Where applicable, for these tools, build parts and debugging mode map to their task's targets. ## ## For instance, the `browserify` grunt task is one of the tools needed to build the app part, either in ## debugging (app_debug), or non-debugging (app_dist) mode. ## ## browserify: ## app_dist: ## <specific config> ## ## app_debug: ## <specific config> ## ## ## Build parts may map to more than one tool. In fact, generally, part builds have three phases: ## ## * clean phase - maps to clean task, one target per build part ## * copy phase - maps to copy task, one target per build part ## * construction phase - maps to part specific tasks, one target per build part and possibly, debugging mode ## ## ## Some part builds have more phases than these; verification and testing phases for instance. ## ## Grunt tasks per build part exist, controlling these phases. ## ## ## Finally, this is how the main grunt commandline tasks are mapped to all of the above: ## ## * grunt [default] - shortcut for `grunt dist` unless the `GRUNT_TASKS` environment variable specifies a space separated list of alternative tasks to ## run instead; ## ## * grunt dist - does a for-production, non-debugging, all-parts, tested, minified build plus artifacts; ## * grunt debug - does a for-testing, debugging, all-parts except documentation, tested, as-is build; ## * grunt dev - does a for-local, debugging, all-parts except documentation, as-is build; ## (Note that this variant doesn't exit. Instead, it'll keep a close watch on ## filesystem changes, selectively re-triggering part builds as needed) ## ## ## The `--target` command line option sets the build target environment. ## So, for an for-acceptance, non-debugging, all-parts, tested, minified build, do: ## ## * grunt --target=acceptance ## ## ==== ## 'use strict' child_process = require( 'child_process' ) glob = require( 'glob' ) path = require( 'path' ) _ = require( 'underscore' ) module.exports = ( grunt ) -> grunt.initConfig( ## ------------------------------------------------ ## Build configuration ## ------------------------------------------------ ## ## Contents of npm's 'package.json' file as `<%= npm.pkg.* %>` ## Installed dependencies of npm's 'package.json' file as `<%= npm.installed.* %>` ## npm: pkg: grunt.file.readJSON( 'package.json' ) installed: JSON.parse( child_process.execSync( 'npm ls --json --prod --depth 0 --silent' )).dependencies ## ## Local data as `<%= build.* %>` ## build: ## ## Filesystem: ## ## Included for configurations that need an absolute path. ## base: '<%= process.cwd() %>/' source: 'src/' dist: 'dist/' assembly: app: '<%= build.dist %>app/' doc: '<%= build.dist %>doc/' settings: 'settings/' test: src: 'test/' report: 'test-report/' artifactBase: '<%= build.dist %><%= npm.pkg.name %>-<%= npm.pkg.version %>' ## ## This is the default build environment but may be overridden by the 'environment' task ## environment: 'production' ## ## Parts: ## part: app: src: browserify: '<%= build.source %>app.coffee' ## To have certain code included only in debug builds, prefix the filename with `debug.` ## debug: '<%= build.source %>**/debug.*.coffee' lint: '<%= build.source %>**/*.coffee' ## NOTE: `<%= npm.pkg.main %>` should have `<%= build.dist %>` as its prefix: ## tgt: '<%= npm.pkg.main %>' brief: tgt: '<%= build.assembly.app %>build.json' bootstrap: src: '<%= build.source %>index.template.html' tgt: '<%= build.assembly.app %>index.html' doc: ## NOTE: Directories to include and to exclude cannot be expressed in a single expression. ## src: [ '<%= build.source %>', 'vendor' ] srcExclude: [] ## NOTE: `tgt` - must - be a directory. ## tgt: '<%= build.assembly.doc %>'<@ if ( i18n ) { @> i18n: src: '<%= build.source %>i18n/' tgt: '<%= build.assembly.app %>i18n/'<@ } @> settings: src: '<%= build.settings %><%= build.environment %>.json' tgt: '<%= build.assembly.app %>settings.json' style: src: copy: '<%= build.source %>style/' compass: '<%= build.source %>sass/' tgtDir: '<%= build.assembly.app %>style/' ## NOTE: This file will be created because the `style.src.compass` dir contains a file 'app.sass' ## This will be true for any '*.sass' file, except when its filename contains a leading underscore ('_') character. ## tgt: '<%= build.part.style.tgtDir %>app.css' ## ------------------------------------------------ ## Configuration for each npm-loaded task:target ## ------------------------------------------------ ## ## Where applicable these task have a target per build part and sometimes, debugging mode. ## ## ## Compile and bundle your code. ## ## https://github.com/jmreidy/grunt-browserify#readme ## ## https://github.com/substack/node-browserify#readme ## https://github.com/substack/node-browserify#browserifyfiles--opts ## ## https://github.com/substack/browserify-handbook#packagejson ## ## file:./package.json ## ## - browser : https://github.com/substack/browserify-handbook#browser-field ## ## You can define a "browser" field in the package.json of any package that will tell browserify to override lookups for the main field and ## for individual modules. ## ## The browser field only applies to the current package. Any mappings you put will not propagate down to its dependencies or up to its ## dependents. This isolation is designed to protect modules from each other so that when you require a module you won't need to worry about ## any system-wide effects it might have. Likewise, you shouldn't need to wory about how your local configuration might adversely affect ## modules far away deep into your dependency graph. ## ## See also: ## - https://github.com/substack/node-browserify#browser-field ## - https://gist.github.com/defunctzombie/4339901 ## ## ## - browserify.transform : https://github.com/substack/browserify-handbook#browserifytransform-field ## ## You can configure transforms to be automatically applied when a module is loaded in a package's browserify.transform field. ## ## Like the "browser" field, transforms configured in package.json will only apply to the local package for the same reasons. ## ## See also: ## - https://github.com/substack/node-browserify#browserifytransform ## ## - browserify-shim : https://github.com/substack/browserify-handbook#browserify-shim ## ## See also: ## - https://github.com/thlorenz/browserify-shim#readme ## browserify: options: ## Transforms are ideally set in 'package.json' as 'browserify.transform'. ## ## Shadowed here - commented out - but documented, for easy reference. ## ## Browserify transforms are run in order and may modify your source code along the way. ## ## You'll typically want to include 'browserify-shim' last. ## ### transform: [ ## https://github.com/jnordberg/coffeeify#readme ## 'coffeeify' ## https://github.com/epeli/node-hbsfy#readme ## 'hbsfy' ## https://github.com/thlorenz/browserify-shim#readme ## 'browserify-shim' ] ### ## Caveat: Using the extra variable `browserifyOptions` to share a common set between the different targets below. Afaict this can't be done ## any other way. (Duplicating doesn't count). ## browserifyOptions: ( browserifyOptions = ## Scan all files for process, global, __filename, and __dirname, defining as necessary. ## With this option npm modules are more likely to work but bundling takes longer. ## ## When you find yourself using 'browserify-shim', you're likely to want to leave this set to `true`. ## If not, have a try at setting this to `false` for extra build speed. ## detectGlobals: true extensions: [ '.coffee' '.hbs' ] ## Skip all require() and global parsing for each file in this array. ## For giant libs like jquery or threejs that don't have any requires or node-style globals but ## take forever to parse. ## noParse: [ 'jquery' ] )<@ if ( jqueryCdn ) { @> ## Do not include `jquery` in the output bundle. It is an `npm install`ed dependency, and `require()`d, chiefly, by `Backbone`. ## Instead, a `<script>` tag in the main entry point will load `jquery` from a CDN. ## A 'browserify-shim' will take care of exposing that jquery to the app. (see 'package.json') ## The app will take care of exposing it to Backbone. ## exclude: [ 'jquery' ]<@ } @> ## Non-debugging build ## app_dist: files: [ src: '<%= build.part.app.src.browserify %>' dest: '<%= build.part.app.tgt %>' ] ## Debugging build ## app_debug: options: watch: true browserifyOptions: _.extend( {} , browserifyOptions , debug: true ) files: [ src: [ '<%= build.part.app.src.browserify %>', '<%= build.part.app.src.debug %>' ] dest: '<%= build.part.app.tgt %>' ] ## ## Remove your previously built build results. ## ## https://github.com/gruntjs/grunt-contrib-clean#readme ## clean: ## ## Distribution artifact destination directory: ## dist: files: [ src: '<%= build.dist %>' ] ## ## Per build part cleaning within the above destination directory: ## app: files: [ src: '<%= build.part.app.tgt %>' ] brief: files: [ src: '<%= build.part.brief.tgt %>' ] bootstrap: files: [ src: '<%= build.part.bootstrap.tgt %>' ] doc: files: [ src: '<%= build.part.doc.tgt %>' ]<@ if ( i18n ) { @> i18n: files: [ src: '<%= build.part.i18n.tgt %>' ]<@ } @> settings: files: [ src: '<%= build.part.settings.tgt %>' ] style: files: [ src: '<%= build.part.style.tgtDir %>' ] ## ## Delint your coffeescript - before transpilation to javascript. ## ## https://github.com/vojtajina/grunt-coffeelint#readme ## ## http://www.coffeelint.org/ ## file:./coffeelint.json ## coffeelint: options: configFile: 'coffeelint.json' app: files: [ src: '<%= build.part.app.src.lint %>' ] gruntfile: files: [ src: 'Gruntfile.coffee' ] test: files: [ src: '<%= build.test.src %>**/*.coffee' ] ## ## Delint your coffeescript - after transpilation to javascript. ## ## https://github.com/bmac/grunt-coffee-jshint#readme ## ## https://github.com/Clever/coffee-jshint#readme ## http://www.jshint.com/docs/options/ ## http://www.jshint.com/ ## coffee_jshint: options: ## NOTE: The use of browserify and the UMD (Universal Module Definition) pattern implies the legimate use of the globals below. ## ## I would have liked to specify these globals and other jshint options through a '.jshintrc' file instead but have been unsuccessful so far. ## ## Look at the supplied 'file:./.jshintrc' for further inspiration. ## globals: [ 'define' ] ## Caveat: Using the extra variable `jshintOptions` to share a common set between the different targets below. Afaict this can't be done any ## other way. (Duplicating doesn't count). ## jshintOptions: ( jshintOptions = [ ## Enforcing options: 'eqeqeq' 'forin' 'noarg' 'nonew' 'undef' 'unused' ## Relaxing options: 'debug' 'loopfunc' 'validthis' ]) app: options: jshintOptions: jshintOptions.concat( [ ## Environment options: 'browserify' 'browser' 'devel' ] ) files: '<%= coffeelint.app.files %>' gruntfile: options: jshintOptions: jshintOptions.concat( [ ## Environment options: 'node' ] ) files: '<%= coffeelint.gruntfile.files %>' test: options: jshintOptions: jshintOptions.concat( [ ## Environment options: 'jasmine' 'node' ] ) files: '<%= coffeelint.test.files %>' ## ## Compile your sass to bundled css. ## ## https://github.com/gruntjs/grunt-contrib-compass#readme ## ## http://compass-style.org/help/documentation/configuration-reference/ ## ## http://sass-lang.com/documentation/file.SASS_REFERENCE.html#options ## http://sass-lang.com/documentation/file.SASS_REFERENCE.html#output_style ## compass: options: ## This is not a "rails" app `project_type` ## app: 'stand_alone' ## Source sassDir: '<%= build.part.style.src.compass %>' ## Destination cssDir: '<%= build.part.style.tgtDir %>' ## Images and fonts will have been copied here first by means of the `copy:style` task. ## imagesDir: '<%= build.part.style.tgtDir %>images/' fontsDir: '<%= build.part.style.tgtDir %>fonts/' ## Compass's asset helper functions should produce urls relative to the stylesheet. ## relativeAssets: true raw: 'sass_options = { :property_syntax => :new }\n' style_dist: options: environment: 'production' outputStyle: 'compressed' style_debug: options: environment: 'development' outputStyle: 'nested' sourcemap: true ## ## Create your distribution artifacts. ## ## https://github.com/gruntjs/grunt-contrib-compress#readme ## compress: app_dist: options: archive: '<%= build.artifactBase %>.zip' files: [ expand: true cwd: '<%= build.assembly.app %>' src: '**/*' dest: '.' ] app_debug: options: archive: '<%= build.artifactBase %>-debug.zip' files: '<%= compress.app_dist.files %>' doc: options: archive: '<%= build.artifactBase %>-doc.zip' files: [ expand: true cwd: '<%= build.assembly.doc %>' src: '**/*' dest: '.' ] ## ## Copy your build bits that needs no transformation. ## ## https://github.com/gruntjs/grunt-contrib-copy#readme ## copy: options: mode: true timestamp: true<@ if ( i18n ) { @> i18n: files: [ filter: 'isFile' expand: true cwd: '<%= build.part.i18n.src %>' src: '**/*' dest: '<%= build.part.i18n.tgt %>' ]<@ } @> settings: files: [ filter: 'isFile' src: '<%= build.part.settings.src %>' dest: '<%= build.part.settings.tgt %>' ] style: files: [ filter: 'isFile' expand: true cwd: '<%= build.part.style.src.copy %>' src: '**/*' dest: '<%= build.part.style.tgtDir %>' ] ## ## Test your code. ## ## https://github.com/karma-runner/grunt-karma#readme ## ## Karma: ## https://github.com/karma-runner/karma#readme ## http://karma-runner.github.io/1.0/ ## ## Browserify: ## https://github.com/nikku/karma-browserify#readme ## ## See also the `browserify:` section in this config for more info on browserify and **its** preprocessors: ## ## coffeeify ## hbsfy ## browserify-shim ## ## Jasmine: ## https://github.com/karma-runner/karma-jasmine#readme ## https://github.com/jasmine/jasmine#readme ## http://jasmine.github.io/ ## http://tryjasmine.com/ ## ## PhantomJS: ## https://github.com/karma-runner/karma-phantomjs-launcher#readme ## https://github.com/Medium/phantomjs#readme ## http://phantomjs.org/ ## ## ## The following combo of posts has been instrumental in getting this to work: ## ## http://nick.perfectedz.com/browserify-unit-testing-p1/ ## http://nick.perfectedz.com/browserify-unit-testing-p2/ ## karma: ## https://karma-runner.github.io/1.0/config/configuration-file.html ## options: basePath: '<%= build.test.src %>' ## https://karma-runner.github.io/1.0/config/browsers.html ## browsers: [ 'PhantomJS' ] ## https://karma-runner.github.io/1.0/config/files.html ## exclude: [] files: [] frameworks: [ ## https://github.com/nikku/karma-browserify#usage ## ## "Add browserify as a framework to your Karma configuration file." ## 'browserify' 'jasmine' ] hostname: 'localhost' httpServerOptions: {} logLevel: 'INFO' loggers: [ ## https://github.com/nomiddlename/log4js-node#readme ## type: 'console' ] ## https://karma-runner.github.io/1.0/config/plugins.html ## ## By default, Karma loads all sibling NPM modules which have a name starting with karma-*. ## We like to be explicit, so: ## plugins: [ 'karma-browserify' 'karma-jasmine' 'karma-phantomjs-launcher' ] port: 9876 ## https://karma-runner.github.io/1.0/config/preprocessors.html ## ## Note that there's no need for a `karma-coffee-preprocessor` because that's taken care of by browserify. ## preprocessors: 'unit/init.coffee': [ 'browserify' ] '**/spec/**/*': [ 'browserify' ] protocol: 'http:' ## https://karma-runner.github.io/1.0/config/files.html ## ## Section: Loading Assets ## proxies: {} ## Not related to `karma.options.proxies` setting above. ## ## Whether or not Karma or any browsers should raise an error when an inavlid SSL certificate is found. ## proxyValidateSSL: true reporters: [ 'progress' ] urlRoot: '/' ## Continuous integration mode: ## autoWatch: false background: false colors: false singleRun: true ## ## Plugin specific config: ## ## Browserify: ## ## Reuse `browserify.options.browserifyOptions`. ## browserify: _.extend( {} , browserifyOptions , debug: true<@ if ( jqueryCdn ) { @> ## This is the `karma-browserify` equivalent of `browserify.options.exclude`. ## configure: ( bundle ) -> bundle.on( 'prebundle', () -> bundle.external( 'jquery' ); return ); return<@ } @> ) unit_ci: options: ## Note that `files` is part of this task's extenstion of `karma.options` and its files are therefore relative to `karma.options.basePath`. ## Despite appearance, this is **not** a grunt task's `files` declaration. ## ## https://karma-runner.github.io/1.0/config/files.html ## files: [<@ if ( jqueryCdn ) { @> ## External dependencies to be loaded as `<script/>`s. ## ## * jQuery ## ## jQuery is in this list because the `browserify-shim` config in `package.json` specifies that `require('jquery')` will return ## the global jQuery object: ## ## It does this because `jQuery` will be excluded from a browserify build as specified at: ## ## `browserify.options.exclude` ## ## We have mimicked that behaviour through `karma.options.browserify.configure`. ## ## Loading `jquery` from a cdn will also work, but doing it like this will minimize impact on testing during continuous ## integration ('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'). ## '../node_modules/jquery/dist/jquery.js' ,<@ } @> ## Setup / initialization before all tests. ## 'unit/init.coffee' , ## The unit tests' specs. ## pattern: 'unit/spec/**/*' , ## Assets; non-code files. ## See `proxies` section, below, to see how urls are mapped to these ## pattern: 'unit/asset/**/*' included: false served: true ] proxies: '/settings.json': '/base/unit/asset/settings.json' unit_dev: options: autoWatch: true colors: true singleRun: false files: '<%= karma.unit_ci.options.files %>' proxies: '<%= karma.unit_ci.options.proxies %>' ## ## Substitute build targets and - for cache-busting reasons - a build-run identifier into your app's main ## entry point. ## ## https://github.com/mathiasbynens/grunt-template#readme ## template: bootstrap: options: data: () -> file = grunt.config( 'build.part.brief.tgt' ) ## Don't let grunt handle the exception if this fails. ## brief = do () -> ### jshint unused: false ### try grunt.file.readJSON( file ) catch dummy grunt.fail.fatal( "Unable to read the build brief (\"#{file}\"). Wasn't it created?" ) unless brief?.timestamp environment: brief.environment app: path.relative( grunt.config( 'build.assembly.app' ), grunt.config( 'build.part.app.tgt' )) style: path.relative( grunt.config( 'build.assembly.app' ), grunt.config( 'build.part.style.tgt' )) styleBase: path.relative( grunt.config( 'build.assembly.app' ), grunt.config( 'build.part.style.tgtDir' )) buildRun: brief.buildNumber or brief.timestamp debugging: brief.debugging npm: grunt.config( 'npm' ) files: [ src: '<%= build.part.bootstrap.src %>' dest: '<%= build.part.bootstrap.tgt %>' ] ## ## Minify your compiled and bundled code. ## ## https://github.com/gruntjs/grunt-contrib-uglify#readme ## ## https://github.com/mishoo/UglifyJS2#readme ## http://lisperator.net/uglifyjs/ ## uglify: app: options: compress: drop_console: true files: [ src: '<%= build.part.app.tgt %>' dest: '<%= build.part.app.tgt %>' ] ## ## https://github.com/gruntjs/grunt-contrib-watch#readme ## ## Note that 'watch' isn't your garden-variety multi-task even though its config makes it deceivingly look ## like one. ## ## Its intended mode of operation is as a (non-multi-) task, like: `grunt watch`. ## Doing so will make it watch **all** targets' files and fork their associated `tasks` on any detected change. ## ## That doesn't mean that it isn't possible to, say, `grunt watch:coffee`, it is, but its a one or all choice; ## Making it work for multiple targets (except all) is not possible. ## ## Also note that a value for `files` can only be a pattern string or an array of such values ## (yes that definition is recursive). ## watch: options: spawn: false ## ## The browserify task does its own watching. ## ## But for linting purposes we watch all coffee files here too. ## app: files: '<%= build.part.app.src.lint %>' tasks: 'lint:app' bootstrap: options: livereload: true files: [ ## Watch for changed assembly - targets - ## '<%= build.part.app.tgt %>'<@ if ( i18n ) { @> '<%= build.part.i18n.tgt %>**/*'<@ } @> '<%= build.part.settings.tgt %>' '<%= build.part.style.tgtDir %>**/*.css' ## Watch for changed bootstrap - source - ## '<%= build.part.bootstrap.src %>' ] tasks: [ 'brief:debug' 'bootstrap:debug' ]<@ if ( i18n ) { @> i18n: files: [ '<%= build.part.i18n.src %>**/*' ] tasks: 'i18n'<@ } @> settings: files: '<%= build.part.settings.src %>' tasks: [ 'environment:<%= build.environment %>' 'settings' ] style: files: [ '<%= build.part.style.src.copy %>**/*' '<%= build.part.style.src.compass %>**/*' ] tasks: 'style:debug' ## ## Generate your code's documentation ## ## https://github.com/gruntjs/grunt-contrib-yuidoc#readme ## ## http://yui.github.io/yuidoc/args/#command-line ## http://yui.github.io/yuidoc/args/#yuidocjson-fields ## yuidoc: app: name: '<%= npm.pkg.name %>' description: '<%= npm.pkg.description %>' url: '<%= npm.pkg.homepage %>' version: '<%= npm.pkg.version %>' options: ## NOTE: Globbing patterns in `paths` cannot match - any - symbolically linked directories; yuidoc will not find them. ## ## Therefore, the 'doc' task will do any globbing expansion beforehand, and then reset `paths` to the result. ## paths: '<%= build.part.doc.src %>' ## NOTE: `exclude` must be a string containing comma separated paths to directories. ## ## This is exactly what the template expansion below will achieve: ## exclude: '<%= grunt.file.expand( grunt.config( "build.part.doc.srcExclude" )) %>' ## NOTE: Yuidoc will empty the `outdir` directory before construction. ## outdir: '<%= build.part.doc.tgt %>' extension: '.coffee' syntaxtype: 'coffee' linkNatives: true tabtospace: 4 ## NOTE: The list of external YUIDoc documentation sets, as bundled with installed packages will be dynamically ## established when the 'doc' task is run. ## external: {} ) ## ================================================ ## The build tools, npm-loaded tasks: ## ## Be sure to have `npm install <plugin> --save-dev`-ed each of these: ## ================================================ grunt.loadNpmTasks( 'grunt-browserify' ) grunt.loadNpmTasks( 'grunt-coffeelint' ) grunt.loadNpmTasks( 'grunt-coffee-jshint' ) grunt.loadNpmTasks( 'grunt-contrib-clean' ) grunt.loadNpmTasks( 'grunt-contrib-compass' ) grunt.loadNpmTasks( 'grunt-contrib-compress' ) grunt.loadNpmTasks( 'grunt-contrib-copy' ) grunt.loadNpmTasks( 'grunt-contrib-uglify' ) grunt.loadNpmTasks( 'grunt-contrib-watch' ) grunt.loadNpmTasks( 'grunt-contrib-yuidoc' ) grunt.loadNpmTasks( 'grunt-karma' ) grunt.loadNpmTasks( 'grunt-template' ) ## ================================================ ## The build tools, internally defined tasks: ## ================================================ grunt.registerTask( 'create_brief' 'Generate \'build.json\' file containing the build details' ( debugging ) -> stamp = new Date() buildNumber = process.env.BUILD_NUMBER unless buildNumber localBuild = 'build.localNumber' localNumber = grunt.config( localBuild ) or 0 buildNumber = "+#{localNumber}" grunt.config.set( localBuild, localNumber + 1 ) buildInfo = buildNumber: buildNumber buildId: process.env.BUILD_ID or null revision: process.env.GIT_COMMIT or 'working dir' grunted: grunt.template.date( stamp, 'yyyy mmm dd HH:MM:ss' ) environment: grunt.config( 'build.environment' ) debugging: ( debugging is 'debug' ) name: grunt.config( 'npm.pkg.name' ) version: grunt.config( 'npm.pkg.version' ) timestamp: +stamp grunt.file.write( grunt.config( 'build.part.brief.tgt' ), JSON.stringify( buildInfo, null, 4 )) return ) grunt.registerTask( 'environment' 'Set the target environment' ( environment ) -> if ( ( override = grunt.option( 'target' ) ? process.env.GRUNT_TARGET )? and override isnt environment ) grunt.log.ok( "Overriding target environment to \"#{override}\"" ) environment = override grunt.config.set( 'build.environment', environment ) if environment? return ) ## ================================================ ## Per build part tasks: ## ================================================ grunt.registerTask( 'app' 'Build the app.' ( debugging ) -> grunt.task.run( 'lint:app' 'clean:app' "browserify:app_#{debugging}"<@ if ( i18n ) { @> 'i18n'<@ } @> 'settings' "style:#{debugging}" ## brief before bootstrap "brief:#{debugging}" 'bootstrap' ) ) grunt.registerTask( 'brief' 'Build the build\'s brief.' ( debugging ) -> grunt.task.run( 'clean:brief' "create_brief:#{debugging}" ) ) grunt.registerTask( 'doc' 'Build the documentation' () -> ## Fully, expand any globs in 'build.part.doc.src' before passing the result to `yuidoc`. ## ## Because `yuidoc` expects either a string containing a single directory path or an array of such strings ## We cannot use the grunt template mechanism to do the substitution. ## path = 'yuidoc.app.options.paths' grunt.config( path, grunt.file.expand( grunt.config( path ))) ## ## Include any installed npm dependencies with bundled YUIDoc documentation, signalled by the presence of a `data.json` and some duck typing. ## externals = glob .sync( "node_modules/@(#{ Object ## Names of installed `dependencies`. ## .keys( grunt.config( 'npm.installed' )) ## ## Escaped for use in this glob expression. ## .map( ( name ) -> name.replace( /[!()*+?@\[\]^{|}]/g, '\\$&' ) ) .join( '|' ) })/**/data.json" ) .filter( ( path ) -> data = grunt.file.readJSON( path ) ## Does it walk like a duck? ## for prop in [ 'project', 'files', 'modules', 'classes', 'elements', 'classitems', 'warnings' ] return false unless data[ prop ] return true ) .map( ( path ) -> base: "/#{ path.slice( 0, -( 'data.json'.length )) }" json: path ) grunt.config( 'yuidoc.app.options.external', data: externals ) if externals.length ## grunt.task.run( 'clean:doc' 'yuidoc:app' ) ) grunt.registerTask( 'bootstrap' 'Build the app\'s startup entry point.' [ 'clean:bootstrap' 'template:bootstrap' ] )<@ if ( i18n ) { @> grunt.registerTask( 'i18n' 'Build the app\'s internationalization files' [ 'clean:i18n' 'copy:i18n' ] )<@ } @> grunt.registerTask( 'lint' 'Look for lint in the app\'s code' ( target = '' ) -> grunt.task.run( "coffeelint:#{target}" "coffee_jshint:#{target}" ) ) grunt.registerTask( 'settings' 'Build the build\'s target environment\'s settings.' [ 'clean:settings' 'copy:settings' ] ) grunt.registerTask( 'style' 'Build the app\'s stylesheet and related assets' ( debugging ) -> grunt.task.run( 'clean:style' 'copy:style' "compass:style_#{debugging}" ) ) grunt.registerTask( 'test' 'Unit test the app\'s code' ( mode = 'ci' ) -> grunt.task.run( "karma:unit_#{mode}" ) ) ## ================================================ ## Command line tasks; the usual suspects anyway: ## ================================================ grunt.registerTask( 'default' 'Shortcut for `grunt dist` unless the `GRUNT_TASKS` environment variable specifies a space separated list of alternative tasks to run instead.' () -> tasks = process.env.GRUNT_TASKS?.split( /\s/ ) grunt.task.run( if tasks?.length then tasks else 'dist' ) ) grunt.registerTask( 'dist' [ 'clean:dist' 'environment:production' 'app:dist' 'uglify:app' 'test:ci' 'compress:app_dist' 'doc' 'compress:doc' ] ) grunt.registerTask( 'debug' [ 'clean:dist' 'environment:testing' 'app:debug' 'test:ci' 'compress:app_debug' ] ) grunt.registerTask( 'dev' [ 'clean:dist' 'environment:local' 'app:debug' 'watch' ] )