High Performance AMP Blog with Jekyll - Part 4
In this series I'll show how to setup a high performance, mobile friendly AMP Blog with custom Jekyll plugins while using GitHub pages as a free hosting provider. We create a staging environment and setup an automatic deploy and testing with Travis CI.
We want a professional setup, so to achieve additional security to ensure that we are not deploying a broken website we want our output tested. One easy way is to setup an automated test that parses the html of our generated website and checks for syntax errors as not closed html-tags and broken links. This is a kind of E2E test, which can be done with very few lines of code.
The Basics - what are we talking about today?
The Travis CI lifecycle
A Travis CI build runs certain steps when it executes the build. We can hook into each step and define custom actions to execute within each step. We are already using install
, script
, and deploy
step in our .tavis.yml
and you can find a full list in the Job Lifecycle Docs
# .travis.yml
...
install:
- bundle install
script:
- JEKYLL_ENV="production" bundle exec jekyll build
deploy:
provider: script
script: bash script/deploy.sh
...
HTML Proofer
HTML Proofer is a Gem that checks your resulting site to ensure all links and images exist and that we didn’t forget to close a HTML tag in a template. We’ll run it after the jekyll build was done on our docs
folder as an aditional test in the script
step, so we can gain confidence that current changes don’t break the website and we are one step closer to Continuous Delivery
Install the plugin
We add gem 'html-proofer'
in our Gemfile
# Gemfile
...
group :jekyll_plugins do
gem 'html-proofer'
gem 'jekyll_picture_tag'
end
and install it with bundle install
development/websites/my-new-website
▶ bundle install
...
Using html-proofer 3.15.3
...
Bundle complete! 8 Gemfile dependencies, 45 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Run the test locally
development/websites/my-new-website
▶ bundle exec htmlproofer docs
Running ["ImageCheck", "LinkCheck", "ScriptCheck"] on ["./docs"] on *.html...
Checking 12 external links...
Ran on 4 files!
- ./docs/404.html
* External link http://localhost:4000/404.html failed: 404 No error
- ./docs/index.html
* image /generated/flag-775-e90e07ca7.png does not have an alt attribute (line 36)
- ./docs/jekyll/update/2020/07/22/welcome-to-jekyll.html
* External link http://localhost:4000/jekyll/update/2020/07/22/welcome-to-jekyll.html failed: 404 No error
htmlproofer 3.15.3 | Error: HTML-Proofer found 3 failures!
We see that it finds 3 errors, 2 of them refer to an non existing external link and one to a missing alt
tag for our flag image. We are ignoring the external links for a second and fix the misssing alt
tag first.
Provide an alt-tag for Jekyll Picture Tag
In our index.markdown we add the --alt
parameter to create the missing attribute
# index.markdown
...
{% picture flag.png --alt This is a flag for demo purpose %}
...
Rebuild and check linking
development/websites/my-new-website
▶ bundle exec jekyll build
...
development/websites/my-new-website
▶ bundler exec htmlproofer docs
Running ["ImageCheck", "LinkCheck", "ScriptCheck"] on ["docs"] on *.html...
Checking 12 external links...
Ran on 4 files!
- docs/404.html
* internally linking to /my-new-website/, which does not exist (line 21)
<a class="site-title" rel="author" href="/my-new-website/">Your awesome title</a>
* internally linking to /my-new-website/about/, which does not exist (line 31)
<a class="page-link" href="/my-new-website/about/">About</a>
* internally linking to /my-new-website/assets/main.css, which does not exist (line 18)
<link rel="stylesheet" href="/my-new-website/assets/main.css">
- docs/about/index.html
* internally linking to /my-new-website/, which does not exist (line 21)
<a class="site-title" rel="author" href="/my-new-website/">Your awesome title</a>
* internally linking to /my-new-website/about/, which does not exist (line 31)
<a class="page-link" href="/my-new-website/about/">About</a>
* internally linking to /my-new-website/assets/main.css, which does not exist (line 18)
<link rel="stylesheet" href="/my-new-website/assets/main.css">
- docs/index.html
* internally linking to /my-new-website/, which does not exist (line 21)
<a class="site-title" rel="author" href="/my-new-website/">Your awesome title</a>
* internally linking to /my-new-website/about/, which does not exist (line 31)
<a class="page-link" href="/my-new-website/about/">About</a>
* internally linking to /my-new-website/assets/main.css, which does not exist (line 18)
<link rel="stylesheet" href="/my-new-website/assets/main.css">
* internally linking to /my-new-website/feed.xml, which does not exist (line 46)
<a href="/my-new-website/feed.xml">via RSS</a>
* internally linking to /my-new-website/jekyll/update/2020/07/22/welcome-to-jekyll.html, which does not exist (line 41)
<a class="post-link" href="/my-new-website/jekyll/update/2020/07/22/welcome-to-jekyll.html">
Welcome to Jekyll!
</a>
- docs/jekyll/update/2020/07/22/welcome-to-jekyll.html
* internally linking to /my-new-website/, which does not exist (line 23)
<a class="site-title" rel="author" href="/my-new-website/">Your awesome title</a>
* internally linking to /my-new-website/about/, which does not exist (line 33)
<a class="page-link" href="/my-new-website/about/">About</a>
* internally linking to /my-new-website/assets/main.css, which does not exist (line 20)
<link rel="stylesheet" href="/my-new-website/assets/main.css">
* internally linking to /my-new-website/jekyll/update/2020/07/22/welcome-to-jekyll.html, which does not exist (line 67)
<a class="u-url" href="/my-new-website/jekyll/update/2020/07/22/welcome-to-jekyll.html" hidden=""></a>
htmlproofer 3.15.3 | Error: HTML-Proofer found 15 failures!
We see that the htmlproofer fails because it expects all files to be in our baseurl
subdirectory my-new-website
. This is exactly the place it lives in our live site, so we make it happy by moving everything into that subfolder and run it again.
development/websites/my-new-website
▶ mv docs docs2 && mkdir docs && mv docs2 docs/my-new-website
development/websites/my-new-website
▶ bundler exec htmlproofer docs
Running ["ImageCheck", "LinkCheck", "ScriptCheck"] on ["docs"] on *.html...
Checking 12 external links...
Ran on 4 files!
HTML-Proofer finished successfully
That looks good.
Let’s setup the test in the Travis CI build
We add the HTML Proofer call to our .travis.yml
with the lesson learned that we also need to create the subdirectory in the docs folder. We create a test docs folder called docs_test
and remove it when we are done
# .travis.yml
...
script:
- JEKYLL_ENV="production" bundle exec jekyll build
- cp -a docs docs2 && mkdir docs_test && mv docs2 docs_test/my-new-website
- bundle exec htmlproofer docs_test
- rm -rf docs_test
To speed up the installation of HTML-Proofer we also set the global variable NOKOGIRI_USE_SYSTEM_LIBRARIES=true
and adding the appropriate addon for fetching with libcurl
# .travis.yml
...
env:
global:
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
- secure: fpXV7C9QagH87UQLu...
addons:
apt:
packages:
- libcurl4-openssl-dev
The updated .travis.yml
file
After those changes your .travis.yml
should looks similar to:
language: ruby
rvm:
- 2.6.3
dist: trusty
sudo: false
cache: bundler
notifications:
email: false
install:
- bundle install
script:
- JEKYLL_ENV="production" bundle exec jekyll build
- cp -a docs docs2 && mkdir docs_test && mv docs2 docs_test/my-new-website
- bundle exec htmlproofer docs_test
- rm -rf docs_test
deploy:
provider: script
script: bash script/deploy.sh
skip_cleanup: true
on:
tags: true
branch: staging
branches:
only:
- staging
- "/\\d+\\.\\d+(\\.\\d+)?(-\\S*)?$/"
env:
global:
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true # speeds up installation of html-proofer
- secure: fpXV7C9QagH87UQLu...
addons:
apt:
packages:
- libcurl4-openssl-dev
Let’s run the build
We are adding our changes to git and push to start the build
development/websites/my-new-website
▶ git status
On branch staging
Your branch is up to date with 'origin/staging'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: .travis.yml
modified: Gemfile
modified: index.markdown
no changes added to commit (use "git add" and/or "git commit -a")
▶ git add . && git commit -m"setup html proofer" && git push
Now we head over to this Travis CI build and have a look what happens
Great, that worked well.
Conclusion
We setup an automated test that ensures the validity of our output with HTML Proofer. If any issue is found, the build will fail and we don’t push broken html to our website.