├── .github ├── FUNDING.yml └── workflows │ ├── gempush.yml │ └── ruby.yml ├── .rspec ├── .gitignore ├── Gemfile ├── spec ├── fixtures │ └── unit │ │ ├── _config.yml │ │ ├── _includes │ │ └── include.html │ │ ├── nothing.html │ │ ├── index.md │ │ ├── _docs │ │ ├── document-with-include.md │ │ └── document-with-liquid-tag.md │ │ ├── _posts │ │ ├── 2020-04-16-post-with-img.md │ │ ├── 2020-04-16-post-with-iframe.md │ │ ├── 2020-04-16-post-with-loading-img.md │ │ ├── 2020-04-16-post-with-loading-iframe.md │ │ └── 2018-05-22-post-with-multiple-markdown-images.md │ │ └── _layouts │ │ └── default.html ├── spec_helper.rb └── jekyll-loading_spec.rb ├── lib ├── jekyll-loading-lazy │ └── version.rb └── jekyll-loading-lazy.rb ├── .rubocop.yml ├── Rakefile ├── LICENSE.md ├── jekyll-loading-lazy.gemspec ├── README.md └── Gemfile.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: gildesmarais 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | --order random 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.gem 2 | spec/fixtures/unit/.jekyll-cache 3 | pkg 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_config.yml: -------------------------------------------------------------------------------- 1 | url: https://gil.desmarais.de 2 | collections: 3 | docs: 4 | output: true 5 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_includes/include.html: -------------------------------------------------------------------------------- 1 | This is an include. It has an image. ![](https://via.placeholder.com/150) 2 | -------------------------------------------------------------------------------- /spec/fixtures/unit/nothing.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Nothing 4 | --- 5 | 6 |

Nothing to do in here.

7 | -------------------------------------------------------------------------------- /spec/fixtures/unit/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Just a page 4 | --- 5 | 6 | ![This is an image](https://via.placeholder.com/150). 7 | -------------------------------------------------------------------------------- /lib/jekyll-loading-lazy/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jekyll 4 | class LoadingLazy 5 | VERSION = "0.1.1" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_docs/document-with-include.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Document with include 3 | --- 4 | 5 | This is a document with an include: {% include include.html %} 6 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_docs/document-with-liquid-tag.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Document with liquid tag 3 | --- 4 | 5 | This is an image with a liquid tag. 6 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_posts/2020-04-16-post-with-img.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Post with html tag 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: rubocop-jekyll 2 | 3 | inherit_gem: 4 | rubocop-jekyll: .rubocop.yml 5 | 6 | AllCops: 7 | TargetRubyVersion: 2.5 8 | Exclude: 9 | - vendor/**/* 10 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | require "rspec/core/rake_task" 5 | 6 | RSpec::Core::RakeTask.new(:spec) 7 | 8 | task :default => %w(spec) 9 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_posts/2020-04-16-post-with-iframe.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Post with html 7 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_posts/2020-04-16-post-with-loading-img.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Post with html tag having loading attribute 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_posts/2020-04-16-post-with-loading-iframe.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Post with html 7 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_posts/2018-05-22-post-with-multiple-markdown-images.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Post with multiple markdown images 4 | --- 5 | 6 | 1. ![alt](https://via.placeholder.com/150) 7 | 2. ![alt](https://via.placeholder.com/250) 8 | 3. ![alt](https://via.placeholder.com/350) 9 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "jekyll-loading-lazy" 4 | 5 | RSpec.configure do |_config| 6 | UNIT_FIXTURES_DIR = File.expand_path("fixtures/unit", __dir__).freeze 7 | 8 | def unit_fixtures_dir(*paths) 9 | File.join(UNIT_FIXTURES_DIR, *paths) 10 | end 11 | 12 | def find_by_title(docs, title) 13 | docs.find { |d| d.data["title"] == title } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/fixtures/unit/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ page.title }} 6 | 7 | 8 | 9 |
Layout content started.
10 | {{ content }} 11 |
Layout content ended.
12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/jekyll-loading-lazy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "jekyll" 4 | require "nokogiri" 5 | 6 | module Jekyll 7 | class LoadingLazy 8 | def self.process(content) 9 | html = content.output 10 | content.output = process_tags(html) if process_tags?(html) 11 | end 12 | 13 | def self.process?(doc) 14 | (doc.is_a?(Jekyll::Page) || doc.write?) && doc.output_ext == ".html" || 15 | doc.permalink&.end_with?("/") 16 | end 17 | 18 | def self.process_tags?(html) 19 | html.include?(" $HOME/.gem/credentials 36 | gem build *.gemspec 37 | gem push *.gem 38 | env: 39 | GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}} 40 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | name: rubocop, rspec and build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | 17 | - name: Set up Ruby 2.5 18 | uses: actions/setup-ruby@v1 19 | with: 20 | ruby-version: 2.5.x 21 | 22 | - name: Cache gems 23 | uses: actions/cache@preview 24 | with: 25 | path: vendor/bundle 26 | key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} 27 | restore-keys: | 28 | ${{ runner.os }}-gem- 29 | 30 | - name: setup bundler 31 | run: | 32 | gem install bundler 33 | bundle config path vendor/bundle 34 | bundle config --global frozen 1 35 | - name: bundle install 36 | run: bundle install --jobs 4 --retry 3 37 | 38 | - name: run rubocop 39 | run: bundle exec rubocop --fail-fast 40 | 41 | - name: run rspec 42 | run: bundle exec rake 43 | 44 | - name: build 45 | run: bundle exec rake build 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Gil Desmarais and approved contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /jekyll-loading-lazy.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path("lib", __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require "jekyll-loading-lazy/version" 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = "jekyll-loading-lazy" 9 | spec.version = Jekyll::LoadingLazy::VERSION 10 | spec.authors = ["Gil Desmarais"] 11 | spec.email = %w(jekyll-loading-lazy@desmarais.de) 12 | spec.summary = 'Automatically adds loading="lazy" to and 83 | HTML 84 | end 85 | end 86 | context "with img with liquid tags" do 87 | it "adds loading attribute" do 88 | expect(document_with_liquid_tag.output).to include(<<~HTML) 89 |

This is an image with a liquid tag.

90 | HTML 91 | end 92 | end 93 | 94 | context "with img within includes" do 95 | it "adds loading attribute" do 96 | expect(document_with_include.output).to include(<<~HTML) 97 |

This is a document with an include: This is an include. It has an image.

98 | HTML 99 | end 100 | end 101 | end 102 | 103 | context "with loading attribute present" do 104 | context "with img" do 105 | it "does not set loading=lazy" do 106 | expect(post_with_loading_img.output).to include(<<~HTML) 107 |

108 | HTML 109 | end 110 | end 111 | 112 | context "with iframe" do 113 | it "does not set loading=lazy" do 114 | expect(post_with_loading_iframe.output).to include(<<~HTML) 115 | 116 | HTML 117 | end 118 | end 119 | end 120 | 121 | context "without any img/iframe" do 122 | it "does not change the markup" do 123 | expect(page_nothing).to include(<<~HTML) 124 |

Nothing to do in here.

125 | HTML 126 | end 127 | end 128 | end 129 | --------------------------------------------------------------------------------