live reloading golang server with gulp and browser-sync

It's been a while since I've posted anything, primarily because I just started a new job! I'm working on Dev Ops tools for multiple development teams to use across the organization. They are in the process of transitioning their continuous delivery pipeline to use Docker containers instead of just VMs, and new tools are needed to ease the transition.

Today, I was setting up a new project, and since it was relatively open-ended, I decided to use golang. Yes, colloquially it's called go, but, as I have learned from experience in the past couple of days, golang is the proper name, simply because search engines can pick up on it.

I chose to use the golang package for atom as my IDE. I think that the command line tools for go are pretty good out of the box, so I didn't feel pressured to go for something heavier-weight.

I was pleasantly surprised by how mature the go ecosystem has gotten, and how easy it was to get started with the language and tools. I did run into a few snags with the language and compiler coming into it with a JavaScript and C# background. For example, []byte is a byte slice (similar to a byte array) and byte[] is invalid, but the compiler doesn't point this out directly, which had me lost and confused for longer than I would like to admit.

Compiling and running go is fast. It takes less than a second to build and run a basic HTTP server, even on the mediocre laptop I was given.

So, as I was shoehorning some angular boilerplate into the project, I began to wonder if there was a way to integrate my simple go build (go run main.go otherThing.go) with gulp and browser-sync.

If you aren't already familiar, Gulp is a node.js-based platform for pre-processing JavaScript, HTML, and CSS, and browser-sync is a proxy server that makes it easy to serve those front-end assets and reload them in the browser whenever a file changes. I wanted a similar solution for my .go files: To stop the server, recompile, and restart every time a file changed.

So, I checked online, and found the gulp-go package. Unfortunately, the way that it kills and restarts its child process is only compatible with Mac OS and Linux, so I forked the repo to make it work on Windows as well. After that, I was able to set up the live-reloading of my server as just another gulp task.

//--snip--
gulp.task('bundle-templates-watch', ['bundle-templates'], function() { browserSync.reload(); });
gulp.task('copy-html-watch', ['copy-html'], function() { browserSync.reload(); });
gulp.task('bundle-js-watch', ['bundle-js'], function() { browserSync.reload(); });
gulp.task('go-server-watch', ['go-restart'], function() {
  setTimeout(function() { browserSync.reload(); }, 300); 
});

gulp.task('watch', ['build'], function() {
  gulp.watch(html, ['copy-html-watch']);
  gulp.watch(watchJs, ['bundle-js-watch']);
  gulp.watch(watchTemplates, ['bundle-templates-watch']);
  gulp.watch(watchLess, ['bundle-less']);
  gulp.watch([watchGo, watchServerTemplates], ['go-server-watch']);
});
//--snip--

I did notice a small problem with the browser-sync proxy server, however. It would try to reload as soon as go run finished. But there was a small lag between when go run finished an when the server started accepting requests, so it would cause the proxy's connection to hang. After adding the 300 millisecond timeout, it worked seamlessly every time.

I was really happy with the result: 100% of my code would live-reload when I saved the file, all within one console. Definitely a nice developer experience! It does take a while to get all of the dependencies downloaded and the gulpfile set up correctly, but once that's in place, I think it's well worth it.