Path: blob/main/_plugins/jekyll-bundler.rb
1677 views
require 'digest'12# While reading in all of the files for the site3# load the bundles and find out their last modified time4# so we can use that as a cache buster5Jekyll::Hooks.register :site, :post_read do |site|6site.config['javascript_bundles'].each do |name, resources|7if Jekyll.env == 'production'8# Get the maximum last file modified time to use as the bundle timestamp9bundle_timestamp = resources['resources'].map { |f| File.mtime(f).to_i }.max10site.config['javascript_bundles'][name]['timestamp'] = bundle_timestamp1112# This is inefficient since we read twice but it's also not that expensive.13bundle = resources['resources'].map { |f| File.read(f) }.join("\n")14hash = Digest::MD5.hexdigest(bundle)[0..7]15site.config['javascript_bundles'][name]['hash'] = hash16site.config['javascript_bundles'][name]['path'] = "/assets/js/bundle.#{name}.#{hash}.js"1718Jekyll.logger.info "[GTN/Bundler] Analysing JS Bundle #{name} => #{bundle_timestamp} / #{hash}"19else20Jekyll.logger.info '[GTN/Bundler] Serving plain JS'21end22end23end2425# When writing the site, build the bundles26# It's basically "cat *.js > bundle.js"27# We don't need no fancy JS minification28# gzip probably does enough, everything else is pre-minified.29Jekyll::Hooks.register :site, :post_write do |site|30site.config['javascript_bundles'].each do |name, resources|31if Jekyll.env == 'production'32bundle_path = "#{site.dest}#{resources['path']}"33Jekyll.logger.info "[GTN/Bundler] Building JS bundle #{name} => #{bundle_path}"3435# Just concatenate them all together36bundle = resources['resources'].map { |f| File.read(f) }.join("\n")3738# Write the bundle to the output directory39File.write(bundle_path, bundle)40end41end42end4344module Jekyll45module Filters4647# Our (very simple) JS Bundler48module JsBundle49##50# Setup the local cache via +Jekyll::Cache+51def cache52@@cache ||= Jekyll::Cache.new('GtnJsBundle')53end5455# Return the preloads for the bundles, when in production56# +test+:: ignore this57# Returns the HTML to load the bundle58#59# Example:60# {{ 'load' | bundle_preloads }}61def bundle_preloads(_test)62if Jekyll.env == 'production'63bundle_preloads_prod64else65''66end67end6869# (Internal) Return the production preloads for the bundles70def bundle_preloads_prod71bundles = @context.registers[:site].config['javascript_bundles']72baseurl = @context.registers[:site].config['baseurl']7374# Select the ones wishing to be preloaded75bundles = bundles.select do |_name, bundle|76bundle['preload'] == true77end7879bundles.map do |_name, bundle|80bundle_path = "#{baseurl}#{bundle['path']}"81"<link rel='preload' href='#{bundle_path}' as='script'>"82end.join("\n")83end8485# Load a specific bundle, in liquid86# +name+:: the name of the bundle to load87# Returns the HTML to load the bundle88#89# Example:90# {{ 'main' | load_bundle }}91def load_bundle(name)92cache.getset("#{Jekyll.env}-#{name}") do93if Jekyll.env == 'production'94load_bundle_production(name)95else96load_bundle_dev(name)97end98end99end100101##102# Dev version of the bundle loader, just direct script links103def load_bundle_dev(name)104bundle = @context.registers[:site].config['javascript_bundles'][name]105raise "Bundle #{name} not found in site config" if bundle.nil?106107Jekyll.logger.debug "[GTN/Bundler] Bundle #{bundle}"108109baseurl = @context.registers[:site].config['baseurl']110111bundle['resources'].map do |f|112"<script src='#{baseurl}/#{f}'></script>"113end.join("\n")114end115116##117# Production version of the bundle loader, with cache busting118def load_bundle_production(name)119bundle = @context.registers[:site].config['javascript_bundles'][name]120raise "Bundle #{name} not found in site config" if bundle.nil?121122baseurl = @context.registers[:site].config['baseurl']123attrs = ''124attrs += ' async' if bundle['async']125attrs += ' defer' if bundle['defer']126bundle_path = "#{baseurl}#{bundle['path']}"127"<script #{attrs} src='#{bundle_path}'></script>"128end129end130end131end132133Liquid::Template.register_filter(Jekyll::Filters::JsBundle)134135136