Having external resources included in your gem-based Jekyll theme is pretty messy. Well not exactly: Just place your styles in the _sass
directory and drop everything else in assets
. Sounds good, doesn’t work – at least for me.
In this site’s theme, I used Bootstrap, so I researched ways to import its resources into the gem-based theme. Those include some stylesheets, Bootstraps own javascript with its dependencies jQuery and popper.js. There are a lot of options out there to get them into your project. Those are the most frequent solutions I found:
- Load them via CDN.
- Copy the resources to their appropriate destination by hand.
- Use NPM or any other JS package manager and add
node_modules
to your sass load paths, and refer to the javascript withinnode_modules
. - Use the jekyll-assets plugin to fetch the resources from their gem-packaged versions.
- Use the jekyll-bootstrap-sass plugin and include styles from the gem and configure asset loading in
_config.yml
.
I really liked none of them, there was a show stopper in every solution. But first of all my requirements:
- Easy updates and version locking.
- All work is done in the theme gem.
- No manual copying of files or explicit specifying of copy paths (minimal update effort).
- Fetching the resources via any resources manager, preferably from the ruby gems repositories as Jekyll also depends on those technologies.
- Benefit from partial includes and sass.
#1 and #3 circumvented the manual solution. The CDN approach was not possible because of #5. The node solution of #4 would work but having NPM as another non-ruby dependency sounded wrong. I like how both of the Jekyll plugins work, but they do not function with a gem-based theme or require additional config in the _config.yml
of the site using the theme.
So I started my solution with the premise of putting all resources into their Jekyll destinations: Stylesheets in the _sass
dir and all additional resources within assets
. I also copied the approach of fetching resources from the gem-packaged versions. The only part missing: How to get the files from the gems to the Jekyll dirs. I went with rake as it is Ruby’s default build tool and automatically there when you start with Jekyll. This is what I did:
Include the additional gems in the themes *.gemspec
:
spec.add_development_dependency "jquery-rails", "~> 4.3.3"
spec.add_development_dependency "bootstrap", "~> 4.1.3"
Install them via:
bundle install
Add the following Rakefile
in the theme’s root directory:
sass_dir = '_sass/vendor'
assets_dir = 'assets/vendor'
task default: %w[copy]
task :clean do
puts FileUtils.rm_rf(sass_dir)
puts FileUtils.rm_rf(assets_dir)
end
task :copy do
['bootstrap','jquery-rails', 'popper.js'].each do |gem|
path = %x{ #{"bundle show %s" % gem} }.strip()
if Dir.exists?(path + '/assets') then
path = path + '/assets'
elsif Dir.exists?(path + '/vendor/assets') then
path = path + '/vendor/assets'
else
path = nil
end
if path then
resource_paths = Dir.glob(path + '/*')
sass_paths = resource_paths.select{ |file_path| file_path.end_with?('/stylesheets')}
if not sass_paths.empty? then
sass_target_dir = [ sass_dir, gem ].join('/')
unless Dir.exists?(sass_target_dir) then
FileUtils.mkdir_p(sass_target_dir)
end
FileUtils.cp_r(sass_paths, sass_target_dir)
end
assets_paths = resource_paths.reject{ |file_path| file_path.end_with?('/stylesheets')}
if not assets_paths.empty? then
assets_target_dir = [ assets_dir, gem ].join('/')
unless Dir.exists?(assets_target_dir) then
FileUtils.mkdir_p(assets_target_dir)
end
FileUtils.cp_r(assets_paths, assets_target_dir)
end
end
end
end
Run it to copy all resources from the gems to the theme directories:
rake copy
Include the Bootstrap styles in your main sass file:
@import 'vendor/bootstrap/stylesheets/bootstrap';
Include the javascripts in your HTML template:
…
<body>
…
<script src="/assets/vendor/jquery-rails/javascripts/jquery3.min.js"></script>
<script src="/assets/vendor/popper.js/javascripts/popper.js"></script>
<script src="/assets/vendor/bootstrap/javascripts/bootstrap.min.js"></script>
</body>
</html>
To update the resources just change the dependency version in your themes *.gemspec
, and run:
bundle install
rake copy
That’s it!