Grunt-contrib-watch with grunt-contrib-connect - node.js

Unfortunately, grunt-contrib-watch and grunt-contrib-connect don't seem to be playing nice.
On the grunt-contrib-connect readme it says:
Note that this server only runs as long as grunt is running. Once grunt's tasks have completed, the web server stops. This behavior can be changed with the keepalive option, and can be enabled ad-hoc by running the task like grunt connect::keepalive.
Fine. But what if I want to run my watch task in tandem with the connect server? Like so:
connect: {
server: {
options: {
port: 8000,
hostname: 'localhost',
keepalive: true
}
}
},
watch: {
options: {
livereload: true
},
files: ['**'],
tasks: ['connect'],
}
Here, the connect task runs when a file is changed. If I set the connect's keepalive option to true, then grunt-contrib-watch stops watching because it technically hasn't finished it's task. If I falsify the keepalive option, then the connect server dies after it has finished the tasks.
Yes, I could run the commands...
$ grunt connect
$ grunt watch
...in separate shells, but is there no way of running them with one command?

Livereload in grunt-contrib-watch informs for changes in files at a port here below you can see it is at 35729.
On the other hand the livereload in grunt-contrib-connect listens for changes at the port 35729.
So we should should configure them as -
connect: {
server: {
options: {
port: 8000,
hostname: 'localhost',
livereload: 35729
}
}
},
watch: {
options: {
livereload: 35729
},
files: ['**'],
tasks: []
}
You need not provide "connect" as a task here. As the work of reloading is done by livereload here.
Now to make these two work with a single command we will register them as -
grunt.registerTask("server", ["connect", "watch"]);
Now the connect is run and then watch is run. Now normally registerTasks works by finishing the first task then the second task and so on. But due to the behaviour of connect as stated by you -
Note that this server only runs as long as grunt is running
Connect is run only once. But watch will keep on running looking for changes (keeping grunt running) and thus keeping the connect server up.
Now when you try
grunt server
things will work like a charm.

I use grunt-nodemon, which encapsulates watch and a nodejs launcher in a single task:
nodemon: {
dev: {
script: 'app.js',
options: {
ignore: [
'node_modules/**',
'public/**'
],
ext: 'js'
}
}
}
Then executed with:
$ grunt nodemon:dev
Now, nodemon only launches the app.js script with nodejs, so you will need a small app.js to load a static static express server:
var express = require('express');
var server = express(); // better instead
server.configure(function(){
server.use(express.static(__dirname + '/public'));
});
server.listen(3000);

Related

Can't change the base folder for lite-server in Angular 2 application

I am going through the 5 minute quickstart of Angular 2. However, my application resides in src/ folder instead of at the root of my repository, and when I run npm start the application is trying to find an index.html file at the root. I read up on lite-server and documentation shows that it uses BrowserSync and I can reconfigure BrowserSync with a bs-config.json in my repository. I did that and this is what my config looks like:
{
"port": 8123,
"server": { "baseDir": "./src" }
}
According to the log it's using the specified config:
[1] > todo-app-angular2#1.0.0 lite E:\GitHub\todo-app-angular2
[1] > lite-server "./bs-config.json"
I also tried an override through bs-config.js
module.exports = {
port: 8123,
server: {
baseDir: "./src"
}
};
However the Angular application is still opened on port 3000 and it's disregarding the baseDir defined in the config. What am I doing wrong?
You should use a file called bs-config.js (instead of a bs-config.json one) since lite-server tries to load a module using the require function. The configuration should be a valid Node module:
module.exports = {
"port": 8123,
"server": { "baseDir": "./src" }
};
See this line in the source code: https://github.com/johnpapa/lite-server/blob/master/lib/lite-server.js#L20.
This file by default is loaded from the user's project folder.
Edit
After digging a bit more, the first part of my answer relies on the code from github but not the one actually installed using npm install (version 1.3.4)
There are two options in this case:
port
baseDir
Using this command will fix your problem:
$ lite-server --baseDir ./src --port 3333
Hope it helps you,
Thierry
The answer from Thierry Templier is not quite correct (anymore), you can use either the bs-config.json or bs-config.js configuration to adjust your browser-sync configuration. This is what I came up initially for the angular2 quick start example with JIT(Just-In-Time) and AOT(Ahead-Of-Time) compilation support (bs-config.json)
{
"port": 8000,
"server": ["app", "."]
}
to host the project from multiple directories.
However, I did not like this solution because by overwriting the server section in the json file, the default middleware configuration was overwritten at the same time.
Therefore I ended with the following approach, I took the default lite-server's config-defaults.js files and modified it instead (bs-config.js):
'use strict';
var fallback = require('connect-history-api-fallback');
var log = require('connect-logger');
/*
| For up-to-date information about the options:
| http://www.browsersync.io/docs/options/
*/
module.exports = {
port: 8000,
injectChanges: false, // workaround for Angular 2 styleUrls loading
filters: ['./**/*.{html,htm,css,js}'],
watchOptions: {
ignored: 'node_modules'
},
server: ['./', 'app'],
middleware: [
log({ format: '%date %status %method %url' }),
fallback({
index: '/index.html',
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] // systemjs workaround
})
]
};

Grunt Connect server ignoring port and not opening browser

Trying to get grunt-connect setup.
What I want is to start a server (either localhost or an IP), the browser to open at that url and ideally this to livereload when a CSS, HTML or JS file is changed. But we can come to that later.
This is what I have in the gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
includesPath: "includes",
connect: {
test: {
port: 9001,
hostname: '0.0.0.0',
base: '',
open: true
}
}
});
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.registerTask('default', ['connect:test']);
grunt.registerTask('server', ['connect:test']);
};
this is the dependency in the package.json
"grunt-contrib-connect": "~0.8.0"
When I run either grunt or grunt server the Terminal window says
Started connect web server on http: //0.0.0.0:8000
It doesn't open a browser. If I go to that address in the browser, there is no page there.
What do you reckon?
So it seems I was missing the options object! What a stupid, Friday afternoon mistake that was. Frustrating that it didn't error though, I assume it has default settings it uses, which would explain why it used it's on port?
This code did the trick, thanks for your help Dave McNally
connect: {
server: {
options: {
keepalive: true,
port: 4000,
base: '.',
open: true
}
}
}
You’ll want a value in the base parameter, the default '.' will do if source is in same root directory and as mentioned, you don't need to specify hostname when using the default. Also, check ports, as you're specifying one in the task but then opening another in the given address?

watch doesn't refresh the page on file change (express site)

It would be nice to have the browser automatically reload the page when I change a project file. I have this node-express site with the server being defined in 'server.js'
However, I've tried different grunt configurations, but none of them caused the browser to reload on a file change although the 'watch' task prints a message that the file changed!
Here is the relevant grunt configuration:
watch: {
all: {
files: 'views/index.ejs', // for now only watch this file!
options: {
livereload: true
}
}
},
express: {
options: {
background: true,
error: function(err, result, code) {},
fallback: function() {},
port: 3000
delay: 0,
output: ".+",
debug: false
},
dev: {
options: {
script: './server.js',
node_env: 'development',
livereload: true
}
}
}
....
grunt.registerTask('server', [
'express:dev',
'open',
'watch'
])
};
And to run the task I do
$> grunt server
Can someone explain what is wrong with this configuration ?
thnx
You need to install the livereload browser plugin from http://livereload.com/
I am trying to use grunt livereload to reload css changes on my node.js pages. I am getting closer to solve my problem which is similar to yours. So from what i know so far and please correct me if i'm wrong you dont need to install "livereload browser plugin" right? I used grunt alone without node.js and i could just use livereload without installing "livereload browser plugin" i just had to add a line in my .html (the problem i run into with node is how to reload .ejs and i found this page/question on the way solving it) : so i dont know if installing the livereload thing is another way to do the script part or if this is the case like i mentioned in my problem if i want to live reload .ejs i have to install the plugin.

Gruntjs - Running Multiple Blocking Tasks in a Specific Order ( Mongo & Node.js )

I've recently taken a love to Gruntjs and have been happily throwing in at every opportunity to make my development life that much easier. I currently have it compiling my SASS files, running watches, and using nodemon to keep my node server updating as I work on the app.
So here's where I've spent the morning driving myself nuts. I would like to start MongoDB prior to the Node application running. In the Node app's setup, I check for any values in the databases, and if it's empty, push a test file full of information into the tables.
I've currently tried using grunt-concurrent and grunt-shell-spawn to run the necessary mongo and node commands.
grunt.initConfig({
shell: {
mongo: {
command: 'mongo'
},
node: {
command: 'node app.js'
}
},
concurrent: {
dev: {
tasks: ['shell:mongo','shell:node'],
options: { logConcurrentOutput: true }
}
}
});
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-shell-spawn');
Is there a way to ensure that the mongo command reaches it's "blocking" state prior to running the node task? I'm guessing that this could be done by running the node task async on a setTimeout function, but I don't want to have to constantly be waiting to see changes in the development process take effect. Currently I have been keeping a separate shell tab open for the database and would really like to integrate this into Grunt to keep everything in one place.
I'm not sure about it's importance on a broad scale, but anyone that's utilizing Node.js and MongoDB would really find this useful.
Thanks
Trying using grunt-nodemon with shell:mongo while specifying "options: { async: true }"
concurrent: {
tasks: ['shell', 'nodemon'],
options: {
logConcurrentOutput: true
}
},
shell: {
mongo: {
command: 'mongod',
options: {
async: true
}
}
},
nodemon: {
dev: {
script: "server.js",
}
}
This worked for me.
You can interval check the mongodb's service port to see if it is accessible?\

What's the purpose of gruntjs server task?

I'm learning how to propel use gruntjs. I found the server task but I can't get the point.
Can i use the server task mapping concatenated/minified files to test my application (uses backbone.js) without moving or placing source files in web server root? Without apache for example.
If no, what's the supposed use of server task?
The server task is used to start a static server with the base path set as the web root.
Example: Serve ./web-root as http://localhost:8080/:
grunt.initConfig({
server: {
port: 8080,
base: './web-root'
}
});
It will function similar to an Apache server, serving up static files based on their path, but uses the http module via connect to set it up (source).
If you need it to serve more than just static files, then you'll want to consider defining a custom server task:
grunt.registerTask('server', 'Start a custom web server.', function() {
grunt.log.writeln('Starting web server on port 1234.');
require('./server.js').listen(1234);
});
And custom server instance:
// server.js
var http = require('http');
module.exports = http.createServer(function (req, res) {
// ...
});
Can I use the server task mapping concatenated/minified files to test my application [...]
Concatenation and minification have their own dedicated tasks -- concat and min -- but could be used along with a server task to accomplish all 3.
Edit
If you want it to persist the server for a while (as well as grunt), you could define the task as asynchronous (with the server's 'close' event):
grunt.registerTask('server', 'Start a custom web server.', function() {
var done = this.async();
grunt.log.writeln('Starting web server on port 1234.');
require('./server.js').listen(1234).on('close', done);
});
The server task is now the connect task and it's included in the grunt-contrib-connect package.
The connect task starts a connect web server.
Install this plugin with this command:
npm install grunt-contrib-connect --save-dev
Note: --save-dev includes the package in your devDependencies, see https://npmjs.org/doc/install.html
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-contrib-connect');
Run this task with the grunt connect command.
Note that this server only runs as long as grunt is running. Once grunt's tasks have completed, the web server stops. This behavior can be changed with the keepalive option, and can be enabled ad-hoc by running the task like grunt connect:targetname:keepalive. targetname is equal to "server" in the code sample below.
In this example, grunt connect (or more verbosely, grunt connect:server) will start a static web server at http://localhost:9001/, with its base path set to the www-root directory relative to the Gruntfile, and any tasks run afterwards will be able to access it.
// Project configuration.
grunt.initConfig({
connect: {
server: {
options: {
port: 9001,
base: 'www-root'
}
}
}
});
The point of the server task is to have quick and dirty access to static files for testing. grunt server IS NOT a production server environment. It really should only be used during the grunt lifecycle to get static testing assets to the testing environment. Use a full-fledged server, possibly controlled by the NPM lifecycle scripts, for production environments.

Resources