#!/usr/bin/env node var program = require('commander'); // options program .usage('component build [scripts] [styles] [files]') .option('-w, --watch', 'watch for file changes and rebuild automatically') .option('-r, --reload', 'refresh livereload server on file changes (works only with --watch)') .option('-o, --out ', 'output directory defaulting to ./build', 'build') .option('-n, --name ', 'base name for build files defaulting to build', 'build') .option('-d, --dev', 'build development dependencies, use aliases, and use sourceURLs') .option('-s, --standalone [name]', 'build a standalone, UMD-wrapped version of the component with the given global name') .option('-R, --no-require', 'exclude require from build') .option('-a, --no-auto', 'not require automatically') .option('-p, --prefix ', 'prefix css asset urls with ', '') .option('-b, --browsers ', 'browsers to support with autoprefixer') .option('-c, --copy', 'copy files instead of linking') .option('--umd [name]', 'alias for --standalone') .option('--debug', 'turn on debug statements'); // examples program.on('--help', function(){ console.log(' Examples:'); console.log(); console.log(' # build to ./build'); console.log(' $ component build'); console.log(); console.log(' # build to ./dist as assets.js, assets.css'); console.log(' $ component build -o dist -n assets'); console.log(); console.log(' # build as standalone as window.$'); console.log(' $ component build --standalone $'); console.log(); console.log(' # build only .js'); console.log(' $ component build scripts'); console.log(); process.exit(); }); // parse argv program.parse(process.argv); if (program.debug) require('debug').enable('component-build*,component-consoler*,component-resolver*'); var Resolve = require('component-resolver'); var utils = require('component-consoler'); var Build = require('component-build'); var mkdir = require('mkdirp'); var path = require('path'); var fs = require('fs'); var rimraf = require('rimraf'); var exists = fs.existsSync || path.existsSync; var args = program.args; var log = utils.log; var slice = Array.prototype.slice; // object of which files to build var builds; if (!args.length) { builds = { scripts: true, styles: true, files: true, }; } else { builds = { scripts: !!~args.indexOf('scripts') || !!~args.indexOf('js'), styles: !!~args.indexOf('styles') || !!~args.indexOf('css'), files: !!~args.indexOf('files'), }; } // component.json required if (!exists('component.json')) utils.fatal('missing component.json'); // output paths var jsPath = path.join(program.out, program.name + '.js'); var cssPath = path.join(program.out, program.name + '.css'); // mkdir -p mkdir.sync(program.out); // whitespace console.log(); process.on('exit', function(){ console.log(); }); // resolve var options = { development: program.dev, install: true, verbose: true, require: program.require, autorequire: program.auto, umd: program.standalone || program.umd || '', prefix: program.prefix || '', browsers: program.browsers, destination: program.out, copy: program.copy, }; var watching = program.watch || program.reload; var resolving = false; var build; if (!watching) return resolve(); var watcher = require('component-watcher')({ root: process.cwd(), development: program.dev }); watcher.on('resolve', resolve); watcher.on('scripts', buildScripts); watcher.on('styles', buildStyles); process.stdin.setEncoding('utf8'); process.stdin.on('data', function (data) { switch (data.trim()) { case 'r': case 'resolve': return resolve(); case 's': case 'j': case 'js': case 'scripts': return buildScripts(); case 'c': case 'css': case 'styles': return buildStyles(); } }); if (!program.reload) return; var server = require('tiny-lr-fork')(); server.listen(35729); server.on('error', function (err) { if (err.code === 'EADDRINUSE') { utils.fatal('livereload port 35729 is already in use by another process'); } utils.fatal(err); }); function reload() { if (program.reload) { server.changed({ body: { files: slice.call(arguments) } }); } } function resolve() { if (resolving) return; resolving = true; var start = Date.now(); Resolve(process.cwd(), options, function (err, tree) { resolving = false; if (err) { if (!watching) utils.fatal(err); utils.error('build', 'resolve failed: ' + err.message); return; } build = Build(tree, options); log('build', 'resolved in ' + (Date.now() - start) + 'ms'); buildScripts(); buildStyles(); buildFiles(); }) } function buildScripts() { if (resolving) return; if (!builds.scripts) return; var start = Date.now(); build.scripts(function (err, js) { if (err) { utils.error(err); if (fs.existsSync(jsPath)) fs.unlinkSync(jsPath); return; } if (!js) return; fs.writeFile(jsPath, js); log('build', jsPath + ' in ' + (Date.now() - start) + 'ms - ' + (js.length / 1024 | 0) + 'kb'); reload(jsPath); }) } function buildStyles() { if (resolving) return; if (!builds.styles) return; var start = Date.now(); build.styles(function (err, css) { if (err) { utils.error(err); if (fs.existsSync(cssPath)) fs.unlinkSync(cssPath); return; } if (!css) return; fs.writeFile(cssPath, css); log('build', cssPath + ' in ' + (Date.now() - start) + 'ms - ' + (css.length / 1024 | 0) + 'kb'); reload(cssPath); }) } function buildFiles() { if (resolving) return; if (!builds.files) return; var start = Date.now(); build.files(function (err) { if (err) { utils.error(err); rimraf(options.destination, function(err) { if (err) utils.fatal(err); return }); } else { log('build', 'files in ' + (Date.now() - start) + 'ms'); } }) }