From 80a8826ba9753fe9c2a6d3aa78dab48f4801dcff Mon Sep 17 00:00:00 2001 From: Martin Costello Date: Sat, 10 Feb 2024 19:38:36 +0000 Subject: [PATCH] Upgrade to Middleman v4 (#111) - Upgrade to version 4 of Middleman. - Simplify the site settings. - Delete files not used since migration from Azure App Service. --- .github/workflows/build.yml | 6 +- Gemfile | 29 +- Gemfile.lock | 228 ++++--- build.ps1 | 2 +- config.rb | 88 +-- ...ng-your-asp-net-website-is-secure.html.md} | 0 ...tched-from-wordpress-to-middleman.html.md} | 592 +++++++++--------- ...11-30-this-blog-is-now-opensource.html.md} | 0 ...-js.md => 2016-10-10-apple-pay-js.html.md} | 0 ...owserstack-automate-api-client-v2.html.md} | 0 ...0-publishing-my-first-alexa-skill.html.md} | 0 ...17-08-28-migrating-from-iis-to-s3.html.md} | 0 ...egrations-in-a-dotnet-application.html.md} | 0 ...roductivity-and-performance-gains.html.md} | 0 ...ure-static-websites-with-appveyor.html.md} | 0 ...writing-logs-to-xunit-test-output.html.md} | 0 ...2018-10-02-sql-localdb-wrapper-v2.html.md} | 0 ...7-aspnet-core-pseudo-localization.html.md} | 0 ...h-apple-prototype-for-aspnet-core.html.md} | 0 ...-06-16-refit-and-system-text-json.html.md} | 0 ...lambda-with-dotnet-custom-runtime.html.md} | 0 ...ntiforgery-with-application-parts.html.md} | 0 ...ces-gotchas-with-aspnetcore-oauth.html.md} | 0 ...ors-with-aspnet-core-minimal-apis.html.md} | 0 ...ng-to-dotnet-8-part-1-why-upgrade.html.md} | 0 ...8-part-2-automation-is-our-friend.html.md} | 0 ...o-dotnet-8-part-3-previews-1-to-5.html.md} | 0 ...ding-to-dotnet-8-part-4-preview-6.html.md} | 0 ...net-8-part-5-preview-7-and-rc-1-2.html.md} | 0 ...to-dotnet-8-part-6-stable-release.html.md} | 0 ...ive-aot-make-dotnet-lambda-go-brr.html.md} | 0 source/_facebookmeta.erb | 2 +- source/_footer.erb | 4 +- source/_head.erb | 18 +- source/_microsoft.erb | 2 +- source/_navbar.erb | 2 +- source/_opengraph.erb | 12 +- source/_scripts.erb | 4 +- source/_social.erb | 2 +- source/_twittermeta.erb | 16 +- source/about-me.html.erb | 4 +- source/archive.html.erb | 4 +- source/feed.xml.builder | 12 +- source/hostingstart.html | 1 - source/humans.txt.erb | 4 +- source/index.html.erb | 8 +- source/layouts/bloglayout.erb | 4 +- source/parameters.xml | 7 - source/robots.txt.erb | 2 +- source/scripts/site.js.erb | 4 +- source/sitemap.xml.builder | 4 +- 51 files changed, 485 insertions(+), 576 deletions(-) rename source/{2014-03-04-ensuring-your-asp-net-website-is-secure.md => 2014-03-04-ensuring-your-asp-net-website-is-secure.html.md} (100%) rename source/{2015-06-18-why-i-switched-from-wordpress-to-middleman.md => 2015-06-18-why-i-switched-from-wordpress-to-middleman.html.md} (98%) rename source/{2015-11-30-this-blog-is-now-opensource.md => 2015-11-30-this-blog-is-now-opensource.html.md} (100%) rename source/{2016-10-10-apple-pay-js.md => 2016-10-10-apple-pay-js.html.md} (100%) rename source/{2016-10-18-browserstack-automate-api-client-v2.md => 2016-10-18-browserstack-automate-api-client-v2.html.md} (100%) rename source/{2017-02-20-publishing-my-first-alexa-skill.md => 2017-02-20-publishing-my-first-alexa-skill.html.md} (100%) rename source/{2017-08-28-migrating-from-iis-to-s3.md => 2017-08-28-migrating-from-iis-to-s3.html.md} (100%) rename source/{2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.md => 2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.html.md} (100%) rename source/{2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.md => 2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.html.md} (100%) rename source/{2018-06-30-azure-static-websites-with-appveyor.md => 2018-06-30-azure-static-websites-with-appveyor.html.md} (100%) rename source/{2018-09-30-writing-logs-to-xunit-test-output.md => 2018-09-30-writing-logs-to-xunit-test-output.html.md} (100%) rename source/{2018-10-02-sql-localdb-wrapper-v2.md => 2018-10-02-sql-localdb-wrapper-v2.html.md} (100%) rename source/{2018-12-17-aspnet-core-pseudo-localization.md => 2018-12-17-aspnet-core-pseudo-localization.html.md} (100%) rename source/{2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.md => 2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.html.md} (100%) rename source/{2019-06-16-refit-and-system-text-json.md => 2019-06-16-refit-and-system-text-json.html.md} (100%) rename source/{2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.md => 2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.html.md} (100%) rename source/{2020-06-16-integration-testing-antiforgery-with-application-parts.md => 2020-06-16-integration-testing-antiforgery-with-application-parts.html.md} (100%) rename source/{2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.md => 2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.html.md} (100%) rename source/{2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.md => 2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.html.md} (100%) rename source/{2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.md => 2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.html.md} (100%) rename source/{2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.md => 2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.html.md} (100%) rename source/{2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.md => 2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.html.md} (100%) rename source/{2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.md => 2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.html.md} (100%) rename source/{2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.md => 2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.html.md} (100%) rename source/{2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.md => 2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.html.md} (100%) rename source/{2023-11-29-native-aot-make-dotnet-lambda-go-brr.md => 2023-11-29-native-aot-make-dotnet-lambda-go-brr.html.md} (100%) delete mode 100644 source/hostingstart.html delete mode 100644 source/parameters.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1dd7105..f380bd4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,13 +30,13 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7 + ruby-version: 3.3 - name: Build blog shell: pwsh run: | - bundle config path vendor/bundle - bundle install + bundler config path vendor/bundle + bundler install ./build.ps1 - name: Publish blog diff --git a/Gemfile b/Gemfile index 1a277f4..4a5ca76 100644 --- a/Gemfile +++ b/Gemfile @@ -1,24 +1,21 @@ source 'https://rubygems.org' -gem "bundler", "~> 1.17.3" -gem "haml", "~> 5.2.2" -gem "middleman", "~> 3.4.1" -gem "middleman-blog", "~> 3.5.3" +gem "bundler", "~> 2.5.6" +gem "haml", "~> 6.3.0" +gem "middleman", "~> 4.5.1" +gem 'middleman-autoprefixer', '~> 3.0.0' +gem "middleman-blog", "~> 4.0.3" +gem "middleman-livereload", "~> 3.4.7" gem "middleman-minify-html", "~> 3.4.1" -gem "middleman-syntax", "~> 3.3.0" +gem "middleman-syntax", "~> 3.4.0" +gem "nokogiri", "~> 1.16.2" +gem 'terser', '~> 1.2.0' # For feed.xml.builder -gem "builder", "~> 3.0" +gem "builder", "~> 3.2.4" -# Live-reloading plugin -gem "middleman-livereload", "~> 3.4.6" - -# Windows does not come with time zone data -gem "tzinfo-data" - -# For faster file watcher updates on Windows: -gem 'wdm', '~> 0.1.0' if Gem.win_platform? +gem "tzinfo-data", "~> 1.2024.1", platforms: [:mswin, :mingw, :jruby, :x64_mingw] +gem 'wdm', '~> 0.1.1', platforms: [:mswin, :mingw, :x64_mingw] +gem "rack", "~> 2.2.8" gem "redcarpet", "~> 3.6.0" - -gem "rack", "~> 1.6.11" diff --git a/Gemfile.lock b/Gemfile.lock index 6732340..ac62ac6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,84 +1,90 @@ GEM remote: https://rubygems.org/ specs: - activesupport (4.2.11.3) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.3.8) + activesupport (7.0.8) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) + autoprefixer-rails (10.4.16.0) + execjs (~> 2) + backports (3.24.1) builder (3.2.4) - capybara (2.4.4) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - chunky_png (1.4.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.12.2) - compass (1.0.3) - chunky_png (~> 1.2) - compass-core (~> 1.0.2) - compass-import-once (~> 1.0.5) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - sass (>= 3.3.13, < 3.5) - compass-core (1.0.3) - multi_json (~> 1.0) - sass (>= 3.3.0, < 3.5) - compass-import-once (1.0.5) - sass (>= 3.2, < 3.5) + concurrent-ruby (1.2.3) + contracts (0.16.1) + dotenv (2.8.1) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) erubis (2.7.0) eventmachine (1.2.7) - execjs (2.8.1) - ffi (1.15.5) - haml (5.2.2) - temple (>= 0.8.0) + execjs (2.9.1) + fast_blank (1.0.1) + fastimage (2.3.0) + ffi (1.16.3) + haml (6.3.0) + temple (>= 0.8.2) + thor tilt - hike (1.2.3) - hooks (0.4.1) - uber (~> 0.0.14) + hamster (3.0.0) + concurrent-ruby (~> 1.0) + hashie (3.6.0) htmlcompressor (0.2.0) http_parser.rb (0.8.0) - i18n (0.7.0) - json (2.6.3) - kramdown (1.17.0) - listen (3.0.8) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - middleman (3.4.1) + i18n (1.6.0) + concurrent-ruby (~> 1.0) + kramdown (2.4.0) + rexml + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + memoist (0.16.2) + middleman (4.5.1) coffee-script (~> 2.2) - compass (>= 1.0.0, < 2.0.0) - compass-import-once (= 1.0.5) - execjs (~> 2.0) haml (>= 4.0.5) - kramdown (~> 1.2) - middleman-core (= 3.4.1) - middleman-sprockets (>= 3.1.2) - sass (>= 3.4.0, < 4.0) - uglifier (~> 2.5) - middleman-blog (3.5.3) - addressable (~> 2.3.5) - middleman-core (~> 3.2) + kramdown (>= 2.3.0) + middleman-cli (= 4.5.1) + middleman-core (= 4.5.1) + middleman-autoprefixer (3.0.0) + autoprefixer-rails (~> 10.0) + middleman-core (>= 4.0.0) + middleman-blog (4.0.3) + addressable (~> 2.3) + middleman-core (>= 4.0.0) tzinfo (>= 0.3.0) - middleman-core (3.4.1) - activesupport (~> 4.1) - bundler (~> 1.1) - capybara (~> 2.4.4) + middleman-cli (4.5.1) + thor (>= 0.17.0, < 1.3.0) + middleman-core (4.5.1) + activesupport (>= 6.1, < 7.1) + addressable (~> 2.4) + backports (~> 3.6) + bundler (~> 2.0) + contracts (~> 0.13, < 0.17) + dotenv erubis - hooks (~> 0.3) - i18n (~> 0.7.0) - listen (~> 3.0.3) - padrino-helpers (~> 0.12.3) - rack (>= 1.4.5, < 2.0) - thor (>= 0.15.2, < 2.0) - tilt (~> 1.4.1, < 2.0) + execjs (~> 2.0) + fast_blank + fastimage (~> 2.0) + hamster (~> 3.0) + hashie (~> 3.4) + i18n (~> 1.6.0) + listen (~> 3.0) + memoist (~> 0.14) + padrino-helpers (~> 0.15.0) + parallel + rack (>= 1.4.5, < 3) + sassc (~> 2.0) + servolux + tilt (~> 2.0.9) + toml + uglifier (~> 3.0) + webrick middleman-livereload (3.4.7) em-websocket (~> 0.5.1) middleman-core (>= 3.3) @@ -86,81 +92,65 @@ GEM middleman-minify-html (3.4.1) htmlcompressor (~> 0.2.0) middleman-core (>= 3.2) - middleman-sprockets (3.5.0) - middleman-core (>= 3.3) - sprockets (~> 2.12.1) - sprockets-helpers (~> 1.1.0) - sprockets-sass (~> 1.3.0) - middleman-syntax (3.3.0) + middleman-syntax (3.4.0) middleman-core (>= 3.2) rouge (~> 3.2) - mime-types (3.4.1) - mime-types-data (~> 3.2015) - mime-types-data (3.2023.0218.1) - mini_portile2 (2.8.2) - minitest (5.18.0) - multi_json (1.15.0) - nokogiri (1.15.0) - mini_portile2 (~> 2.8.2) + minitest (5.22.2) + nokogiri (1.16.2-x86_64-linux) racc (~> 1.4) - padrino-helpers (0.12.9) - i18n (~> 0.6, >= 0.6.7) - padrino-support (= 0.12.9) + padrino-helpers (0.15.3) + i18n (>= 0.6.7, < 2) + padrino-support (= 0.15.3) tilt (>= 1.4.1, < 3) - padrino-support (0.12.9) - activesupport (>= 3.1) - racc (1.6.2) - rack (1.6.13) + padrino-support (0.15.3) + parallel (1.24.0) + parslet (2.0.0) + public_suffix (5.0.4) + racc (1.7.3) + rack (2.2.8) rack-livereload (0.3.17) rack - rack-test (2.1.0) - rack (>= 1.3) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) redcarpet (3.6.0) + rexml (3.2.6) rouge (3.30.0) - sass (3.4.25) - sprockets (2.12.5) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-helpers (1.1.0) - sprockets (~> 2.0) - sprockets-sass (1.3.1) - sprockets (~> 2.0) - tilt (~> 1.1) - temple (0.10.1) + sassc (2.4.0) + ffi (~> 1.9) + servolux (0.13.0) + temple (0.10.3) + terser (1.2.0) + execjs (>= 0.3.0, < 3) thor (1.2.2) - thread_safe (0.3.6) - tilt (1.4.1) - tzinfo (1.2.11) - thread_safe (~> 0.1) - tzinfo-data (1.2024.1) - tzinfo (>= 1.0.0) - uber (0.0.15) - uglifier (2.7.2) - execjs (>= 0.3.0) - json (>= 1.8.0) - xpath (2.1.0) - nokogiri (~> 1.3) + tilt (2.0.11) + toml (0.3.0) + parslet (>= 1.8.0, < 3.0.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uglifier (3.2.0) + execjs (>= 0.3.0, < 3) + webrick (1.8.1) PLATFORMS - ruby + x86_64-linux DEPENDENCIES - builder (~> 3.0) - bundler (~> 1.17.3) - haml (~> 5.2.2) - middleman (~> 3.4.1) - middleman-blog (~> 3.5.3) - middleman-livereload (~> 3.4.6) + builder (~> 3.2.4) + bundler (~> 2.5.6) + haml (~> 6.3.0) + middleman (~> 4.5.1) + middleman-autoprefixer (~> 3.0.0) + middleman-blog (~> 4.0.3) + middleman-livereload (~> 3.4.7) middleman-minify-html (~> 3.4.1) - middleman-syntax (~> 3.3.0) - rack (~> 1.6.11) + middleman-syntax (~> 3.4.0) + nokogiri (~> 1.16.2) + rack (~> 2.2.8) redcarpet (~> 3.6.0) - tzinfo-data + terser (~> 1.2.0) + tzinfo-data (~> 1.2024.1) + wdm (~> 0.1.1) BUNDLED WITH - 1.17.3 + 2.5.6 diff --git a/build.ps1 b/build.ps1 index e2389bd..4cae9a0 100755 --- a/build.ps1 +++ b/build.ps1 @@ -6,7 +6,7 @@ git rev-parse HEAD > version.txt git rev-parse --abbrev-ref HEAD > branch.txt -bundle exec middleman build +bundler exec middleman build if ($LASTEXITCODE -ne 0) { Write-Host "middleman build failed with exit code $LASTEXITCODE" diff --git a/config.rb b/config.rb index 1442c46..7ff3f6e 100644 --- a/config.rb +++ b/config.rb @@ -1,102 +1,40 @@ -### -# Blog settings -### +activate :autoprefixer do |prefix| + prefix.browsers = "last 2 versions" +end + +page "/*.json", layout: false +page "/*.txt", layout: false +page "/*.xml", layout: false Time.zone = "UTC" activate :blog do |blog| - blog.permalink = "{title}" - blog.sources = "{year}-{month}-{day}-{title}.html" - blog.taglink = "tags/{tag}.html" - # blog.layout = "layout" - blog.summary_separator = /(READMORE)/ - blog.summary_length = 250 - blog.year_link = "{year}.html" - blog.month_link = "{year}/{month}.html" - blog.day_link = "{year}/{month}/{day}.html" blog.default_extension = ".md" - blog.tag_template = "tag.html" blog.calendar_template = "calendar.html" - - # Enable pagination - # blog.paginate = true - # blog.per_page = 10 - # blog.page_link = "page/{num}" end activate :directory_indexes -page "/feed.xml", layout: false page "/humans.txt", layout: false, :directory_index => false -page "/hostingstart.html", layout: false, :directory_index => false page "/robots.txt", layout: false, :directory_index => false -page "/sitemap.xml", layout: false - -### -# Compass -### - -# Change Compass configuration -# compass_config do |config| -# config.output_style = :compact -# end - -### -# Page options, layouts, aliases and proxies -### - -# Per-page layout changes: -# -# With no layout -# page "/path/to/file.html", :layout => false -# -# With alternative layout -# page "/path/to/file.html", :layout => :otherlayout -# -# A path which all have the same layout -# with_layout :admin do -# page "/admin/*" -# end -# Proxy pages (https://middlemanapp.com/advanced/dynamic_pages/) -# proxy "/this-page-has-no-template.html", "/template-file.html", :locals => { -# :which_fake_page => "Rendering a fake page with a local variable" } - -### -# Helpers -### - -# Automatic image dimensions on image_tag helper -# activate :automatic_image_sizes - -# Reload the browser automatically whenever files change configure :development do - # activate :livereload + activate :livereload set :site_root_uri, "https://localhost/" set :render_analytics, false end -# Methods defined in the helpers block are available in templates -# helpers do -# def some_helper -# "Helping" -# end -# end - set :css_dir, 'styles' - set :js_dir, 'scripts' - set :images_dir, 'images' -# Build-specific configuration configure :build do activate :minify_html, remove_input_attributes: false activate :minify_css - activate :minify_javascript + activate :minify_javascript, compressor: Terser.new activate :gzip activate :asset_hash @@ -104,18 +42,10 @@ set :render_analytics, true end -## -# Syntax Configuration -## - activate :syntax set :markdown_engine, :redcarpet set :markdown, :fenced_code_blocks => true -## -# Custom Configuration -## - set :cdn_domain, "cdn.martincostello.com" set :site_domain, "blog.martincostello.com" set :site_root_uri_canonical, "https://blog.martincostello.com/" diff --git a/source/2014-03-04-ensuring-your-asp-net-website-is-secure.md b/source/2014-03-04-ensuring-your-asp-net-website-is-secure.html.md similarity index 100% rename from source/2014-03-04-ensuring-your-asp-net-website-is-secure.md rename to source/2014-03-04-ensuring-your-asp-net-website-is-secure.html.md diff --git a/source/2015-06-18-why-i-switched-from-wordpress-to-middleman.md b/source/2015-06-18-why-i-switched-from-wordpress-to-middleman.html.md similarity index 98% rename from source/2015-06-18-why-i-switched-from-wordpress-to-middleman.md rename to source/2015-06-18-why-i-switched-from-wordpress-to-middleman.html.md index 09d09a6..f95c622 100644 --- a/source/2015-06-18-why-i-switched-from-wordpress-to-middleman.md +++ b/source/2015-06-18-why-i-switched-from-wordpress-to-middleman.html.md @@ -1,296 +1,296 @@ ---- -title: Why I Switched From WordPress To Middleman -date: 2015-06-18 -tags: blogging,middleman,wordpress -layout: bloglayout -description: "Why I switched from using WordPress to the Middleman static site generator for writing my blog." ---- - -A few years ago I thought I'd set up a blog. Initially I created a blog in [Blogspot](http://martincostello.blogspot.co.uk/) but I decided some time later that I'd rather host it myself with custom DNS, etc., mainly as a learning exercise. As I'm mostly a developer in the Microsoft stack, I decided I'd set it up in Windows Azure as an Azure Website (now a "Microsoft Azure Web App") as that was something I knew of and knew a little about. A few clicks through a wizard later and I had a WordPress blog running in Azure, backed by a MySQL database. Great - time to get blogging! - -Flash-foward a few years, and I had a sum total of [one solitary blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/). Yeah, so I'd been a bit slack on the whole writing a blog thing. However I've got an idea for a second blog post that I've been procrastinating over writing for a while, so I thought I'd start on that (aside: this isn't that blog post, that's coming soon). By this point I'd grown two different Azure subscriptions and the blog was running in the wrong one and I was starting to hit limits on my free Azure credits due to other usage, so I figured I'd switch it around. The problems begin. - -READMORE - -## Problems, Problems, Problems - -So the first problem was that the MySQL database that Azure automatically provisioned for me when the WordPress blog was initially provisioned is through a third-party provider. I had no idea where this was, but eventually through some clicking of buried-away links in the Azure portal I found a link through to the third-party portal for the database. It was then that I discovered that the database was on a free tier with a paltry 20MB maximum size. 20MB seemed a bit pathetic considering with one post I'd already used 15MB, and I already wanted to move the database to a different subscription so why remove the limit and start paying more? So how do you move a MySQL database from one subscription to another? I don't know, I never found out - more on this later. - -The next hurdle was that I'm not really au-fait with MySQL management given I'm a Microsoft/Windows guy, and if I'm honest I wasn't particularly inclined to learn to do so either. Microsoft have been pushing for SQL Server interoperability with PHP (which WordPress is written in) for [a while](http://blogs.technet.com/b/dataplatforminsider/archive/2014/11/06/available-today-preview-release-of-the-sql-server-php-driver.aspx) so I thought why not migrate to use SQL Server as the data store instead? That way I can host a SQL database (which I know how to do) in Azure in the right subscription and point WordPress at that instead. There's [PHP drivers for SQL Server](https://msdn.microsoft.com/en-us/data/ff657782.aspx) now and a [WordPress plugin](https://wordpress.org/plugins/wordpress-database-abstraction/) for using SQL Server as well? Microsoft have even [blogged about](http://blogs.msdn.com/b/brian_swan/archive/2010/05/12/running-wordpress-on-sql-server.aspx) how to do it, so it can't be that hard, right? **Wrong** as I was about to discover. - -## The Abortive Attempt To Use SQL Server - -Migrating to SQL Server it is then. Let's get started. Step one: where the hell is the website source? - -As everything had been set up for me in the Azure wizard, I'd never actually seen the website source itself ever. Better get it then, which is pretty simple. I just had to FTP into the IIS website's directory in Azure and pull it out. - -Great I've got the source, now what do I do? Well I better put it in source control somewhere before I start tinkering. That way I can rollback if I mess everything up, plus I can setup a test slot somewhere where I can do testing without worrying about screwing up my "production" MySQL database. Azure has a nice [deploy from Git workflow](https://azure.microsoft.com/en-gb/documentation/articles/web-sites-publish-source-control/) so I'll go with a Git repo to look after it. There's some private configuration data for the site to run in Azure though (like connection strings) so I don't want it publicly available. GitHub don't allow private repositories for free but Visual Studio Online is always private, supports Git and is [free for up to 5 users](https://www.visualstudio.com/en-us/products/visual-studio-online-pricing-vs.aspx). I'm only one person, so great, sounds like the perfect fit. I'll get all the code checked in and branch and get to work then. - -Cue montage of trying to get it to work to the theme of Murder She Wrote. I'll let this selection of tweets show you some highlights of the journey: - -

PHP confuses me.

— Martin Costello (@martin_costello) February 8, 2015
- - -

On reflection, staying up until 3am messing about with PHP wasn't the best idea.

— Martin Costello (@martin_costello) February 9, 2015
- -

Now, can I solve this PHP mystery in 25 minutes before I have to go out? *Cue Mission:Impossible theme*

— Martin Costello (@martin_costello) February 9, 2015
- -

Computers: the source of my income and maybe also a killing spree in the imminent future.

— Martin Costello (@martin_costello) February 11, 2015
- -## Mission: Failed - -As you can see, I gave up. The main problems and reasons being: - - 1. The WordPress plug-in was out-of-date (2 years+ since the last update) and didn't work properly with my version of WordPress; - 1. The SQL Server PHP drivers didn't seem to want to run on PHP 5.5. After much banging my head against the wall I discovered that not only did they work fine with PHP 5.4, but also that the PHP drivers were already installed in Azure Websites meaning that lots of playing around trying to find the right binaries and get them to load were pointless; - 1. I could not work out how to import the MySQL data in SQL Server successfully without violating unique constraints and/or losing data integrity. - -## A Change Of Tack - -After the WordPress/SQL Server debacle I went into hibernation on the whole blog situation for a few months until this week. I'd seen various chatter here and there over the last few months about static site generators, so I wondered whether that would be a viable option. So I issued this tweet: - -

NERDS: recommend me a static site generator. I want to replace a WordPress blog that has fuck-all in it.

— Martin Costello (@martin_costello) June 15, 2015
- -I didn't get my useful feedback from my followers, so I went to our friend Google. It led me to the following two links: - - 1. [Static Site Generators](https://staticsitegenerators.net/) - Just a big list, not very helpful; - 1. [StaticGen](https://www.staticgen.com/) - A much better curated list, ranked by the projects' GitHub star counts. - -The main one that lept out was [Jekyll](http://jekyllrb.com/) as I'd heard of it before and GitHub uses it to generate GitHub pages sites. However not long afterwards I discovered that [Jekyll doesn't officially support Windows](http://jekyllrb.com/docs/windows/). I'm mainly a Windows guy, and even though I have an Ubuntu VM in Hyper-V on my laptop, I'd rather stick with the environment and tools I know. There are [guides for getting it to work on Windows](http://jekyll-windows.juthilo.com/), but as my heart wasn't set on Jekyll and I'd rather use something supported, so I ruled it out of the running. - -Cue some head-scratching, after which I did some further googling and found [this post by Scott Hanselman](http://www.hanselman.com/blog/RunningTheRubyMiddlemanStaticSiteGeneratorOnMicrosoftAzure.aspx). [Middleman](https://middlemanapp.com/) was in the second row on [StaticGen](https://www.staticgen.com/). Interesting... - -Having read Scott's article, I summised that Middleman worked on Windows, and would work in Azure (it's a static site I know, but good to know the workflow has been tried and tested by someone else). The article is mostly about getting the site to *build* on Azure, which **for now** I'm not interested in. That's a nice to have I can do in the future (it's on my VS Online backlog in fact), but at the time I just wanted the site - I can deploy it via FTP in the short-term. - -## Getting To Grips With Middleman - -Reading the [Middleman](https://middlemanapp.com/basics/install/) documentation things seemed straight-forward: - - 1. HTML templating from HTML and Markdown to HTML; - 1. Builds with Ruby; - 1. Generates a static site ready for deployment. - -As ever, I steamed right ahead and got stuck in, having not *thoroughly* read the documentation (like most developers). I had a site template, and it built. Great. - -Now how do you write a blog with it? - -It turns out (having read the documentation again *properly*) that Middleman has a [blog plug-in](https://middlemanapp.com/basics/blogging/). Huzzah! - -More digging around in the generated code shows the following blog features: - - 1. Archiving; - 1. Tags; - 1. Atom Feed; - 1. XML site map. - -This all looks very encouraging. In fact, this level of encouraging: - -

Found using the Middleman static site generator surprisingly easy to get to grips with. Wordpress: your days are numbered...

— Martin Costello (@martin_costello) June 16, 2015
- -## Implementing The Blog - -So over the course of the next two evenings I set about in earnest migrating over from WordPress to Middleman. It involved a number of steps, and probably took about 10 hours' of effort in total. It was a mixture of migration, feature parity and some new features I fancied adding in because I was giving the blog some love so would be a good opportunity. I hadn't set myself a timescale or deadline for completing the work, but given I only had one extant blog post to worry about, I figured having it completed within a week would be reasonable. - -### Installing Ruby + DevKit - -Middleman uses some Ruby gems that need the Ruby DevKit so they can compile native extensions. While this is all [documented elsewhere on the internet](http://jekyll-windows.juthilo.com/1-ruby-and-devkit/), I'll just list the basic steps for doing this on Windows here: - - 1. [Download](http://rubyinstaller.org/downloads/) and install Ruby (I installed Ruby 2.2.2 (x64)); - 1. [Download](http://rubyinstaller.org/downloads/) and install the Ruby Development Kit (I installed the one for Ruby 2.0 (x64)); - 1. Run the following commands in a command-line window: - - ``` - ruby dk.rb init - ruby dk.rb install - ``` - -### Setting Up Compilation - -I'm quite a big fan of being able to compile on the command-line, so I set myself up a ```Build.cmd``` and checked it into Git for compiling the site as I go. It's nothing ground-breaking, here's the content: - -``` -@echo off - -bundle exec middleman build %* -``` - -Then it's just a simple command of: - -``` -c:\coding\blog>build -``` - -The ```%*``` on the end passes any arguments through to bundle, which is useful if compilation produces errors so you can do this to get more detail: - -``` -c:\coding\blog>build --verbose -``` - -### Feature Parity - -While WordPress has a plethora of plug-ins and being PHP is infinitely customisable, I never really ventured down that route as PHP isn't my thing. The only thing I'd be missing is a comments engine, but I'll cover that below. That means that all I really need to retain is the same site structure so that anything indexed by search engines doesn't result in a nasty 404. This was pretty much all covered by the examples in the Middleman example templates that got generated and just needed to be tweaked to my liking for how they rendered, like using proper UK date formats. - -Below are a few snippets and gotchas found in the process: - -#### Dropping .html From URLs - -WordPress defaults to extensionless URLs. To keep my URLs I needed to get rid of them. - -To do this, set this option on the blog in ```config.rb```: - -``` -blog.permalink = "{title}" -``` - -Then *after* the blog options, set this: - -``` -activate :directory_indexes -``` - -For a while I had blogs misbehaving but non-blog pages working as expected. This was fixed by turning on ```directory_indexes``` after the blog pages were considered when the directory indexes were created. - -#### Forcing CSS and Javascript Cache Updates - -If you change your CSS browser caches might not pick-up the change and you'll end up with a screwy UX. If you activate asset hashing as described below, your CSS and Javascript paths (assuming you use the ```javascript_include_tag``` or ```stylesheet_link_tag``` helpers to render them) will have a hash added to the file name so that they move between deployments, forcing client caches to be invalidated. - -``` -configure :build do - activate :asset_hash -end -``` - -#### Fixing Timezone-related Errors - -The blog plug-in uses the ```tzinfo``` gem to handle timezones. However Windows doesn't include the data required for this that Linux has natively, which causes builds to fail. The remedy this add this line to ```Gemfile```: - -``` -gem "tzinfo-data" -``` - -#### Adding The Homepage To sitemap.xml With The Date Of The Lastest Blog Article - -The blog template comes with a ```sitemap.xml.builder``` file which renders a sitemap of articles in the blog for you. It won't render any other pages you might have though. There's probably a snazzier way to enumerate the pages during the build and list everything, but I only wanted two extra entries. To add them manually, you can add something like the code below. This adds an entry for the root of the site, and dates it as being updated at the same time as the latest blog entry (because it lists the last few posts on it). - -``` -xml.url do - xml.loc site_url - xml.lastmod File.mtime(blog.articles[0].source_file).iso8601 - xml.changefreq "monthly" - xml.priority "0.5" -end -``` - -For other pages, I change `````` to be the filetime of the relevant source file: - -``` -xml.lastmod File.mtime("source/my-page.html.erb").iso8601 -``` - -#### Parameterise All The Things - -Put commonly used text, variables etc. as variables in your ```config.rb``` file. For example: - -``` -set :site_root_uri_canonical, "https://blog.martincostello.com/" -set :blog_author, "Martin Costello" -set :twitter_handle, "martin_costello" -``` - -I'm unlikely to change my name any time soon, but it makes the code a bit more readable that being hard-coded literals of my name all over the codebase. - -#### Partial All The Things - -Similar to ASP.NET MVC, as well as full pages Middleman supports partial pages for snippet re-use. I've used this liberally throughout this site to try and keep to the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principle. - -As an example here's the raw code for my entire layout page which contains 7 partials. - -``` - - - <%= partial "head" %> - - <%= partial "navbar" %> -
- <%= yield %> -
- <%= partial "footer" %> -
- <%= partial "aside" %> - <%= partial "scripts" %> - <%= partial "analytics" %> - <%= partial "disquscount" %> - - -``` - -You can also use partials in partials, which can be, erm, fun. - -### Importing Content - -I was in the "lucky" situation of only having one extant blog post, so I didn't have to worry about a bulk import or conversion process, which you might not have the luxury of doing. Given this, I just copied the text from the old blog and then manually re-wrote it in Markdown in the new format to live in the new site. That was probably about a 30 minute job and wasn't overly taxing or vexing. There was also the homepage and "about me" pages in the old blog, but I just rewrote those from scratch. - -If you need to import content en-masse I'd suggest writing something in your language of choice to try and parse your existing articles and convert the text to Markdown. Alternatively you could just pull out the raw HTML and dump it into a Markdown file as-is and not worry about any dud formatting. - -### Syntax Highlighting - -My [first blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/) uses a lot of code examples and when this blog was still running in its PHP incarnation I was never really happy with the styling. For this new blog I did some digging around to find something to use. Again, it turns out there's a dedicated Middleman plug-in just for this: ```middleman-syntax```. - -You can wire-it up to use [Rouge](https://github.com/jneen/rouge) just like GitHub pages, so that's exactly what I did. - -All it took was these lines in the gemfile: - -``` -gem "middleman-syntax" -gem "redcarpet" -``` - -And these configuration settings in ```config.rb```: - -``` -activate :syntax -set :markdown_engine, :redcarpet -set :markdown, :fenced_code_blocks => true -``` - -### Security - -I like to ensure all my sites are best-practice secured, so I ran through the points in my [first blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/) and sorted everything out. As there's no code in the site as it's static, this was purely ```Web.config``` jiggery-pokery to get IIS running in Azure doing what I wanted. - -### Eye-Candy - -As I was doing a relaunch and spruce-up, I figured I'd add a few nice-to-have features to the site to spruce it up. Namely: - - 1. Integration with [Disqus](https://disqus.com/) for comments; - 1. Social sharing buttons for Facebook, Google+ and Twitter; - 1. Review my SEO and Social Media related metadata (like OpenGraph `````` tags). - -I won't get into the detail here as you can see the results here in the blog for yourself, but it was just simple following of the integration guides for Disqus and social sharing and using partials for the buttons and scripts etc. so they were centralised and I could re-use them as needed with minimal fuss. - -### Switching Over - -With all the feature and testing cards on my VS Online task board in the Done column, it was time to put the site live. Ideally I'd have done it with 100% uptime (just for the show-off factor), but I couldn't due to the need to migrate the SSL host name bindings between Azure Web Apps due to the subscription changeover. For my particular set up this involved: - - 1. Remove the host name binding for ```blog.martincostello.com``` from the old Web App; - 1. Add the host name binding for ```blog.martincostello.com``` to the new Web App; - 1. Setup the SSL certificate binding; - 1. Update my DNS ```CNAME``` to point at the new Web App; - 1. Flush my DNS cache. - -Then it was just a simple matter of pushing the final build of the site to Azure over FTP, checking it was working and deleting the old Azure resources using the subscription I didn't want to use any more. At which point I felt quite pleased with myself! - - - -## Conclusion - -Middleman is a nice static site generator to use for a blog. It has a plug-in for blogging, lets you use Markdown for authoring, has built-in support for paging, sorting, tags and all the other goodness you'd expect in a simple blog. There's a bit of a learning curve if you're not that familiar with Ruby, but unless you want to do something *really* custom, you shouldn't need to learn anything beyond a few loops and string/date formatting. Most of the Ruby you'll write will be tag blocks to output dynamic content during the build process: - -``` -<%= current_page.data.title %> -``` - -The biggest selling point for me was being able to use Markdown to write posts. In fact, that's what I'm writing this very post in right now. I've got a few more things left to implement in the near future, such as automating deployment of the ```build``` folder to Azure using Git so I don't need to do manual FTP copies, and adding in a proper HTML sidebar to the pages to list the recent posts and the post archive. Other that that I'm a lot happier with the appearance of my blog, the management overhead, and the cost, than I ever was with the PHP incarnation. - -I think this tweet, and the fact that you are reading this blog post right now, speak for themselves: - - +--- +title: Why I Switched From WordPress To Middleman +date: 2015-06-18 +tags: blogging,middleman,wordpress +layout: bloglayout +description: "Why I switched from using WordPress to the Middleman static site generator for writing my blog." +--- + +A few years ago I thought I'd set up a blog. Initially I created a blog in [Blogspot](http://martincostello.blogspot.co.uk/) but I decided some time later that I'd rather host it myself with custom DNS, etc., mainly as a learning exercise. As I'm mostly a developer in the Microsoft stack, I decided I'd set it up in Windows Azure as an Azure Website (now a "Microsoft Azure Web App") as that was something I knew of and knew a little about. A few clicks through a wizard later and I had a WordPress blog running in Azure, backed by a MySQL database. Great - time to get blogging! + +Flash-foward a few years, and I had a sum total of [one solitary blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/). Yeah, so I'd been a bit slack on the whole writing a blog thing. However I've got an idea for a second blog post that I've been procrastinating over writing for a while, so I thought I'd start on that (aside: this isn't that blog post, that's coming soon). By this point I'd grown two different Azure subscriptions and the blog was running in the wrong one and I was starting to hit limits on my free Azure credits due to other usage, so I figured I'd switch it around. The problems begin. + +READMORE + +## Problems, Problems, Problems + +So the first problem was that the MySQL database that Azure automatically provisioned for me when the WordPress blog was initially provisioned is through a third-party provider. I had no idea where this was, but eventually through some clicking of buried-away links in the Azure portal I found a link through to the third-party portal for the database. It was then that I discovered that the database was on a free tier with a paltry 20MB maximum size. 20MB seemed a bit pathetic considering with one post I'd already used 15MB, and I already wanted to move the database to a different subscription so why remove the limit and start paying more? So how do you move a MySQL database from one subscription to another? I don't know, I never found out - more on this later. + +The next hurdle was that I'm not really au-fait with MySQL management given I'm a Microsoft/Windows guy, and if I'm honest I wasn't particularly inclined to learn to do so either. Microsoft have been pushing for SQL Server interoperability with PHP (which WordPress is written in) for [a while](http://blogs.technet.com/b/dataplatforminsider/archive/2014/11/06/available-today-preview-release-of-the-sql-server-php-driver.aspx) so I thought why not migrate to use SQL Server as the data store instead? That way I can host a SQL database (which I know how to do) in Azure in the right subscription and point WordPress at that instead. There's [PHP drivers for SQL Server](https://msdn.microsoft.com/en-us/data/ff657782.aspx) now and a [WordPress plugin](https://wordpress.org/plugins/wordpress-database-abstraction/) for using SQL Server as well? Microsoft have even [blogged about](http://blogs.msdn.com/b/brian_swan/archive/2010/05/12/running-wordpress-on-sql-server.aspx) how to do it, so it can't be that hard, right? **Wrong** as I was about to discover. + +## The Abortive Attempt To Use SQL Server + +Migrating to SQL Server it is then. Let's get started. Step one: where the hell is the website source? + +As everything had been set up for me in the Azure wizard, I'd never actually seen the website source itself ever. Better get it then, which is pretty simple. I just had to FTP into the IIS website's directory in Azure and pull it out. + +Great I've got the source, now what do I do? Well I better put it in source control somewhere before I start tinkering. That way I can rollback if I mess everything up, plus I can setup a test slot somewhere where I can do testing without worrying about screwing up my "production" MySQL database. Azure has a nice [deploy from Git workflow](https://azure.microsoft.com/en-gb/documentation/articles/web-sites-publish-source-control/) so I'll go with a Git repo to look after it. There's some private configuration data for the site to run in Azure though (like connection strings) so I don't want it publicly available. GitHub don't allow private repositories for free but Visual Studio Online is always private, supports Git and is [free for up to 5 users](https://www.visualstudio.com/en-us/products/visual-studio-online-pricing-vs.aspx). I'm only one person, so great, sounds like the perfect fit. I'll get all the code checked in and branch and get to work then. + +Cue montage of trying to get it to work to the theme of Murder She Wrote. I'll let this selection of tweets show you some highlights of the journey: + + + + + + + + + + +## Mission: Failed + +As you can see, I gave up. The main problems and reasons being: + + 1. The WordPress plug-in was out-of-date (2 years+ since the last update) and didn't work properly with my version of WordPress; + 1. The SQL Server PHP drivers didn't seem to want to run on PHP 5.5. After much banging my head against the wall I discovered that not only did they work fine with PHP 5.4, but also that the PHP drivers were already installed in Azure Websites meaning that lots of playing around trying to find the right binaries and get them to load were pointless; + 1. I could not work out how to import the MySQL data in SQL Server successfully without violating unique constraints and/or losing data integrity. + +## A Change Of Tack + +After the WordPress/SQL Server debacle I went into hibernation on the whole blog situation for a few months until this week. I'd seen various chatter here and there over the last few months about static site generators, so I wondered whether that would be a viable option. So I issued this tweet: + + + +I didn't get my useful feedback from my followers, so I went to our friend Google. It led me to the following two links: + + 1. [Static Site Generators](https://staticsitegenerators.net/) - Just a big list, not very helpful; + 1. [StaticGen](https://www.staticgen.com/) - A much better curated list, ranked by the projects' GitHub star counts. + +The main one that lept out was [Jekyll](http://jekyllrb.com/) as I'd heard of it before and GitHub uses it to generate GitHub pages sites. However not long afterwards I discovered that [Jekyll doesn't officially support Windows](http://jekyllrb.com/docs/windows/). I'm mainly a Windows guy, and even though I have an Ubuntu VM in Hyper-V on my laptop, I'd rather stick with the environment and tools I know. There are [guides for getting it to work on Windows](http://jekyll-windows.juthilo.com/), but as my heart wasn't set on Jekyll and I'd rather use something supported, so I ruled it out of the running. + +Cue some head-scratching, after which I did some further googling and found [this post by Scott Hanselman](http://www.hanselman.com/blog/RunningTheRubyMiddlemanStaticSiteGeneratorOnMicrosoftAzure.aspx). [Middleman](https://middlemanapp.com/) was in the second row on [StaticGen](https://www.staticgen.com/). Interesting... + +Having read Scott's article, I summised that Middleman worked on Windows, and would work in Azure (it's a static site I know, but good to know the workflow has been tried and tested by someone else). The article is mostly about getting the site to *build* on Azure, which **for now** I'm not interested in. That's a nice to have I can do in the future (it's on my VS Online backlog in fact), but at the time I just wanted the site - I can deploy it via FTP in the short-term. + +## Getting To Grips With Middleman + +Reading the [Middleman](https://middlemanapp.com/basics/install/) documentation things seemed straight-forward: + + 1. HTML templating from HTML and Markdown to HTML; + 1. Builds with Ruby; + 1. Generates a static site ready for deployment. + +As ever, I steamed right ahead and got stuck in, having not *thoroughly* read the documentation (like most developers). I had a site template, and it built. Great. + +Now how do you write a blog with it? + +It turns out (having read the documentation again *properly*) that Middleman has a [blog plug-in](https://middlemanapp.com/basics/blogging/). Huzzah! + +More digging around in the generated code shows the following blog features: + + 1. Archiving; + 1. Tags; + 1. Atom Feed; + 1. XML site map. + +This all looks very encouraging. In fact, this level of encouraging: + + + +## Implementing The Blog + +So over the course of the next two evenings I set about in earnest migrating over from WordPress to Middleman. It involved a number of steps, and probably took about 10 hours' of effort in total. It was a mixture of migration, feature parity and some new features I fancied adding in because I was giving the blog some love so would be a good opportunity. I hadn't set myself a timescale or deadline for completing the work, but given I only had one extant blog post to worry about, I figured having it completed within a week would be reasonable. + +### Installing Ruby + DevKit + +Middleman uses some Ruby gems that need the Ruby DevKit so they can compile native extensions. While this is all [documented elsewhere on the internet](http://jekyll-windows.juthilo.com/1-ruby-and-devkit/), I'll just list the basic steps for doing this on Windows here: + + 1. [Download](http://rubyinstaller.org/downloads/) and install Ruby (I installed Ruby 2.2.2 (x64)); + 1. [Download](http://rubyinstaller.org/downloads/) and install the Ruby Development Kit (I installed the one for Ruby 2.0 (x64)); + 1. Run the following commands in a command-line window: + + ``` + ruby dk.rb init + ruby dk.rb install + ``` + +### Setting Up Compilation + +I'm quite a big fan of being able to compile on the command-line, so I set myself up a ```Build.cmd``` and checked it into Git for compiling the site as I go. It's nothing ground-breaking, here's the content: + +``` +@echo off + +bundle exec middleman build %* +``` + +Then it's just a simple command of: + +``` +c:\coding\blog>build +``` + +The ```%*``` on the end passes any arguments through to bundle, which is useful if compilation produces errors so you can do this to get more detail: + +``` +c:\coding\blog>build --verbose +``` + +### Feature Parity + +While WordPress has a plethora of plug-ins and being PHP is infinitely customisable, I never really ventured down that route as PHP isn't my thing. The only thing I'd be missing is a comments engine, but I'll cover that below. That means that all I really need to retain is the same site structure so that anything indexed by search engines doesn't result in a nasty 404. This was pretty much all covered by the examples in the Middleman example templates that got generated and just needed to be tweaked to my liking for how they rendered, like using proper UK date formats. + +Below are a few snippets and gotchas found in the process: + +#### Dropping .html From URLs + +WordPress defaults to extensionless URLs. To keep my URLs I needed to get rid of them. + +To do this, set this option on the blog in ```config.rb```: + +``` +blog.permalink = "{title}" +``` + +Then *after* the blog options, set this: + +``` +activate :directory_indexes +``` + +For a while I had blogs misbehaving but non-blog pages working as expected. This was fixed by turning on ```directory_indexes``` after the blog pages were considered when the directory indexes were created. + +#### Forcing CSS and Javascript Cache Updates + +If you change your CSS browser caches might not pick-up the change and you'll end up with a screwy UX. If you activate asset hashing as described below, your CSS and Javascript paths (assuming you use the ```javascript_include_tag``` or ```stylesheet_link_tag``` helpers to render them) will have a hash added to the file name so that they move between deployments, forcing client caches to be invalidated. + +``` +configure :build do + activate :asset_hash +end +``` + +#### Fixing Timezone-related Errors + +The blog plug-in uses the ```tzinfo``` gem to handle timezones. However Windows doesn't include the data required for this that Linux has natively, which causes builds to fail. The remedy this add this line to ```Gemfile```: + +``` +gem "tzinfo-data" +``` + +#### Adding The Homepage To sitemap.xml With The Date Of The Lastest Blog Article + +The blog template comes with a ```sitemap.xml.builder``` file which renders a sitemap of articles in the blog for you. It won't render any other pages you might have though. There's probably a snazzier way to enumerate the pages during the build and list everything, but I only wanted two extra entries. To add them manually, you can add something like the code below. This adds an entry for the root of the site, and dates it as being updated at the same time as the latest blog entry (because it lists the last few posts on it). + +``` +xml.url do + xml.loc site_url + xml.lastmod File.mtime(blog.articles[0].source_file).iso8601 + xml.changefreq "monthly" + xml.priority "0.5" +end +``` + +For other pages, I change `````` to be the filetime of the relevant source file: + +``` +xml.lastmod File.mtime("source/my-page.html.erb").iso8601 +``` + +#### Parameterise All The Things + +Put commonly used text, variables etc. as variables in your ```config.rb``` file. For example: + +``` +set :site_root_uri_canonical, "https://blog.martincostello.com/" +set :blog_author, "Martin Costello" +set :twitter_handle, "martin_costello" +``` + +I'm unlikely to change my name any time soon, but it makes the code a bit more readable that being hard-coded literals of my name all over the codebase. + +#### Partial All The Things + +Similar to ASP.NET MVC, as well as full pages Middleman supports partial pages for snippet re-use. I've used this liberally throughout this site to try and keep to the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principle. + +As an example here's the raw code for my entire layout page which contains 7 partials. + +``` + + + <%= partial "head" %> + + <%= partial "navbar" %> +
+ <%= yield %> +
+ <%= partial "footer" %> +
+ <%= partial "aside" %> + <%= partial "scripts" %> + <%= partial "analytics" %> + <%= partial "disquscount" %> + + +``` + +You can also use partials in partials, which can be, erm, fun. + +### Importing Content + +I was in the "lucky" situation of only having one extant blog post, so I didn't have to worry about a bulk import or conversion process, which you might not have the luxury of doing. Given this, I just copied the text from the old blog and then manually re-wrote it in Markdown in the new format to live in the new site. That was probably about a 30 minute job and wasn't overly taxing or vexing. There was also the homepage and "about me" pages in the old blog, but I just rewrote those from scratch. + +If you need to import content en-masse I'd suggest writing something in your language of choice to try and parse your existing articles and convert the text to Markdown. Alternatively you could just pull out the raw HTML and dump it into a Markdown file as-is and not worry about any dud formatting. + +### Syntax Highlighting + +My [first blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/) uses a lot of code examples and when this blog was still running in its PHP incarnation I was never really happy with the styling. For this new blog I did some digging around to find something to use. Again, it turns out there's a dedicated Middleman plug-in just for this: ```middleman-syntax```. + +You can wire-it up to use [Rouge](https://github.com/jneen/rouge) just like GitHub pages, so that's exactly what I did. + +All it took was these lines in the gemfile: + +``` +gem "middleman-syntax" +gem "redcarpet" +``` + +And these configuration settings in ```config.rb```: + +``` +activate :syntax +set :markdown_engine, :redcarpet +set :markdown, :fenced_code_blocks => true +``` + +### Security + +I like to ensure all my sites are best-practice secured, so I ran through the points in my [first blog post](https://blog.martincostello.com/ensuring-your-asp-net-website-is-secure/) and sorted everything out. As there's no code in the site as it's static, this was purely ```Web.config``` jiggery-pokery to get IIS running in Azure doing what I wanted. + +### Eye-Candy + +As I was doing a relaunch and spruce-up, I figured I'd add a few nice-to-have features to the site to spruce it up. Namely: + + 1. Integration with [Disqus](https://disqus.com/) for comments; + 1. Social sharing buttons for Facebook, Google+ and Twitter; + 1. Review my SEO and Social Media related metadata (like OpenGraph `````` tags). + +I won't get into the detail here as you can see the results here in the blog for yourself, but it was just simple following of the integration guides for Disqus and social sharing and using partials for the buttons and scripts etc. so they were centralised and I could re-use them as needed with minimal fuss. + +### Switching Over + +With all the feature and testing cards on my VS Online task board in the Done column, it was time to put the site live. Ideally I'd have done it with 100% uptime (just for the show-off factor), but I couldn't due to the need to migrate the SSL host name bindings between Azure Web Apps due to the subscription changeover. For my particular set up this involved: + + 1. Remove the host name binding for ```blog.martincostello.com``` from the old Web App; + 1. Add the host name binding for ```blog.martincostello.com``` to the new Web App; + 1. Setup the SSL certificate binding; + 1. Update my DNS ```CNAME``` to point at the new Web App; + 1. Flush my DNS cache. + +Then it was just a simple matter of pushing the final build of the site to Azure over FTP, checking it was working and deleting the old Azure resources using the subscription I didn't want to use any more. At which point I felt quite pleased with myself! + + + +## Conclusion + +Middleman is a nice static site generator to use for a blog. It has a plug-in for blogging, lets you use Markdown for authoring, has built-in support for paging, sorting, tags and all the other goodness you'd expect in a simple blog. There's a bit of a learning curve if you're not that familiar with Ruby, but unless you want to do something *really* custom, you shouldn't need to learn anything beyond a few loops and string/date formatting. Most of the Ruby you'll write will be tag blocks to output dynamic content during the build process: + +``` +<%= current_page.data.title %> +``` + +The biggest selling point for me was being able to use Markdown to write posts. In fact, that's what I'm writing this very post in right now. I've got a few more things left to implement in the near future, such as automating deployment of the ```build``` folder to Azure using Git so I don't need to do manual FTP copies, and adding in a proper HTML sidebar to the pages to list the recent posts and the post archive. Other that that I'm a lot happier with the appearance of my blog, the management overhead, and the cost, than I ever was with the PHP incarnation. + +I think this tweet, and the fact that you are reading this blog post right now, speak for themselves: + + diff --git a/source/2015-11-30-this-blog-is-now-opensource.md b/source/2015-11-30-this-blog-is-now-opensource.html.md similarity index 100% rename from source/2015-11-30-this-blog-is-now-opensource.md rename to source/2015-11-30-this-blog-is-now-opensource.html.md diff --git a/source/2016-10-10-apple-pay-js.md b/source/2016-10-10-apple-pay-js.html.md similarity index 100% rename from source/2016-10-10-apple-pay-js.md rename to source/2016-10-10-apple-pay-js.html.md diff --git a/source/2016-10-18-browserstack-automate-api-client-v2.md b/source/2016-10-18-browserstack-automate-api-client-v2.html.md similarity index 100% rename from source/2016-10-18-browserstack-automate-api-client-v2.md rename to source/2016-10-18-browserstack-automate-api-client-v2.html.md diff --git a/source/2017-02-20-publishing-my-first-alexa-skill.md b/source/2017-02-20-publishing-my-first-alexa-skill.html.md similarity index 100% rename from source/2017-02-20-publishing-my-first-alexa-skill.md rename to source/2017-02-20-publishing-my-first-alexa-skill.html.md diff --git a/source/2017-08-28-migrating-from-iis-to-s3.md b/source/2017-08-28-migrating-from-iis-to-s3.html.md similarity index 100% rename from source/2017-08-28-migrating-from-iis-to-s3.md rename to source/2017-08-28-migrating-from-iis-to-s3.html.md diff --git a/source/2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.md b/source/2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.html.md similarity index 100% rename from source/2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.md rename to source/2017-10-03-reliably-testing-http-integrations-in-a-dotnet-application.html.md diff --git a/source/2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.md b/source/2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.html.md similarity index 100% rename from source/2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.md rename to source/2018-06-23-upgrade-to-dotnet-21-for-productivity-and-performance-gains.html.md diff --git a/source/2018-06-30-azure-static-websites-with-appveyor.md b/source/2018-06-30-azure-static-websites-with-appveyor.html.md similarity index 100% rename from source/2018-06-30-azure-static-websites-with-appveyor.md rename to source/2018-06-30-azure-static-websites-with-appveyor.html.md diff --git a/source/2018-09-30-writing-logs-to-xunit-test-output.md b/source/2018-09-30-writing-logs-to-xunit-test-output.html.md similarity index 100% rename from source/2018-09-30-writing-logs-to-xunit-test-output.md rename to source/2018-09-30-writing-logs-to-xunit-test-output.html.md diff --git a/source/2018-10-02-sql-localdb-wrapper-v2.md b/source/2018-10-02-sql-localdb-wrapper-v2.html.md similarity index 100% rename from source/2018-10-02-sql-localdb-wrapper-v2.md rename to source/2018-10-02-sql-localdb-wrapper-v2.html.md diff --git a/source/2018-12-17-aspnet-core-pseudo-localization.md b/source/2018-12-17-aspnet-core-pseudo-localization.html.md similarity index 100% rename from source/2018-12-17-aspnet-core-pseudo-localization.md rename to source/2018-12-17-aspnet-core-pseudo-localization.html.md diff --git a/source/2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.md b/source/2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.html.md similarity index 100% rename from source/2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.md rename to source/2019-06-10-sign-in-with-apple-prototype-for-aspnet-core.html.md diff --git a/source/2019-06-16-refit-and-system-text-json.md b/source/2019-06-16-refit-and-system-text-json.html.md similarity index 100% rename from source/2019-06-16-refit-and-system-text-json.md rename to source/2019-06-16-refit-and-system-text-json.html.md diff --git a/source/2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.md b/source/2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.html.md similarity index 100% rename from source/2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.md rename to source/2019-11-11-integration-testing-lambda-with-dotnet-custom-runtime.html.md diff --git a/source/2020-06-16-integration-testing-antiforgery-with-application-parts.md b/source/2020-06-16-integration-testing-antiforgery-with-application-parts.html.md similarity index 100% rename from source/2020-06-16-integration-testing-antiforgery-with-application-parts.md rename to source/2020-06-16-integration-testing-antiforgery-with-application-parts.html.md diff --git a/source/2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.md b/source/2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.html.md similarity index 100% rename from source/2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.md rename to source/2021-08-15-github-codespaces-gotchas-with-aspnetcore-oauth.html.md diff --git a/source/2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.md b/source/2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.html.md similarity index 100% rename from source/2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.md rename to source/2021-11-28-using-json-source-generators-with-aspnet-core-minimal-apis.html.md diff --git a/source/2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.md b/source/2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.html.md similarity index 100% rename from source/2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.md rename to source/2023-07-10-upgrading-to-dotnet-8-part-1-why-upgrade.html.md diff --git a/source/2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.md b/source/2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.html.md similarity index 100% rename from source/2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.md rename to source/2023-07-11-upgrading-to-dotnet-8-part-2-automation-is-our-friend.html.md diff --git a/source/2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.md b/source/2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.html.md similarity index 100% rename from source/2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.md rename to source/2023-07-12-upgrading-to-dotnet-8-part-3-previews-1-to-5.html.md diff --git a/source/2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.md b/source/2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.html.md similarity index 100% rename from source/2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.md rename to source/2023-07-19-upgrading-to-dotnet-8-part-4-preview-6.html.md diff --git a/source/2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.md b/source/2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.html.md similarity index 100% rename from source/2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.md rename to source/2023-10-13-upgrading-to-dotnet-8-part-5-preview-7-and-rc-1-2.html.md diff --git a/source/2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.md b/source/2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.html.md similarity index 100% rename from source/2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.md rename to source/2023-11-20-upgrading-to-dotnet-8-part-6-stable-release.html.md diff --git a/source/2023-11-29-native-aot-make-dotnet-lambda-go-brr.md b/source/2023-11-29-native-aot-make-dotnet-lambda-go-brr.html.md similarity index 100% rename from source/2023-11-29-native-aot-make-dotnet-lambda-go-brr.md rename to source/2023-11-29-native-aot-make-dotnet-lambda-go-brr.html.md diff --git a/source/_facebookmeta.erb b/source/_facebookmeta.erb index 4e61cb5..52fa77f 100644 --- a/source/_facebookmeta.erb +++ b/source/_facebookmeta.erb @@ -2,4 +2,4 @@ %> - + diff --git a/source/_footer.erb b/source/_footer.erb index 4f0885f..99b04de 100644 --- a/source/_footer.erb +++ b/source/_footer.erb @@ -10,12 +10,12 @@

- © <%= blog_author %> 2014-<%= Time.now.utc.strftime("%Y") %> | + © <%= config[:blog_author] %> 2014-<%= Time.now.utc.strftime("%Y") %> | Built from <%= git_sha[0,7] %> on <%= git_branch %>
- © <%= blog_author %> 2014-<%= Time.now.utc.strftime("%Y") %> + © <%= config[:blog_author] %> 2014-<%= Time.now.utc.strftime("%Y") %>
diff --git a/source/_head.erb b/source/_head.erb index c789d34..036d4a6 100644 --- a/source/_head.erb +++ b/source/_head.erb @@ -1,10 +1,10 @@ - <%= (current_page.data.title || blog_title) + " | " + blog_subtitle %> + <%= (current_page.data.title || config[:blog_title]) + " | " + config[:blog_subtitle] %> - - " /> - + + " /> + <% @@ -23,7 +23,7 @@ - + <% if current_page.data.date %> " /> @@ -33,13 +33,13 @@ <%= partial "microsoft" %> <%= partial "opengraph" %> <%= partial "twittermeta" %> - - - + + + <%= tag(:link, :rel => "manifest", :href => "/manifest.webmanifest", :open => false) %> - + <%= feed_tag :atom, "#{blog.options.prefix.to_s}/feed.xml", title: "Atom" %> diff --git a/source/_microsoft.erb b/source/_microsoft.erb index b5317c9..83cda60 100644 --- a/source/_microsoft.erb +++ b/source/_microsoft.erb @@ -1,4 +1,4 @@ - + diff --git a/source/_navbar.erb b/source/_navbar.erb index 3085cd7..3826360 100644 --- a/source/_navbar.erb +++ b/source/_navbar.erb @@ -1,5 +1,5 @@