Skip to content

Instantly share code, notes, and snippets.

@MichaelCurrin
Last active January 31, 2024 18:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MichaelCurrin/61053a564bdb3098bae11f949bab3578 to your computer and use it in GitHub Desktop.
Save MichaelCurrin/61053a564bdb3098bae11f949bab3578 to your computer and use it in GitHub Desktop.
Set up Ruby, Bundler and a project-level Jekyll on macOS Catalina and up

Set up Jekyll environment on macOS

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.

1. Install dev tools

Use the XCode CLI to install dev tools. Recommended so that you can install native extensions when installing gems.

$ xcode-select --install

2. Install Ruby

Your system already has a Ruby installed, but its version and gems are locked in Catalina. So here we install another Ruby using Homebrew.

  1. Install Homebrew package manager.
    • See instructions on brew.sh homepage.
  2. Use Homebrew to install Ruby - see ruby formula. Note version 3 is not suitable yet for Jekyll.
    $ brew install ruby@2.7
  3. 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.
  4. 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"

3. Set up system gems

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.

  1. Add the following to your shell config. This will add something like ~/.gem/ruby/2.7.0/bin to your PATH, so your gems can be run from anywhere.
    GEM_PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin"
    export PATH="$GEM_PATH:$PATH"
  2. Open a new terminal to reload your shell configs.
  3. Install Bundler in your user's ~/.gem/ directory. Using flag as below to avoid sudo use.
    $ gem install bundler --user-install
    $ which -a bundler
    /Users/mcurrin/.gem/ruby/2.7.0/bin/bundler

4. Install project-scoped gems

  1. 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.
  2. 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.
    $ cd my-jekyll-project
    $ bundle config set --local path vendor/bundle
    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.
    $ cat .bundle/config
    ---
    BUNDLE_PATH: "vendor/bundle"
  3. Install project gems.
    $ bundle install
    Check installed gems.
    $ 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
    ...
    

5. Run Jekyll in your project

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
@chuckhoupt
Copy link

Nice. Comment: Why install gems into vendor/bundle for each site? I know this is the recommended setup for production servers, but for development on a Mac it will waste a lot of time/disk for all the duplicate gems.

Minor typo: "3. Get Ruby is setup." should be "3. Get Ruby setup".

@MichaelCurrin
Copy link
Author

The idea of isolating dependencies into project folder like vendor/bundle is the same as creating a virtual environment in Python or node_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.

@MichaelCurrin
Copy link
Author

MichaelCurrin commented Nov 12, 2020

Also I can't assume that someone else is willing to change their user-level gems to use my project, so a project-scoped flow is safer.

@monfresh
Copy link

monfresh commented Dec 3, 2020

.bashrc should be replaced with .bash_profile. ~/.bashrc does not get read automatically on macOS. You can test this by adding echo "hello from bashrc" to your ~/.bashrc, and open a new terminal tab. You will not see anything, but if you add echo "hello from bash_profile" to your ~/.bash_profile, you will see the hello statement.

@MichaelCurrin
Copy link
Author

MichaelCurrin commented Dec 4, 2020

Oh, I didn't realize that.

When I used Bash pre-Catalina, I had this line in my .bash_profile at the time.

. ~/.bashrc

I don't know I made that or it came with it.

I confirmed what you used using what I found is the most reliable for switching shells, with a login flag.

exec -l bash

As discussed in the other GH thread, a .bash_profile is not standard on Debian/Ubuntu. And creating one would prevent any code in .profile from running.

Also I found a table of comparisons.

https://en.wikipedia.org/wiki/Unix_shell#Configuration_files

@MichaelCurrin
Copy link
Author

I've given 3 options for Bash.

I also made some other changes.

@sieveLau
Copy link

Step 4.1: the quotes are not correct. Should be:

gem 'jekyll', '~> 3.9'
gem "kramdown-parser-gfm", '~> 1.1.0'

@MichaelCurrin
Copy link
Author

@sieveLau , fixed, thanks!

@sieveLau
Copy link

@sieveLau , fixed, thanks!

It seems the pair wrapping jekyll is still incorrect.

@MichaelCurrin
Copy link
Author

oops. Thanks, fixed again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment