Jekyll, Bundler and NPM

I’m wondering: has someone had good experiences with combining NPM with Bundler and Jekyll? I’d like to set up a simple way of managing JavaScript dependencies. I have never set up a JS bundling setup from scratch. Ideally, I’d only have:

  • One dependency manager to ask for installing or updating the setup (not sure if this is even possible or desirable, but somehow combining two package managers feels wrong)
  • One command to start the dev server (e.g. npm run dev)
  • One command to start a site build (e.g. npm run build)

I guess I also need something like Grunt or Parcel to combine the JS files?

Background is that I want to add Alpine.js. I already have several JS files that I combine using includes and that feels messy.

Hi Koos

I know your struggle and have a solution fr you. GitHub Pages does not support custom builds with NPM etc. But you can use GitHub Actions with a config of like 100 lines or Netlify with a config of a few lines.

Some Ruby or Jekyll projects use rake to manage npm install and other tasks but I struggle to get into it.

My approach is to use a Makefile and call it with make command. That comes from the C compilation background but you’ll also see it in Python and C++ projects. It comes with mac and linux and I think you can install on windows

Here is my simple Jekyll related makefile.

To use it:

cd repo
make install
make build

And now the site is built.

Run those commands on GitHub Actions or your remote server and it will work the same. On Netlify you don’t even need to run make install as Netlify finds a Gemfile and package.json and installs for you.

I use a Makefile for all my Jekyll projects as it let’s me manage by commands easily and I can run multiple tasks underneath like NPM and Bundle steps to install or build.

For example to you can define commands as

install-js:
	npm install

install-gems:
	bundle config set --local path vendor/bundle
	bundle install

install: install-js install-gems

Which means when you run

make install

It runs

npm install
bundle config...
bundle install

And you can define build as

build:
  npm run build
  bundle exec jekyll build --trace

So you just have to run make build and it will run both commands.

And then you would have make build as the build step in your Netlify config or GH Actions workflow.

Note that make will exit on failure so it effectively does

npm run build && bundle exec ...

Regarding using parcel etc.

You can define that in your package.json file. So that npm run build will run a parcel command and then react build etc.

Or you can move everything to makefile

So

build: lint
  parcel foo
  react build bar
  bundle exec jekyll build --trace

Above I also define that make lint always runs before the other commands in the build command.

And you can define a dev command like this. Here I assume you build a static npm site rather than have it running as a dev server.

dev:
  npm run build
  bundle exec jekyll serve --trace

If your Jekyll site needs to point to a server side node app, then you’ll have to start that node app in another terminal window when running your Jekyll dev server

Thanks, that’s pretty simple :slight_smile: I’m not on Github pages, so I think I could just as well do that with a bash script? Not sure about the mac-specificness of that though, maybe Makefiles have better support.

But this way you manually have to rebuild and refresh with every JS change, right?

Make is available on mac and linux and will run bash commands.

You can choose to run then bash commands directly like with an alias on your machine.

A makefile is a nice versioned way to share commands across your machines and across local and CI flows

Yes you have to stop and start the dev step to build the JS.

But you could use npm run watch in another tab to build and then continuously look for changed Js files and rebuild. I’m not so familiar with it but have see it in some JS projects.

If you want to run the two command at the same time in one terminal, you can use this concurrently package.

The example is within package.json start command so it is implied that it it runs node_modules/bin/concurrently or similar

You could try use it in your make command. Dont know if this works. Use npx as a shortcut for the Node Modules path.

dev:
  npx concurrently 'npm run watch' 'bundle exec jekyll s

You can also try parallel jobs in make, here calling two targets.

make -j 2 watch-js jekyll-serve

If that that works you could turn that into a make command.

dev:
   make -j 2 watch-js jekyll-serve

Thanks, I’m going to try that out. Just to make sure I understand the approach: the idea is that the bundler and npm watch/build processes run in parallel (not serial) and there’s not actual relationship between the two other than the make file?

What’s not clear to me yet: how do you let the browser connected to the dev server reload on changes to html and assets including JS?

That’s correct. The processes start and stop at the same time but they don’t know about each other

Get it to work in too terminal tabs first and the try the one terminal parallel approach.

Also bear in mind that a rebuild of npm assets to assets will also trigger Jekyll to rebuild but that should be a good flow.

Jekyll serve has a flag for --livereload to refresh the browser on file changes and based on my previous paragraph it will pick up JS changes too.

I hope that outputting 10 JS assets doesnt cause 10 rebuilds in the same second. Maybe you can set a wait flag along with the hot reload flag, or just make sure you output as few JS files as possible

I have a copy of jekyll CLI flags near the bottom here

A possible alternative using alias:

Let’s say I wanted to run a npm watch script at the same time as a Jekyll build/serve command. I’d install parallelshell and add something like the below to my bash_aliases file:

alias serve=‘parallelshell “bundle exec jekyll serve --livereload” “npm run watch-js”’

Then in my terminal all I have to type is serve.

That is similar to concurrently I suggest above. Haven’t used either but here is a comparison

My hope is that make with parallel job flag will do this without relying on an external library

Also the problem is not that bad if you accept creating a 2nd terminal and leaving it running while your work on your site for a few hours or even days.