From 2dd00e74a5575ddd921015e12f22511a2bb19a93 Mon Sep 17 00:00:00 2001 From: Jaysinh Shukla Date: Thu, 6 Aug 2026 21:27:00 +0530 Subject: [PATCH] Audit SEO automatically with Lighthouse CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #35 asks for an open source tool that tests SEO appropriateness, for that tool to run periodically, and only then for the code to be improved according to what it reports. This does the first three and acts on the findings of the fourth. Lighthouse is the tool. `.lighthouserc.json` runs its SEO category against seven representative pages — the homepage, about, the tag index, one tag page, two posts and a post under the book/review categories — and asserts a perfect category score. A new workflow runs it on every pull request and on a weekly cron, since search engines change what they reward without any commit on our side. Three things this turned up while being set up. The audit has to build the way pages.yml does. A development build has no `site.url`, which leaves `rel=canonical` relative and robots.txt without a sitemap line; Lighthouse scored those pages 0.83 while production scored 100. The workflow therefore builds with the production config. Autodiscovery is not enough. Pointed at `_site` it collects `index.html` files only, so all twelve posts — the pages whose SEO actually matters — went unaudited. The URLs are listed explicitly instead. Listing post URLs meant pinning the timezone. Jekyll derives permalinks from the post date in local time, so `2019-01-13 01:23:12 +0530` builds to /2019/01/12/ on a UTC runner and /2019/01/13/ on a machine in IST. The same commit produced different URLs depending on where it was built. Setting `timezone: UTC` makes local builds agree with CI; all twelve live post URLs were checked against the deployed site and none of them change. The audit then reported two links whose text does not describe the target, "this" and "here". Both are reworded, which brings every audited page to 100. Closes #35 Co-Authored-By: Claude Opus 5 --- .github/workflows/lighthouse.yml | 52 +++++++++++++++++++ .gitignore | 3 ++ .lighthouserc.json | 29 +++++++++++ _config.yml | 5 ++ ...-review-introduction-to-the-commandline.md | 3 +- ...19-01-13-python-3-7-feature-walkthrough.md | 6 +-- 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/lighthouse.yml create mode 100644 .lighthouserc.json diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml new file mode 100644 index 0000000..69bd23b --- /dev/null +++ b/.github/workflows/lighthouse.yml @@ -0,0 +1,52 @@ +name: SEO audit + +on: + pull_request: + branches: + - master + schedule: + # Mondays at 06:00 UTC. Search engines change what they reward without any + # commit on our side, so the audit runs on a timer as well as per change. + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + lighthouse: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Ruby + uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb # v1.257.0 + with: + ruby-version: "3.2.0" + bundler-cache: true + + # Built exactly as pages.yml builds it. A development build has no + # site.url, which leaves rel=canonical relative and robots.txt without a + # sitemap line, and Lighthouse fails both of those on a site that is + # actually fine in production. + - name: Build site + env: + JEKYLL_ENV: production + run: bundle exec jekyll build --config _config.yml,_config_production.yml + + - name: Set up Node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "22" + + - name: Run Lighthouse CI + run: npx --yes @lhci/cli@0.14.x autorun --config=.lighthouserc.json + + - name: Upload Lighthouse reports + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: lighthouse-reports + path: .lighthouseci/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 87fe7c0..1997390 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ _site .sass-cache .jekyll-metadata +# lighthouse-ci report output +.lighthouseci + # vim wap [._]*.s[a-v][a-z] diff --git a/.lighthouserc.json b/.lighthouserc.json new file mode 100644 index 0000000..ba5b5d2 --- /dev/null +++ b/.lighthouserc.json @@ -0,0 +1,29 @@ +{ + "ci": { + "collect": { + "staticDistDir": "./_site", + "url": [ + "http://localhost/index.html", + "http://localhost/about/index.html", + "http://localhost/tags/index.html", + "http://localhost/tags/python/index.html", + "http://localhost/2019/01/12/python-3-7-feature-walkthrough.html", + "http://localhost/2017/08/28/how_to_repair_a_broken_grub_in_ubuntu.html", + "http://localhost/book/review/2017/02/28/book-review-introduction-to-the-commandline.html" + ], + "numberOfRuns": 1, + "settings": { + "onlyCategories": ["seo"] + } + }, + "assert": { + "assertions": { + "categories:seo": ["error", { "minScore": 1 }] + } + }, + "upload": { + "target": "filesystem", + "outputDir": "./.lighthouseci" + } + } +} diff --git a/_config.yml b/_config.yml index 42e7932..a1a373c 100644 --- a/_config.yml +++ b/_config.yml @@ -26,6 +26,11 @@ twitter_username: jaysinhp github_username: ultimatecoder # Build settings +# Build in UTC so a local build produces the same post URLs as CI, which +# runs in UTC. Without this the same commit yields different permalinks +# depending on the machine timezone. +timezone: UTC + markdown: kramdown theme: minima plugins: diff --git a/_posts/2017-02-28-book-review-introduction-to-the-commandline.md b/_posts/2017-02-28-book-review-introduction-to-the-commandline.md index 2a95205..cfe9741 100644 --- a/_posts/2017-02-28-book-review-introduction-to-the-commandline.md +++ b/_posts/2017-02-28-book-review-introduction-to-the-commandline.md @@ -118,7 +118,8 @@ should be `args=$1`. I myself has corrected the typographical error in the book. This change will be published maybe in the next release of this book. If you are encountering any mistakes while reading, I request you to fix the -change [here](http://write.flossmanuals.net/command-line/introduction/). The +change in [the FLOSS Manuals editing +interface](http://write.flossmanuals.net/command-line/introduction/). The interface for editing the book is beginner friendly. It took less than 5 minutes to drive the change. diff --git a/_posts/2019-01-13-python-3-7-feature-walkthrough.md b/_posts/2019-01-13-python-3-7-feature-walkthrough.md index b0ab101..75436cf 100644 --- a/_posts/2019-01-13-python-3-7-feature-walkthrough.md +++ b/_posts/2019-01-13-python-3-7-feature-walkthrough.md @@ -169,9 +169,9 @@ migrate to the hash-based approach. I hope you were able to learn something new by reading this post. If you want to read an in-depth discussion on each feature introduced in Python 3.7, then -please read -[this](https://docs.python.org/3.7/whatsnew/changelog.html#python-3-7-0-final) -official post. Happy hacking! +please read the +[official Python 3.7 changelog](https://docs.python.org/3.7/whatsnew/changelog.html#python-3-7-0-final). +Happy hacking! ###### Proofreaders: [Jason Braganza](https://janusworx.com/), Ninpo, basen_ from #python at Freenode, Ultron from #python-offtopic at Freenode, up|ime from ##English at Freenode