.gitignore000066400000000000000000000002651517543712600130640ustar00rootroot00000000000000node_modules npm-debug.log tmp *.sublime-project *.sublime-workspace /build /dist /node_modules /*.log /package-lock.json /yarn.lock /*.iws .idea/workspace.xml .idea/tasks.xml .idea/000077500000000000000000000000001517543712600120515ustar00rootroot00000000000000.idea/grunt-express.iml000066400000000000000000000005201517543712600153770ustar00rootroot00000000000000 .idea/inspectionProfiles/000077500000000000000000000000001517543712600157305ustar00rootroot00000000000000.idea/inspectionProfiles/Project_Default.xml000066400000000000000000000003711517543712600215250ustar00rootroot00000000000000 .idea/misc.xml000066400000000000000000000015161517543712600135310ustar00rootroot00000000000000 true false true .idea/modules.xml000066400000000000000000000004261517543712600142450ustar00rootroot00000000000000 .idea/vcs.xml000066400000000000000000000002471517543712600133710ustar00rootroot00000000000000 .scrutinizer.yml000066400000000000000000000005471517543712600142610ustar00rootroot00000000000000checks: 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.yml000066400000000000000000000001321517543712600131760ustar00rootroot00000000000000language: node_js node_js: - "7" - "node" before_script: - npm install grunt-cli -g Gruntfile.js000066400000000000000000000004541517543712600133710ustar00rootroot00000000000000module.exports = (grunt) => { const builder = require(`corifeus-builder`); const loader = new builder.loader(grunt); loader.js({ replacer: { type: 'p3x', npmio: true, }, }); grunt.registerTask('default', builder.config.task.build.js); };README.md000066400000000000000000000167071517543712600123630ustar00rootroot00000000000000[//]: #@corifeus-header [![Build Status](https://travis-ci.org/patrikx3/grunt-p3x-express.svg?branch=master)](https://travis-ci.org/patrikx3/grunt-p3x-express) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/patrikx3/grunt-p3x-express/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/grunt-p3x-express/?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/patrikx3/grunt-p3x-express/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/grunt-p3x-express/?branch=master) [![NPM](https://nodei.co/npm/grunt-p3x-express.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/grunt-p3x-express/) --- # Grunt task for running an Express Server that works great with LiveReload + Watch/Regarde ## Issues / Support This is an open source project. Time is a precious thing, so I have rarely time to give support and fix issues for someone else. I fix a bug, when I have an error that I need. If you got an issue, error or bug, I hope someone will have time to do it for you, otherwise, you are on your own. Though, if I know the solution, I will tell you. Besides, core errors will be fixed by me. ***If you want to extend, fix bugs or add in new features, I promptly merge pull requests or you can become a ```patrikx3``` member.*** Besides, when I can support, please note, I cannot support old versions, only the current/latest version. ### Node Version Requirement ``` >=7.8.0 ``` ### Built on Node ``` v8.1.0 ``` The ```async``` and ```await``` keywords are required. Install NodeJs: https://nodejs.org/en/download/package-manager/ ### Updating Since, I work full time, I can work only on weekends. Github updates are released only Sundays. Minor errors can be released any time, but reflects will be shown only in NPM. # Description [//]: #@corifeus-header:end Simple grunt task for running an Express server that works great with LiveReload + Watch/Regarde ## Getting Started This plugin requires Grunt `>=1.0.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-p3x-express --save-dev ``` Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: ```js grunt.loadNpmTasks('grunt-p3x-express'); ``` ## 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"] } } ``` ## Release History ### Old version https://github.com/ericclemmons/grunt-express-server [//]: #@corifeus-footer --- [**GRUNT-P3X-EXPRESS**](https://pages.corifeus.tk/grunt-p3x-express) Build v1.0.17-15 [Corifeus](http://www.corifeus.tk) by [Patrik Laszlo](http://patrikx3.tk) [//]: #@corifeus-footer:endgrunt-express.iml000066400000000000000000000005171517543712600144250ustar00rootroot00000000000000 grunt-p3x-express.iml000066400000000000000000000004751517543712600151400ustar00rootroot00000000000000 package.json000066400000000000000000000025651517543712600133670ustar00rootroot00000000000000{ "name": "grunt-p3x-express", "corifeus": { "publish": true, "type": "p3x", "code": "Next" }, "description": "Grunt task for running an Express Server that works great with LiveReload + Watch/Regarde", "version": "1.0.17-15", "homepage": "https://pages.corifeus.tk/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-express.git" }, "bugs": { "url": "https://github.com/patrikx3/grunt-express/issues" }, "license": "MIT", "main": "Gruntfile.js", "engines": { "node": ">=7.8.0" }, "scripts": { "test": "./node_modules/.bin/grunt" }, "devDependencies": { "corifeus-builder": "^1.7.660-16", "express": "^4.15.3", "grunt": "^1.0.1", "grunt-cli": "^1.2.0", "grunt-contrib-clean": "^1.1.0", "grunt-contrib-jshint": "^1.1.0", "grunt-contrib-nodeunit": "^1.0.0", "grunt-contrib-watch": "^1.0.0" }, "peerDependencies": { "grunt": ">=0.4.0" }, "keywords": [ "gruntplugin", "express", "server" ] }src/000077500000000000000000000000001517543712600116605ustar00rootroot00000000000000src/express.js000066400000000000000000000026621517543712600137150ustar00rootroot00000000000000/* * 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); }); }; src/index.js000066400000000000000000000001601517543712600133220ustar00rootroot00000000000000module.exports = { express: require('./express'), } module.exports.express.server = require('./lib/server');src/lib/000077500000000000000000000000001517543712600124265ustar00rootroot00000000000000src/lib/server.js000066400000000000000000000113021517543712600142670ustar00rootroot00000000000000/* * 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(); } }; }; tasks/000077500000000000000000000000001517543712600122165ustar00rootroot00000000000000tasks/express.js000066400000000000000000000000531517543712600142430ustar00rootroot00000000000000module.exports = require('../src/express');