LiveReload problems when serving Hugo and webpack theme at same time

Hi everyone! I’m attempting to write a simple CLI build tool for a Hugo theme. One of my goals is to make it easy for an end-user to run two processes at the same time:

  • hugo server
  • webpack --watch (plus various other options) in a themes/ subfolder

I’d like to provide one simple command that saves a user from having to open two separate terminal windows and give two separate commands.

When I run each process in a separate terminal window, the site automatically reloads fine.But I’m having trouble getting LiveReload to work when running both processes at once.

I’ve been attempting to do this within a Node.js CLI app (based on the Commander library), but I’m also open to using shell scripts for this.

Here’s how I attempted to do this in a shell script:

# bin/dev.sh
trap "kill %1" EXIT
hugo server & cd "themes/my-theme-folder" && ./node_modules/.bin/webpack --watch

And here’s an attempt in Node:

const spawn = require('child_process').spawn

let webpackCmd = 'node_modules/.bin/webpack'
let webpackProcess = spawn(webpackCmd, ['--watch'], { cwd: path.join(process.cwd(), 'themes', 'my-theme')})

webpackProcess.stdout.on('data', (data) => { console.log(`${data}`)})
webpackProcess.stderr.on('data', (data) => { console.log(`${data}`)})
webpackProcess.on('close', (code) => { console.log(`Exited with code: ${code}`)})

let hugoProcess = spawn('hugo', ['server'])
hugoProcess.stdout.on('data', (data) => { console.log(`${data}`)})
hugoProcess.stderr.on('data', (data) => { console.log(`${data}`)})
hugoProcess.on('close', (code) => { console.log(`Exited with code: ${code}`)})

Both of these approaches build the theme assets (scss, js, etc) on first run but it seems like changes after that are not gettting picked up by Hugo.

I’m not a Node expert, so maybe I’m not allowing these processes to communicate properly?

Any suggestions are greatly appreciated.

@egardner Sounds like you are trying to create something similar to Netlify’s “Victor Hugo.” I can’t help with your specific errors in the console, but I can speak to this approach working when combining webpack with Hugo:

https://github.com/netlify/victor-hugo

@rdwatters I wasn’t aware of this, thanks for sharing! It’s always good to have a fleshed-out example to study. I’ll see if I can incorporate some of their techniques to my problem.

@rdwatters thanks again for the Victor Hugo link!

I ended up adapting some of what they did, but making modifications as well (the Victor Hugo kit doesn’t distinguish between content and theme, which is something I wanted to preserve).

It looks like the Victor template uses BrowserSync to handle the livereload functionality, and a gulp watch task runs a static rebuild of assets or content pages when necessary. I tried doing this but I found the BrowserSync server to be pretty slow.

I’m still using Gulp for this but I wanted to leverage Hugo and Webpack’s native watch abilities since they are both pretty fast (especially Hugo, which is kind of amazing here).

In case it’s helpful to anyone else, here’s an example of a simple gulp task that runs hugo and webpack --watch simultaneously:

// Abridged gulpfile.js in project root:
//
const fs = require('fs')
const gulp = require('gulp')
const spawn = require('child_process').spawn
const yaml = require('js-yaml')

const THEME_NAME = yaml.safeLoad(fs.readFileSync('./config.yml', 'utf8')).theme
const THEME_PATH = path.join(__dirname, 'themes', THEME_NAME)
const WEBPACK_BIN = './node_modules/.bin/webpack'

// Run hugo server and webpack --watch simultaneously, with merged output
gulp.task('dev', (cb) => {
  spawn(WEBPACK_BIN, ['--watch'], { cwd: THEME_PATH, stdio: 'inherit' }, (err) => {
    if (err) return cb(err)
    cb()
  })

  spawn('hugo', ['server'], { stdio: 'inherit' }, (err) => {
    if (err) return cb(err)
    cb()
  })
})

Great minds think alike :wink:

Haha, glad you got it working and nice work on the Gulp setup. Cheers.

Haha, I saw that when I was doing some research and recognized your handle!

The project I’m working on is currently in a private repo, but in the near future I want to open-source. It could serve as another example of how to set up a Hugo build system for a project that is more complex than a typical blog. Inspired somewhat by the Proteus Templates from Thoughtbot, which I found very useful for working in Jekyll & Middleman.

Good stuff and thanks for sharing Proteus. I love thoughtbot, especially Bourbon/Neat. It’s clearly a Ruby project, but I was feeling brazen and put in a request for them to put together a Hugo starter as well…