Live Reloading Chrome Apps and Extensions with Gulp and WebSockets

My new favorite tool these days is Gulp. It’s blazing-fast pipe-streaming architecture combined with its extensibility and ease of configuration make it, dare I say, simply delightful to use.

I’ve been tinkering on a Google Chrome Extension lately and I quickly discovered the annoying obstacle of constantly needing to reload the thing. With a background page or script running, you constantly have to flip between browser tabs and/or windows to do manual refreshes every time you want to see your changes. Icky stuff.

I had used gulp-livereload in the past to solve this issue for traditional front-end web app development, but it didn’t work for refreshing the background script. Then I realized I could pretty easily roll my own lightweight solution using WebSockets.

WebSockets is an implementation of the fabled ‘push notification’ technology of keeping a long-standing open connection between server and client for immediate synchronization. It benefits by having a web standardization that is used in all major browsers, and therefore has an exposed JavaScript API.

For the Node.js and Gulp end of things, I used the module ws:

1
npm install ws --save-dev

Then I added it to my Gulpfile and created a reload task for it, which I added to the relevant watch tasks:

Gulpfile.coffee
1
2
3
4
5
6
7
8
9
10
11
WebSocketServer = require('ws').Server
wss = new WebSocketServer(port: 9191)

gulp.task 'reload', ->
  client.send('reload') for client in wss.clients

gulp.task 'coffee', ->
  ...

gulp.task 'watch', ->
  gulp.watch ["*.coffee"], ["coffee", "reload"]

For the Chrome Extension, I created this little CoffeeScript and included it in both the content and background scripts:

reload-client.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
socket = null

@reloadClient = 
  connect: ->
    socket = new WebSocket('wss://localhost:9191')
    socket.onopen = -> console.log('connected')
    socket.onclose = -> console.log('closed')
    socket.onmessage = (message) ->
      if message.data is "reload"
        window.chrome.runtime.reload()

  disconnect: ->
    socket.close()

# uncomment to connect on load
# reloadClient.connect() 

That’s it! When gulp -w boots, a WebSocket server is instantiated. Whenever a coffee file saves, the server sends a ‘reload’ message to all of its clients. In the browser, calling reloadClient.connect() creates a WebSocket which will sit and wait fervently for its very important message, until you save your next source file.

Comments