.gitignore000066400000000000000000000002271517651455400130640ustar00rootroot00000000000000node_modules npm-debug.log tmp *.sublime-project *.sublime-workspace /build /dist /node_modules /*.log /*.iws .idea/workspace.xml .idea/tasks.xml .idea/000077500000000000000000000000001517651455400120535ustar00rootroot00000000000000.idea/grunt-express-server.iml000066400000000000000000000005201517651455400167050ustar00rootroot00000000000000 .idea/inspectionProfiles/000077500000000000000000000000001517651455400157325ustar00rootroot00000000000000.idea/inspectionProfiles/Project_Default.xml000066400000000000000000000003711517651455400215270ustar00rootroot00000000000000 .idea/misc.xml000066400000000000000000000015161517651455400135330ustar00rootroot00000000000000 true false true .idea/modules.xml000066400000000000000000000004441517651455400142470ustar00rootroot00000000000000 .idea/vcs.xml000066400000000000000000000002471517651455400133730ustar00rootroot00000000000000 .npmrc000066400000000000000000000001061517651455400122100ustar00rootroot00000000000000https://registry.yarnpkg.com/= registry=https://registry.yarnpkg.com/ .scrutinizer.yml000066400000000000000000000005471517651455400142630ustar00rootroot00000000000000checks: javascript: true filter: excluded_paths: - test/* - node_modules/* - build/* - docs/* build: environment: node: 7.8 dependencies: before: - npm install -g grunt-cli tests: override: - command: 'grunt' coverage: file: 'build/coverage/clover.xml' format: 'clover' .travis.yml000066400000000000000000000001321517651455400132000ustar00rootroot00000000000000language: node_js node_js: - "7" - "node" before_script: - npm install grunt-cli -g .yarnrc000066400000000000000000000001031517651455400123640ustar00rootroot00000000000000registry "https://registry.yarnpkg.com/" registry.yarnpkg.com true Gruntfile.js000066400000000000000000000111631517651455400133720ustar00rootroot00000000000000/* * grunt-express-server * https://github.com/ericclemmons/grunt-express-server * * Copyright (c) 2013 Eric Clemmons * Licensed under the MIT license. */ 'use strict'; module.exports = function(grunt) { // Project configuration. grunt.initConfig({ jshint: { all: [ 'Gruntfile.js', 'tasks/**/*.js', 'test/*.js', '!test/server_malformed.js' ], options: { jshintrc: '.jshintrc', }, }, // Before generating any new files, remove any previously-created files. clean: { tests: ['tmp'], }, watch: { express: { options: { livereload: true, spawn: false }, files: [ 'Gruntfile.js', 'tasks/**/*.js', 'test/**/*.js' ], tasks: ['express:defaults'] } }, // Unit tests. nodeunit: { defaults: { src: 'test/defaults_test.js' }, custom_cmd: { src: 'test/custom_cmd_test.js' }, custom_harmony: { src: 'test/custom_harmony.js' }, custom_args: { src: 'test/custom_args_test.js' }, custom_port: { src: 'test/custom_port_test.js' }, custom_node_env: { src: 'test/custom_node_env_test.js' }, custom_delay: { src: 'test/custom_delay_test.js' }, custom_output: { src: 'test/custom_output_test.js' }, stoppable: { src: 'test/stoppable_test.js' } }, express: { options: { script: './test/server.js', port: 3000 }, defaults: {}, custom_cmd: { options: { script: './test/server.coffee', opts: ["node_modules/coffee-script/bin/coffee"], output: "Express server listening on port .+" } }, malformed: { options: { script: './test/server_malformed.js' } }, custom_harmony: { options: { harmony: true, output: "Express server listening on port .+" } }, custom_args: { options: { args: [1, 2], output: "Express server listening on port .+" } }, custom_background: { options: { background: false } }, custom_port: { options: { port: 8080, output: "Express server listening on port .+" } }, custom_node_env: { options: { node_env: "production", output: "Express server listening on port .+" } }, custom_delay: { options: { delay: 1000, output: "This RegEx does not match anything lol" } }, custom_output: { options: { output: "timeout" } }, custom_delay_output: { options: { delay: 1000, output: "Express server listening on port .+" } }, quiet: { options: { script: './test/server-quiet.js' } }, stoppable: {} } }); // Actually load this plugin's task(s). grunt.loadTasks('tasks'); // These plugins provide necessary tasks. grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-nodeunit'); grunt.loadNpmTasks('grunt-contrib-watch'); // Whenever the "test" task is run, first clean the "tmp" dir, then run this // plugin's task(s), then test the result. grunt.registerTask('test', [ 'clean', 'nodeunit:defaults', 'express:defaults', 'express:defaults:stop', 'express:malformed', 'express:custom_cmd', 'nodeunit:custom_cmd', 'express:custom_cmd:stop', 'express:custom_args', 'nodeunit:custom_args', 'express:custom_args:stop', 'express:custom_harmony', 'nodeunit:custom_harmony', 'express:custom_harmony:stop', 'express:custom_port', 'nodeunit:custom_port', 'express:custom_port:stop', 'express:custom_node_env', 'nodeunit:custom_node_env', 'express:custom_node_env:stop', 'express:custom_delay', 'nodeunit:custom_delay', 'express:custom_delay:stop', 'express:custom_output', 'nodeunit:custom_output', 'express:custom_output:stop', 'express:stoppable', 'express:stoppable:stop', 'nodeunit:stoppable', // Multiple servers 'express:custom_port', 'nodeunit:defaults', 'express:defaults', 'nodeunit:custom_port', 'express:custom_port:stop', 'express:defaults:stop', ]); // By default, lint and run all tests. grunt.registerTask('default', ['jshint', 'test']); }; README.md000066400000000000000000000226711517651455400123620ustar00rootroot00000000000000# grunt-express-server [![Build Status](https://travis-ci.org/ericclemmons/grunt-express-server.png?branch=master)](https://travis-ci.org/ericclemmons/grunt-express-server) [![Dependencies](https://david-dm.org/ericclemmons/grunt-express-server.png)](https://david-dm.org/ericclemmons/grunt-express-server) [![devDependencies](https://david-dm.org/ericclemmons/grunt-express-server/dev-status.png)](https://david-dm.org/ericclemmons/grunt-express-server#info=devDependencies&view=table) > Simple grunt task for running an Express server that works great with LiveReload + Watch/Regarde ## Getting Started This plugin requires Grunt `>=0.4.0` If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: ```shell npm install grunt-express-server --save-dev ``` Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: ```js grunt.loadNpmTasks('grunt-express-server'); ``` ## The `express` task ### Setup In your project's Gruntfile, you can create one or multiple servers: ```js grunt.initConfig({ express: { options: { // Override defaults here }, dev: { options: { script: 'path/to/dev/server.js' } }, prod: { options: { script: 'path/to/prod/server.js', node_env: 'production' } }, test: { options: { script: 'path/to/test/server.js' } } } }); ``` You can override the default `options` either in the root of the `express` config or within each individual server task. ### Default `options` ```js express: { options: { // Override the command used to start the server. // (do not use 'coffee' here, the server will not be able to restart // see below at opts for coffee-script support) cmd: process.argv[0], // Will turn into: `node OPT1 OPT2 ... OPTN path/to/server.js ARG1 ARG2 ... ARGN` // (e.g. opts: ['node_modules/coffee-script/bin/coffee'] will correctly parse coffee-script) opts: [ ], args: [ ], // Setting to `false` will effectively just run `node path/to/server.js` background: true, // Called when the spawned server throws errors fallback: function() {}, // Override node env's PORT port: 3000, // Override node env's NODE_ENV node_env: undefined, // Enable Node's --harmony flag harmony: false, // Consider the server to be "running" after an explicit delay (in milliseconds) // (e.g. when server has no initial output) delay: 0, // Regular expression that matches server output to indicate it is "running" output: ".+", // Set --debug (true | false | integer from 1024 to 65535, has precedence over breakOnFirstLine) debug: false, // Set --debug-brk (true | false | integer from 1024 to 65535) breakOnFirstLine: false, // Object with properties `out` and `err` both will take a path to a log file and // append the output of the server. Make sure the folders exist. logs: undefined } } ``` ### Usage By default, unless `delay` or `output` has been customized, **the server is considered "running" once any output is logged to the console**, upon which control is passed back to grunt. Typically, this is: > Express server listening on port 3000 If your server doesn't log anything, the express task will never finish and **none** of the following tasks, after it, will be executed. For example - if you have a development task like this one: ```javascript grunt.registerTask('rebuild', ['clean', 'browserify:scripts', 'stylus', 'copy:images']); grunt.registerTask('dev', ['rebuild', 'express', 'watch']); ``` If you run the dev task and your server doesn't log anything, **'watch' will never be started**. This can easily be avoided, if you log something, when server is created like that: ```javascript var server = http.createServer( app ).listen( PORT, function() { console.log('Express server listening on port ' + PORT); } ); ``` If you log output *before* the server is running, either set `delay` or `output` to indicate when the server has officially started. #### Starting the server If you have a server defined named `dev`, you can start the server by running `express:dev`. The server only runs as long as grunt is running. Once grunt's tasks have completed, the web server stops. #### Stopping the server Similarly, if you start the `dev` server with `express:dev`, you can stop the server with `express:dev:stop`. #### With [grunt-contrib-watch](https://github.com/gruntjs/grunt-contrib-watch) ```js grunt.initConfig({ watch: { express: { files: [ '**/*.js' ], tasks: [ 'express:dev' ], options: { spawn: false // for grunt-contrib-watch v0.5.0+, "nospawn: true" for lower versions. Without this option specified express won't be reloaded } } } }); grunt.registerTask('server', [ 'express:dev', 'watch' ]) ``` **Important:** Note that the `spawn: false` options only need be applied to the watch target regarding the express task. You may have other watch targets that use `spawn: true`, which is useful, for example, to reload CSS and not LESS changes. ```js watch: { options: { livereload: true }, express: { files: [ '**/*.js' ], tasks: [ 'express:dev' ], options: { spawn: false } }, less: { files: ["public/**/*.less"], tasks: ["less"], options: { livereload: false } }, public: { files: ["public/**/*.css", "public/**/*.js"] } } ``` ## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). ## Release History - v0.5.3 - Update peerDeps and enable travis build against Node 4 - v0.5.2 - Add `hardStop` flag ([#99](https://github.com/ericclemmons/grunt-express-server/pull/99)) - v0.5.1 - Add `harmony` flag ([#86](https://github.com/ericclemmons/grunt-express-server/pull/86)) - v0.5.0 - Add breakOnFirstLine option, support for debug ports and fix bugs. Details: ([#68](https://github.com/ericclemmons/grunt-express-server/pull/68), [#70](https://github.com/ericclemmons/grunt-express-server/pull/70), [#73](https://github.com/ericclemmons/grunt-express-server/pull/73)) - v0.4.19 – Use `process.env.PORT` before `3000` ([#59](https://github.com/ericclemmons/grunt-express-server/pull/59)) - v0.4.18 – Fix for when running the node debugger ([#57](https://github.com/ericclemmons/grunt-express-server/pull/57)) - v0.4.17 – Update `devDependencies`...again - v0.4.16 – Update `devDependencies` - v0.4.15 – Recommend using local `coffee` with additional arguments ([#50](https://github.com/ericclemmons/grunt-express-server/pull/50)) - v0.4.14 – Attempt to fix issues running Coffeescript ([#54](https://github.com/ericclemmons/grunt-express-server/pull/54)) - v0.4.13 – Add `--nodejs` for Coffeescript users ([#37](https://github.com/ericclemmons/grunt-express-server/issues/37)) - v0.4.12 – Only remove this task's listeners ([#39](https://github.com/ericclemmons/grunt-express-server/pull/39)) - v0.4.11 – Revert v0.4.10 until Travis can reproduce it - v0.4.10 – Another attempt to fix #28 & #30's server restarting issue ([#31](https://github.com/ericclemmons/grunt-express-server/pull/31)) - v0.4.9 – Revert v0.4.8 until [#30](https://github.com/ericclemmons/grunt-express-server/issues/30#issuecomment-29931192) is resolved - v0.4.8 – Fix issue with start/restarting multiple instances ([#29](https://github.com/ericclemmons/grunt-express-server/pull/29)) - v0.4.7 – Remove broken `error` option ([#27](https://github.com/ericclemmons/grunt-express-server/issues/27)) - v0.4.6 – Store running servers on `process._servers[target]` ([#22](https://github.com/ericclemmons/grunt-express-server/issues/22)) - v0.4.5 – Support multiple servers running at once ([#23](https://github.com/ericclemmons/grunt-express-server/pull/23)) - v0.4.4 - Fix for using `grunt-env` to change environments, thanks to @FredrikAppelros ([#20](https://github.com/ericclemmons/grunt-express-server/pull/20)) - v0.4.3 - Add `cmd` option that defaults to Node, but can be set to `coffee` for Coffeescript support, thanks to @JonET ([#15](https://github.com/ericclemmons/grunt-express-server/pull/15)) - v0.4.2 - Add `debug` option that gets enables Node's debugger, ideally for use with [node-inspector](https://github.com/node-inspector/node-inspector) - v0.4.1 - Add `node_env` option that sets `NODE_ENV` when running the server & restores original env upon closing, thanks to @jgable! - v0.4.0 - Add `delay` option that, when set, passes control back to grunt after timeout - Add `output` regular expression option that, when set, waits for matching message before passing control back to grunt - v0.3.1 - Try to force notification that `express` task has finished as much as possible - v0.3.0 - `express` is now a multitask with customizable options, better error handling and `:stop` task - v0.2.0 - Change `express-server` task to `express` - Config is set via `express: '...'` instead of `server: { script: '...' } ` - v0.1.0 - Initial import from [Genesis Skeleton](https://github.com/ericclemmons/genesis-skeleton) & release package.json000066400000000000000000000021461517651455400133640ustar00rootroot00000000000000{ "name": "grunt-p3x-express", "description": "Grunt task for running an Express Server that works great with LiveReload + Watch/Regarde", "version": "1.0.0", "homepage": "https://github.com/patrikx3/grunt-p3x-express", "author": { "name": "Eric Clemmons", "email": "eric@smarterspam.com" }, "contributors": [ { "name": "Patrik Laszlo", "email": "alabard@gmail.com" } ], "repository": { "type": "git", "url": "git://github.com/patrikx3/grunt-p3x-express.git" }, "bugs": { "url": "https://github.com/patrikx3/grunt-p3x-express/issues" }, "license": "MIT", "main": "Gruntfile.js", "engines": { "node": ">= 0.10.0" }, "scripts": { "test": "./node_modules/.bin/grunt" }, "devDependencies": { "express": "^4.0.0", "grunt": "^1.0.1", "grunt-cli": "^1.2.0", "grunt-contrib-clean": "^1.0.0", "grunt-contrib-jshint": "^1.0.0", "grunt-contrib-nodeunit": "^1.0.0", "grunt-contrib-watch": "^1.0.0" }, "peerDependencies": { "grunt": ">=0.4.0" }, "keywords": [ "gruntplugin", "express", "server" ] } tasks/000077500000000000000000000000001517651455400122205ustar00rootroot00000000000000tasks/express.js000066400000000000000000000026621517651455400142550ustar00rootroot00000000000000/* * grunt-express-server * https://github.com/ericclemmons/grunt-express-server * * Copyright (c) 2013 Eric Clemmons * Licensed under the MIT license. */ 'use strict'; var path = require('path'); module.exports = function(grunt) { var servers = {}; grunt.registerMultiTask('express', 'Start an express web server', function() { if (!servers[this.target]) { servers[this.target] = require('./lib/server')(grunt, this.target); } var server = servers[this.target]; var action = this.args.shift() || 'start'; var options = this.options({ cmd: process.argv[0], opts: [ ], args: [ ], node_env: undefined, harmony: false, background: true, fallback: function() { /* Prevent EADDRINUSE from breaking Grunt */ }, port: process.env.PORT || 3000, delay: 0, output: ".+", debug: false, breakOnFirstLine: false, logs: undefined, hardStop: false }); options.script = path.resolve(options.script); options.args.unshift(options.script); if (options.harmony) { options.args.unshift('--harmony'); } if (!grunt.file.exists(options.script)) { grunt.log.error('Could not find server script: ' + options.script); return false; } server[action](options); }); }; tasks/lib/000077500000000000000000000000001517651455400127665ustar00rootroot00000000000000tasks/lib/server.js000066400000000000000000000113021517651455400146270ustar00rootroot00000000000000/* * grunt-express-server * https://github.com/ericclemmons/grunt-express-server * * Copyright (c) 2013 Eric Clemmons * Licensed under the MIT license. */ 'use strict'; var spawn = require('child_process').spawn; var process = require('process'); module.exports = function(grunt, target) { if (!process._servers) { process._servers = {}; } var backup = null; var done = null; var server = process._servers[target]; // Store server between live reloads to close/restart express var finished = function() { if (done) { done(); done = null; } }; return { start: function start(options) { if (server) { this.stop(options); if (grunt.task.current.flags.stop) { finished(); return; } } backup = JSON.parse(JSON.stringify(process.env)); // Clone process.env // For some weird reason, on Windows the process.env stringify produces a "Path" // member instead of a "PATH" member, and grunt chokes when it can't find PATH. if (!backup.PATH) { if (backup.Path) { backup.PATH = backup.Path; delete backup.Path; } } grunt.log.writeln('Starting '.cyan + (options.background ? 'background' : 'foreground') + ' Express server'); done = grunt.task.current.async(); // Set PORT for new processes process.env.PORT = options.port; // Set NODE_ENV for new processes if (options.node_env) { process.env.NODE_ENV = options.node_env; } if (options.cmd === 'coffee') { grunt.log.writeln('You are using cmd: coffee'.red); grunt.log.writeln('coffee does not allow a restart of the server'.red); grunt.log.writeln('use opts: ["path/to/your/coffee"] instead'.red); } // Set debug mode for node-inspector // Based on https://github.com/joyent/node/blob/master/src/node.cc#L2903 var debugFlag = 'debug'; if (parseInt(process.versions.node.split('.')[0]) > 7) { debugFlag = 'inspect'; } if (options.debug === true) { options.opts.unshift('--' + debugFlag); } else if (!isNaN(parseInt(options.debug, 10))) { options.opts.unshift('--' + debugFlag + '=' + options.debug); } else if (options.breakOnFirstLine === true) { options.opts.unshift('--' + debugFlag + '-brk'); } else if (!isNaN(parseInt(options.breakOnFirstLine, 10))) { options.opts.unshift('--' + debugFlag + '-brk=' + options.breakOnFirstLine); } if ((options.debug || options.breakOnFirstLine) && options.cmd === 'coffee') { options.opts.unshift('--nodejs'); } if (options.background) { var errtype = process.stderr; if(options.logs && options.logs.err) { errtype = 'pipe'; } server = process._servers[target] = spawn( options.cmd, options.opts.concat(options.args), { env: process.env, stdio: ['ignore', 'pipe', errtype] } ); if (options.delay) { setTimeout(finished, options.delay); } if (options.output) { server.stdout.on('data', function(data) { var message = "" + data; var regex = new RegExp(options.output, "gi"); if (message.match(regex)) { finished(); } }); } var out = process.stdout; if(options.logs) { var fs = require('fs'), path = require('path'); if(options.logs.out) { out = fs.createWriteStream(path.resolve(options.logs.out), {flags: 'a'}); } if(options.logs.err && errtype === 'pipe') { server.stderr.pipe(fs.createWriteStream(path.resolve(options.logs.err), {flags: 'a'})); } } server.stdout.pipe(out); server.on('close',this.stop); } else { // Server is ran in current process server = process._servers[target] = require(options.script); } process.on('exit', this.stop); }, stop: function stop(options) { if (server && server.kill) { grunt.log.writeln('Stopping'.red + ' Express server'); server.removeAllListeners('close'); if (options.hardStop) { grunt.log.writeln('Using ' + 'SIGKILL'.red); server.kill('SIGKILL'); } else { server.kill('SIGTERM'); } process.removeListener('exit', finished); process.removeListener('exit', stop); server = process._servers[target] = null; } // Restore original process.env if (backup) { process.env = JSON.parse(JSON.stringify(backup)); } finished(); } }; };