I'm working on a simple node app and all is working well on local. But when deploying on Heroku, I had an error.
The tutorial on Heroku tells to add on package.json
"scripts": {
"start": "node server.js"
},
But, what can I put in server.js ? I found lots of examples but nothing clear or relevant for me. I'm a bit confused about the need of this.
The setting of the app is quite common : npm install/bower install and then "grunt serve" to launch the app. The app is a simple HTML/Angular web app calling endpoints on an API.
NB : I'm not using Express.
Here is the gruntfile.js :
'use strict';
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths for the application
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: '../project/WebApp'
};
//Environment vars
var envConfig = {
dev: {
baseUrl: 'http://localhost:3000',
loginUrl: 'http://demo.lvh.me:9000'
},
prod: {
baseUrl: '',
loginUrl: ''
}
};
// Require ModRewrite object before initConfig
var modRewrite = require('connect-modrewrite');
// Define the configuration for all the tasks
grunt.initConfig({
appConf: appConfig,
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= appConf.dist %>/{,*/}*',
'!<%= appConf.dist %>/.git*'
]
}],
options: {
force: true //since dist directory is outside, we must use force flag.
}
},
server: '.tmp'
},
//server settings
ngconstant: {
// Options for all targets
options: {
space: ' ',
wrap: '\'use strict\';\n\n {%= __ngModule %}',
name: 'config'
},
// Environment targets
development: {
options: {
dest: 'app/config.js'
},
constants: envConfig.dev
},
production: {
options: {
dest: '<%= appConf.app %>/config.js'
},
constants: envConfig.prod
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= appConf.app %>/index.html'],
ignorePath: /\.\.\//,
'options': {
'overrides': {
'semantic-ui': {
'main': ['dist/semantic.css', 'dist/semantic.js']
}
}
}
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= appConf.app %>',
dest: '<%= appConf.dist %>',
src: [
'*.{ico,png,txt}',
'{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= appConf.dist %>/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'bower_components/font-awesome',
src: 'fonts/*',
dest: '<%= appConf.dist %>'
}]
},
styles: {
files: [
{
expand: true,
cwd: '<%= appConf.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
]
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'svgmin'
]
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'demo.lvh.me',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
modRewrite(['^[^\\.]*$ /index.html [L]']),
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
test: {
options: {
port: 9001,
middleware: function (connect) {
return [
rewriteRulesSnippet,
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
dist: {
options: {
open: true,
base: '<%= appConf.dist %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= appConf.app %>/{,*/}*.js'
]
}
},
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= appConf.app %>/{,**/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
css: {
files: ['<%= appConf.app %>/styles/{,**/}*.scss'],
tasks: ['sass'],
options: {
livereload: true,
},
},
styles: {
files: [
'<%= appConf.app %>/styles/{,**/}*.css',
'<%= appConf.app %>/../templating/css/style.css'
],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= appConf.app %>/{,**/}*.html',
'.tmp/styles/{,**/}*.css',
'<%= appConf.app %>/images/{,**/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
sass: {
dev: {
options: {
style: 'expanded'
},
files: [
{
expand: true,
cwd: '<%= appConf.app %>/styles',
src: ['*.scss'],
ext: '.css',
dest: '<%= appConf.app %>/styles'
}
]
}
}
});
grunt.loadNpmTasks('grunt-sass');
// Build the development application
grunt.registerTask('serve', 'Compile then start a connect web server', function () {
grunt.task.run([
'clean:server',
'ngconstant:development',
'wiredep',
'sass',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
};
The tutorial assumes that server.js contains your actual server.
If your server is started by grunt serve, just change the start script to run that instead.
this seems quite more logical to me :) So I tested it and deployement was well but the app crashes with this error :
Starting process with command npm start
2016-03-03T17:14:35.928347+00:00 app[web.1]:
2016-03-03T17:14:35.928397+00:00 app[web.1]: > # start /app
2016-03-03T17:14:35.928412+00:00 app[web.1]: > grunt serve
2016-03-03T17:14:35.928413+00:00 app[web.1]:
2016-03-03T17:14:35.951390+00:00 app[web.1]: sh: 1: grunt: not found
2016-03-03T17:14:35.963949+00:00 app[web.1]:
2016-03-03T17:14:35.978885+00:00 app[web.1]: npm ERR! Linux 3.13.0-77-generic
2016-03-03T17:14:35.979392+00:00 app[web.1]: npm ERR! argv "/app/.heroku/node/bin/node" "/app/.heroku/node/bin/npm" "start"
2016-03-03T17:14:35.979644+00:00 app[web.1]: npm ERR! node v4.2.2
2016-03-03T17:14:35.984767+00:00 app[web.1]: npm ERR! npm v2.14.7
2016-03-03T17:14:35.985031+00:00 app[web.1]: npm ERR! file sh
2016-03-03T17:14:35.985243+00:00 app[web.1]: npm ERR! code ELIFECYCLE
2016-03-03T17:14:35.985481+00:00 app[web.1]: npm ERR! errno ENOENT
2016-03-03T17:14:35.985718+00:00 app[web.1]: npm ERR! syscall spawn
2016-03-03T17:14:35.985939+00:00 app[web.1]: npm ERR! # start: grunt serve
2016-03-03T17:14:35.986118+00:00 app[web.1]: npm ERR! spawn ENOENT
2016-03-03T17:14:35.986312+00:00 app[web.1]: npm ERR!
2016-03-03T17:14:35.986492+00:00 app[web.1]: npm ERR! Failed at the # start script 'grunt serve'.
Related
I have a basic node app with gruntfile and I had some pains to make the deploy. So I did a new grunt task, did some changes.
The deploy then is fine.
But now when I go to my app. I have a blank page.
It doesn't load the appConfig.app dir.
I probably miss something big I couldn't figure out. I thought grunt connect would do the wire but it seems server.js is waiting something.
NB : I think I don't need Express here.
Below are different files :
gruntfile.js
server.js
package.js
Gruntfile.js
'use strict';
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
var modRewrite = require('connect-modrewrite');
// Configurable paths for the application
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist'
};
//Environment vars
var envConfig = {
dev: {
//baseUrl: 'http://localhost:3000',
loginUrl: 'http://demo.lvh.me:9000',
uploadUrl: 'anuploadurl/upload'
},
prod: {
baseUrl: 'http://aprodurl',
loginUrl: 'an herokuapp url'
}
};
// Define the configuration for all the tasks
grunt.initConfig({
appConf: appConfig,
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= appConf.dist %>/{,*/}*',
'!<%= appConf.dist %>/.git*'
]
}],
options: {
force: true //since dist directory is outside, we must use force flag.
}
},
server: '.tmp'
},
//server settings
ngconstant: {
// Options for all targets
options: {
space: ' ',
wrap: '\'use strict\';\n\n {%= __ngModule %}',
name: 'config'
},
// Environment targets
development: {
options: {
dest: 'app/config.js'
},
constants: envConfig.dev
},
production: {
options: {
dest: '<%= appConf.app %>/config.js'
},
constants: envConfig.prod
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= appConf.app %>/index.html'],
ignorePath: /\.\.\//,
'options': {
'overrides': {
'semantic-ui': {
'main': ['dist/semantic.css', 'dist/semantic.js']
}
}
}
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= appConf.app %>/*',
dest: '<%= appConf.dist %>',
src: [
'*.{ico,png,txt}',
'{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '<%= appConf.app %>/images',
dest: '<%= appConf.dist %>/images',
src: ['generated/*']
}, { // not in use
expand: true,
cwd: 'bower_components/font-awesome',
src: 'fonts/*',
dest: '<%= appConf.dist %>'
}]
},
styles: {
files: [
{
expand: true,
cwd: '<%= appConf.app %>/*',
dest: '<%= appConf.dist %>/styles',
src: '{,*/}*.css'
}
]
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'svgmin'
]
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '<%= appConf.app %>/*',
src: '{,*/}*.css',
dest: '<%= appConf.dist %>/styles/'
}]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
modRewrite(['^[^\\.]*$ /index.html [L]']),
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
test: {
options: {
port: 9001,
middleware: function (connect) {
return [
rewriteRulesSnippet,
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
dist: {
options: {
port:process.env.PORT,
open: true,
base: '<%= appConf.app %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'server.js',
'<%= appConf.app %>/{,*/}*.js'
]
}
},
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= appConf.app %>/{,**/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
css: {
files: ['<%= appConf.app %>/styles/{,**/}*.scss'],
tasks: ['sass'],
options: {
livereload: true,
},
},
styles: {
files: [
'<%= appConf.app %>/styles/{,**/}*.css',
'<%= appConf.app %>/../templating/css/style.css'
],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= appConf.app %>/{,**/}*.html',
'.tmp/styles/{,**/}*.css',
'<%= appConf.app %>/images/{,**/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
sass: {
dev: {
options: {
style: 'expanded'
},
files: [
{
expand: true,
cwd: '<%= appConf.app %>/styles',
src: ['*.scss'],
ext: '.css',
dest: '<%= appConf.dist %>/styles'
}
]
}
}
});
grunt.loadNpmTasks('grunt-sass');
// Build the development application
grunt.registerTask('serve', 'Compile then start a connect web server', function () {
grunt.task.run([
'clean:server',
'ngconstant:development',
'wiredep',
'sass',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
// Build the production application
grunt.registerTask('build', 'Compile app on production settings', function () {
grunt.task.run([
'clean:server',
'ngconstant:production',
'wiredep',
'sass',
'concurrent:server',
'autoprefixer',
'connect:dist'
]);
});
};
server.js
var http = require('http');
var port = process.env.PORT || 80;
http.createServer(function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin' : '*'
});
//res.end('app/index.html');
}).listen(port);
console.log('Server running at port '+port);
package.json
{
"private": true,
"engines": {
"node": "4.2.2"
},
"scripts": {
"postinstall": "bower install && grunt build",
"start": "node server.js"
},
"dependencies": { all the dependancies .... }
}
It was a huge and harsh debugging but I finally found out.
It was coming from multiple mistakes and bugs I had :
the node server.js is useless
I invstigated on the grunt connect method and created a production setup
I splitted the grunt serve into a grunt build task and a webconnect task
Then updated package.json file
Very important for heroku : in Gruntfile.js on the connect object :
dist: {
options: {
port:process.env.PORT, #<=== need to have a dynamic port env for Heroku deployment
open: true,
base: '<%= appConf.dist %>'
}
}
here are the grunt tasks added :
// Build the production application
grunt.registerTask('build', 'Compile on dist folder', function () {
grunt.task.run([
'clean:dist',
'ngconstant:production',
'wiredep',
'sass',
'concurrent:dist',
'autoprefixer:dist'
]);
});
// Build the production application
grunt.registerTask('webconnect', 'connect web server', function () {
grunt.task.run([
'connect:dist'
]);
});
then on package.json :
"scripts": {
"postinstall": "bower install && grunt build",
"start": "grunt webconnect"
}
I'm having issues with my grunt serve task. It seems to hang when it gets to the express:dev task;
Running "express:dev" (express) task
Starting background Express server
Debugger listening on port 5858
This an existing project where grunt serve used to work fine. This issue started yesterday when my Mac ran out of power mid process; in my head its either that or I have inadvertently changed something and broken it just before the mac went down and the power thing is just coincidence.
Has anyone got any ideas?
'use strict';
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
var deploySettings = grunt.file.readJSON('config.json'),
deploy = deploySettings.production;
var useminSettings = []
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist' //require('./bower.json').distPath ||
};
grunt.initConfig({
mainApp: appConfig,
express: {
options: {
port: process.env.PORT || 9000
},
dev: {
options: {
script: 'app.js',
debug: true,
node_env: 'development',
livereload:true,
serverreload: true
}
},
prod: {
options: {
script: 'dist/app.js',
node_env: 'production'
}
}
},
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js : {
files: ['<%= mainApp.app %>/js/**/*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: true //'<%= connect.options.livereload %>'
}
},
gruntfile: {
files: ['Gruntfile.js']
},
less: {
files: ['<%= mainApp.app %>/css/**/*.less'],
tasks: ['less:development']
},
livereload: {
options: {
livereload : true //'<%= connect.options.livereload %>'
},
files: [
'<%= mainApp.app %>/**/*.html',
'<%= mainApp.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
},
express: {
files: [
'server/**/*.{js,json}'
],
tasks: ['less:development','express:dev', 'wait'],
options: {
livereload: true,
nospawn: true //Without this option specified express won't be reloaded
}
}
},
// The actual grunt server settings
/*
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
}
},
*/
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= mainApp.app %>/index.html']
//ignorePath: /\.\.\//
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= mainApp.app %>/js/{,*/}*.js'
]
}
},
//compiles our less down
less : {
development:{
options:{
path: '<%= mainApp.app %>/css/main.less',
rootPath: '/css/',
relativeUrls: false
},
files: {
'<%= mainApp.app %>/css/main.css' : '<%= mainApp.app %>/css/main.less'
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src : [
'.tmp',
'<%= mainApp.dist %>/{,*/}*',
'<%= mainApp.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= mainApp.app %>/index.html',
options: {
dest: '<%= mainApp.dist %>/public',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '<%= mainApp.dist %>/public/styles/'
}]
}
},
// ng-annotate tries to make the code safe for minification automatically
// by using the Angular long form for dependency injection.
ngAnnotate: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: ['*.js'],
dest: '.tmp/concat/scripts'
}]
}
},
//copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= mainApp.app %>',
dest: '<%= mainApp.dist %>/public',
src:[
'*.html',
'views/partials/{,*/}*.html',
'static/img/{,*/}*.{png,jpg,jpeg,gif,ico,svg}',
'css/fonts/{,*/}*.{ttf,woff,eot,otf}'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= mainApp.dist %>/public/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'public/bower_components/bootstrap/dist',
src: 'fonts/{,*/}*.{ttf,woff,eot,otf}',
dest: '<%= mainApp.dist %>/public'
}, {
expand: true,
dest: '<%= mainApp.dist %>',
src: [
'app.js',
'package.json',
'server/**/*'
]
}]
},
debug: {
files: [{
expand: true,
dot: true,
cwd: '<%= mainApp.app %>',
dest: '<%= mainApp.dist %>',
src:[
'*.html',
'views/partials/{,*/}*.html',
'js/{,*/}*.js',
'css/{,*/}*.css',
'static/img/{,*/}*.{png,jpg,jpeg,gif}',
'css/fonts/{,*/}*.{ttf,woff,eot,otf}'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= mainApp.dist %>/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'public/bower_components/bootstrap/dist',
src: 'fonts/{,*/}*.{ttf,woff,eot,otf}',
dest: '<%= mainApp.dist %>'
}]
},
styles : {
expand: true,
cwd: '<%= mainApp.app %>/styles',
dest: '.tmp/styles',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
dist:[
'copy:styles'
]
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= mainApp.dist %>/public/*.html']
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= mainApp.dist %>/public/scripts/{,*/}*.js',
'<%= mainApp.dist %>/public/styles/{,*/}*.css'
// '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
// '<%= yeoman.dist %>/styles/fonts/*'
]
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= mainApp.dist %>/public/{,*/}*.html'],
css: ['<%= mainApp.dist %>/public/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= mainApp.dist %>/public']
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= mainApp.dist %>',
src: ['*.html', 'views/partials{,*/}*.html'],
dest: '<%= mainApp.dist %>/public'
}]
}
},
imagemin : {
dynamic: { // Another target
files: [{
expand: true, // Enable dynamic expansion
cwd: '<%= mainApp.dist %>/public/static', // Src matches are relative to this path
src: ['**/*.{png,jpg,gif}'], // Actual patterns to match
dest: '<%= mainApp.dist %>/public/static' // Destination path prefix
}]
}
},
});
// Used for delaying livereload until after server has restarted
grunt.registerTask('wait', function () {
grunt.log.ok('Waiting for server reload...');
var done = this.async();
setTimeout(function () {
grunt.log.writeln('Done waiting!');
done();
}, 1500);
});
grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
this.async();
});
grunt.registerTask('serve', 'Compile then start a connect web server', function(){
grunt.task.run([
'clean:server',
'less:development',
'wiredep',
// 'concurrent:server',
//'connect:livereload',
'express:dev',
//'express-keepalive',
'wait',
'watch'
]);
});
grunt.registerTask('build', function(){
grunt.task.run([
'clean:dist',
'less:development',
'wiredep',
'useminPrepare',
'concurrent:dist',
'copy:styles',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin',
'express:dev'
]);
});
grunt.registerTask('debug', [
'clean:dist',
'less:development',
'wiredep',
'copy:debug'
]);
grunt.registerTask('default', [
'serve'
]);
};
I found the solution to this by reverting to a previous git and manually adding changed.
Somehow it was an issue with node-scheduler. I was scheduling a task using a recurrence rule for dayOfWeek = 7. This was producing the error in grunt serve, nothing to do with the grunt file as it happens.
I changed this to dayOfWeek = 0 and it was fine.
The thing i'm trying to do is server call which will perform "build" task of grunt (grunt is taken from yeoman angular generator)
i'm using restify framework:
var restify = require('restify');
var server = restify.createServer();
server.get('/run',function(req, res){
console.log('running...')
var grunt = require('grunt');
grunt.tasks(['build']);
res.send(200);
});
server.listen(8234, function() {
// sendMail();
console.log('%s listening at %s', server.name, server.url);
});
my "server.js" file located in the same folder the grunt is.
after i sending request to "/run" api the grunt begans to run, but it fails after it tries to start the "concurrent" task
Running "concurrent:dist" (concurrent) task
Warning:
Error: listen EADDRINUSE
at errnoException (net.js:904:11)
at Server._listen2 (net.js:1042:14)
at listen (net.js:1064:10)
at Server.listen (net.js:1138:5)
at Server.listen (C:\myProjects\experimental\node_modules\restify\lib\se
rver.js:312:32)
at Object.<anonymous> (C:\myProjects\experimental\server.js:20:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12) Use --force to continue.
Aborted due to warnings.
I guess the concurrent not playing well with resitfy instanse. but is there a way to solve this?
here is standart grunt file supplied by yeoman angular generator i'm using:
// Generated on 2014-09-08 using generator-angular 0.9.8
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths for the application
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
yeoman: appConfig,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
test: {
options: {
port: 9001,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
dist: {
options: {
open: true,
base: '<%= yeoman.dist %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/spec/{,*/}*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/{,*/}*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
}
},
// The following *-min tasks will produce minified files in the dist folder
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'views/{,*/}*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// ng-annotate tries to make the code safe for minification automatically
// by using the Angular long form for dependency injection.
ngAnnotate: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: ['*.js', '!oldieshim.js'],
dest: '.tmp/concat/scripts'
}]
}
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'bower_components/bootstrap/dist',
src: 'fonts/*',
dest: '<%= yeoman.dist %>'
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
},
// Test settings
karma: {
unit: {
configFile: 'test/karma.conf.js',
singleRun: true
}
}
});
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve:' + target]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
Please help
Thanks forwards
Error: listen EADDRINUSE
means you have already an application listening on port 8234
Running grunt serve in a docker container causes node to crash (for lack of a better term).
(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.
util.js:35
var str = String(f).replace(formatRegExp, function(x) {
^
RangeError: Maximum call stack size exceeded
When I run the app * locally * it works as expected. This * only * happens when running it in the container. My guess is that it's the live reload or one of the other port mappings causing the issue but I don't know how to debug it. I expose the ports used by node in the dockerfile:
EXPOSE 9000 9001 35729
...grunt task...
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/{,*/}*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
wiredep: {
options: {
cwd: '<%= yeoman.app %>'
},
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
}
},
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
},
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
....
I've found related issues on stackoverflow but the solutions don't seem to solve my issue.
Thanks!
I encountered this error when my Gruntfile.js has the following code:
grunt.registerTask('svgmin', ['svgmin']);
I solve the problem by renaming the code to:
grunt.registerTask('s', ['svgmin']);
The problem of the code is that it created a new task called 'svgmin' to run 'svgmin' task which cause the infinite looping.
Hope it helps.
http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower
After following this interesting guide about Angular, Yeoman, Bower and Grunt I was able tot bootstrap an Angular application.
Everything works fine except the testing with Karma. When I run:
grunt test
I get the following error:
Warning: Task "karma" not found. Used --force, continuing.
Done, but with warnings
I checked if I have installed Karma, but that is installed. For Grunt it appears you need to install grunt-karma. So I tried that throughout the following command:
npm install grunt-karma --save-dev
This gives me errrors like:
errno: 53,
code: 'ENOTEMPTY',
path: 'C:\\tmp\\phantomjs\\phantom-1.9.2-windows-.zip-extract-' ..
I am on Windows and executing commands from the powershell.
Hope someone can help.
Edit karma.conf.js and gruntfile
// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-cookies/angular-cookies.js',
'app/bower_components/angular-sanitize/angular-sanitize.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['Chrome'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
Gruntfile
// Generated on 2013-11-02 using generator-angular 0.5.1
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-karma');
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
grunt.initConfig({
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist'
},
watch: {
coffee: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
tasks: ['coffee:dist']
},
coffeeTest: {
files: ['test/spec/{,*/}*.coffee'],
tasks: ['coffee:test']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['copy:styles', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= yeoman.app %>'
]
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
coffee: {
options: {
sourceMap: true,
sourceRoot: ''
},
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/scripts',
src: '{,*/}*.coffee',
dest: '.tmp/scripts',
ext: '.js'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.coffee',
dest: '.tmp/spec',
ext: '.js'
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false
},
dist: {},
server: {
options: {
debugInfo: true
}
}
},
// not used since Uglify task does concat,
// but still available if needed
/*concat: {
dist: {}
},*/
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
dirs: ['<%= yeoman.dist %>']
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
cssmin: {
// By default, your `index.html` <!-- Usemin Block --> will take care of
// minification. This option is pre-configured if you do not wish to use
// Usemin blocks.
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
},
htmlmin: {
dist: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/yeoman/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['*.html', 'views/*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// Put files not handled in other tasks here
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'bower_components/**/*',
'images/{,*/}*.{gif,webp}',
'styles/fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: [
'generated/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
concurrent: {
server: [
'coffee:dist',
'compass:server',
'copy:styles'
],
test: [
'coffee',
'compass',
'copy:styles'
],
dist: [
'coffee',
'compass:dist',
'copy:styles',
'imagemin',
'svgmin',
'htmlmin'
]
},
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
ngmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.dist %>/scripts',
src: '*.js',
dest: '<%= yeoman.dist %>/scripts'
}]
}
},
uglify: {
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'<%= yeoman.dist %>/scripts/scripts.js'
]
}
}
}
});
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'copy:dist',
'cdnify',
'ngmin',
'cssmin',
'uglify',
'rev',
'usemin'
]);
grunt.registerTask('default', [
'jshint',
'test',
'build'
]);
};
Download phantomjs package from https://github.com/Obvious/phantomjs
Unpack and copy it into node_modules of your project.
Run below command gain:
npm install grunt-karma --save-dev
Hope this help.
I had to turn off antivirus (Eset).
The only solution for me that work is:
sudo npm install grunt-karma karma karma-phantomjs-launcher karma-jasmine jasmine-core phantomjs-prebuilt --save-dev
grunt test
or:
grunt serve,
it's work !