Created
January 16, 2012 17:47
-
-
Save mklabs/1621995 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var fs = require('fs'), | |
path = require('path'), | |
url = require('url'), | |
socketio = require('socket.io'), | |
connect = require('connect'), | |
mime = connect.static.mime, | |
// one time-hit, get the file content of the socket.io client side script | |
ioScript = underscore.template(fs.readFileSync(path.join(__dirname, 'util/socket-enable.js'), 'utf8')); | |
// | |
// ### Tasks | |
// | |
// #### task:foo | |
task.registerBasicTask('foo', 'A basic tasks that emits event over socket.io', function(data, name) { | |
var socket = config('socket'); | |
socket && socket.emit('changed'); | |
}); | |
// #### task:connect | |
// | |
// serve task, this one will use raw express (or just connect, should be enough) | |
// application with socket.io connection setup. | |
// | |
// It works by injecting a tiny client-side script on any `*.html` request (might be better | |
// if done on any `content-type: text/html`, this way it would be able to catch up requests, | |
// even those serving dynamic content, not just statics). That client side establish | |
// a new websocket connection and retrigger a page reload whenever the `changed` event is emitted. | |
// | |
// | |
// The server spawn is wrapped up in a grunt task, and set to the config a new `socket` object, | |
// when a new client side connection is done. | |
// | |
// task.registerTask('connect-watch', 'connect watch:reload'); | |
// | |
// The `watch:reload` is setup to fire the `foo` tasks, whose role is to simply emit | |
// the `changed` event on the socket that might have been stored through `config('socket')`. | |
// | |
// todo: that tasks begins to get pretty long, might be worth moving the custom middleware, into | |
// a grunt helper or a simple function defined elsewhere (probably in its own module) | |
task.registerBasicTask('connect', 'Spawns up a local http server', function(data, name) { | |
// path | |
var dirname = path.resolve(name); | |
log.subhead('Spawning http server from dirname ' + dirname + ' on port: ' + data.port); | |
// setup the server | |
var server = connect(); | |
// setup socketio | |
var io = socketio.listen(server); | |
io.enable('browser client minification'); | |
io.enable('browser client etag'); | |
io.enable('browser client gzip'); | |
io.set('log level', 5); | |
// store the socket object in grunt's config, so that we can interract from other tasks | |
io.sockets.on('connection', config.bind(config, 'socket')); | |
// ignore favicon | |
server.use(connect.favicon()); | |
// setup logs | |
data.logs && server.use(connect.logger(data.logs)); | |
// custom static middleware, tricking the static one | |
server.use(function(req, res, next) { | |
// serve any static *.html, support of `index.html` | |
var parsed = url.parse(req.url), | |
// join / normalize from root dir | |
filepath = path.normalize(path.join(dirname, decodeURIComponent(parsed.pathname))), | |
// index.html support when trainling `/` | |
index = path.normalize('/') === filepath.charAt(filepath.length - 1), | |
ioResponse; | |
if(index) filepath += 'index.html'; | |
// deal with our special socket.io client-side script | |
if(path.basename(filepath) === 'socket-enable.js') { | |
res.setHeader('Content-Type', mime.lookup('js')); | |
ioResponse = ioScript(data); | |
res.setHeader('Content-Length', ioResponse.length); | |
return res.end(ioResponse); | |
} | |
fs.stat(filepath, function(e, stat) { | |
// files do not exists, next with error only on unexpected errors | |
if(e) return next((e.code === 'ENOENT' || 'ENAMETOOLONG' === e.code) ? null : e); | |
// file is a dir, next to the directory listing if enabled | |
if(stat.isDirectory()) return next(); | |
// anything that's not `*.html`, give back control to static / directory listing middleware | |
if(path.extname(filepath) !== '.html') return next(); | |
// setup some basic headers, might add some. Below is pretty minimalist (might tweak and add | |
// basic caching stuff for example) | |
res.setHeader('Content-Type', mime.lookup(filepath)); | |
// can't use the ideal stream / pipe case, we need to alter the html response | |
// by injecting that little socket.io client-side app. | |
fs.readFile(filepath, 'utf8', function(e, body) { | |
if(e) return next(e); | |
body = body.replace(/<\/body>/, function(w) { | |
return [ | |
' <script defer src="/socket.io/socket.io.js"></script>', | |
' <script defer src="/socket-enable.js"></script>', | |
w | |
].join('\n'); | |
}); | |
res.setHeader('Content-Length', body.length); | |
res.end(body); | |
}); | |
}); | |
}); | |
// static files | |
server.use(connect.static(dirname)); | |
// directory serving | |
data.dirs && server.use(connect.directory(dirname)); | |
// start the server | |
server.listen(data.port); | |
log.writeln('\033[90mserving \033[36m:path\033[90m on port \033[96m:port\033[0m' | |
.replace(':path', dirname) | |
.replace(':port', data.port) | |
); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
config.init({ | |
lint: { | |
files: ['js/*.js'], | |
build: ['grunt.js', 'build/tasks/*.js'] | |
}, | |
watch: { | |
files: '<config:lint.build>', | |
tasks: 'lint:build', | |
reload: { | |
files: '<config:lint.build>', | |
tasks: 'foo' | |
} | |
}, | |
serve: { | |
intermediate: { port: 3000 }, | |
publish: { port: 3001 } | |
}, | |
connect: { | |
intermediate: { | |
port: 3000, | |
logs: 'dev', | |
dirs: true | |
}, | |
publish: { | |
port: 3001, | |
logs: 'default', | |
dirs: true | |
} | |
}, | |
foo: { | |
bar: [] | |
} | |
}); | |
task.registerTask('connect-watch', 'connect watch:reload'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var url = 'http://localhost:<%= port %>', | |
socket = io.connect(url); | |
socket.on('changed', function(file, path, content) { | |
console.log('socket', arguments); | |
location.assign(location.pathname); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment