Set p Ruby, Bundler and a project-level Jekyll on macOS Catalina and up
This guide is for macOS Catalina and is based on the Jekyll on macOS doc and my experience.
Use the XCode CLI to install dev tools. Recommended so that you can install native extensions when installing gems.
$ xcode-select --install
Your system already has a Ruby installed, but its version and gems are locked in Catalina. So here we install another Ruby using Homebrew.
- Install Homebrew package manager.
- See instructions on brew.sh homepage.
- Use Homebrew to install Ruby - see ruby formula. Note version 3 is not suitable yet for Jekyll.
$ brew install [email protected]
- Choose a relevant shell config to edit. For Bash, use
~/.bashrc
,.profile
or.bash_profile
in the next steps. For ZSH, use~/.zshrc
or~/.zshenv
. - Add the following to your shell config. This will ensure so that your Homebrew install of Ruby will be found before the system Ruby at
/usr/bin/ruby
.RUBY_HOME=/usr/local/opt/ruby/bin export PATH="$RUBY_HOME:$PATH"
If you want to install in a shared directory (owned by root and shared across users for reading), use this.
$ gem install bundler
$ which -a bundler
/usr/local/opt/ruby/bin/bundler
If you get a prompt to use sudo
, then cancel the install command. And rather install in your user's ~/.gem
directory instead as below.
- Add the following to your shell config. This will add something like
~/.gem/ruby/2.7.0/bin
to yourPATH
, so your gems can be run from anywhere.GEM_PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin" export PATH="$GEM_PATH:$PATH"
- Open a new terminal to reload your shell configs.
- Install Bundler in your user's
~/.gem/
directory. Using flag as below to avoidsudo
use.$ gem install bundler --user-install
$ which -a bundler /Users/mcurrin/.gem/ruby/2.7.0/bin/bundler
- Add these two gems to your
Gemfile
.gem "jekyll", "~> 3.9" gem "kramdown-parser-gfm", "~> 1.1.0"
- Here the version matches that of the locked versions on GH Pages. If you don't use GH Pages, I recommend a newer version like Jekyll
~> 4.2
. - For Jekyll 3.9 (and not 3.8 or 4), you need do the Kramdown parser explicitly to avoid errors.
- Here the version matches that of the locked versions on GH Pages. If you don't use GH Pages, I recommend a newer version like Jekyll
- Configure Bundler in your project. Make sure you use the
--local
flag to avoid editing the global Bundler config. See also the Bundle config docs.Check the contents of the YAML Bundler config. Once this file exists, you don't have to set it up. But make sure to add it to the ignore file and set it up on each machine.$ cd my-jekyll-project $ bundle config set --local path vendor/bundle
$ cat .bundle/config
--- BUNDLE_PATH: "vendor/bundle"
- Install project gems.
Check installed gems.
$ bundle install
$ ls vendor/bundle/ruby/2.7.0/gems
addressable-2.7.0 jekyll-feed-0.15.1 minima-2.5.1 colorator-1.1.0 jekyll-sass-converter-1.5.2 pathutil-0.16.2 ...
Serve:
$ bundle exec jekyll serve --trace --livereload
Build:
$ bundle exec jekyll build --trace
Tip: If you run into issues installing or running because of libffi
or ffi_c
missing, you can try these:
brew install libffi
gem install ffi --user-install
# Or
sudo gem install ffi
The idea of isolating dependencies into project folder like
vendor/bundle
is the same as creating a virtual environment in Python ornode_modules
in Node.js. If two projects need different versions of the same gem, they can have their own space without conflicting.From your other comment on Jekyll it looks like you can have multiple versions of a gem installed globally, but that is not they way it goes in Python and Node.js.
Sometimes you'll install a new gem and it will upgrade something else behind the scenes and then later you find another project project and it is hard to work out why.
If I want to setup a project on a different laptop or server, its dependencies are all contain in the Gemfile and installed into the local
vendor/bundle
. No worrying what the global environment is on each machine or making sure you replicate it on each.Yes there is duplication especially of larger gems, but this is acceptable for robustness it gives each project and when storage is not an issue. I have also had a ton of annoying issues over the years where a user-level or root-level change which was maybe even an automated update broke multiple projects - in one case my IDE itself broke.
The situation is bit different for simulating GH Pages locally, as I could setup my user environment to exactly match the gem version of GH Pages, at least for the gems that I care about. But the problem is that I want to use the newer versions of gems or custom gems for my Netlify projects.
Yes it is annoying to wait to install gems for a fresh project each time but after that it is quick to work with.
Thanks for the tip. Fixed.