Please Note: Google recently upgraded their DKIM keys to be 2048-bit.
Unfortunately Namecheap doesn’t yet support the longer key length, although they say that they’re working on it. In response Google Apps now allows for the shorter 1024 key bit length, which I was (and am) using before the upgrade.
I look forward to upgrading my DKIM key to be 2048-bit and will update this post after Namecheap supports it.
Also a big thanks to the folks who brought this to my attention via Twitter: @jmbase, @amanjeev, and @mattdebouge.
Here are the steps I took to make this happen with my favorite domain registrar, Namecheap. If your DNS is elsewhere, fear not, as these steps apply to other registrars (and DNS hosts) too.
Please Note: You may also want to consult this post, Authenticate email with DKIM, while you set this up.
This is an example of what I was unknowingly sending folks:
The first step is to login as the administrator to your Google Apps account. I seldom change any of the settings, so I always feel a little lost trying to find the right page. Here’s the path, current as of the publishing of this post:
Here is an edited (for clarity, I hope) photo that shows you the general area of the settings that you want:
Some things to note here:
Now that you’ve got the two required values, you’ll want to log into Namecheap to navigate to the “Advanced DNS” for your domain:
Once there, click the “Add New Record” button and select “TXT Record” from the dropdown menu. Paste the appropriate values into the “Host” and “Value” fields and then save them with the green “✓” icon.
Once the DNS propagates, you’ll see the green “Authenticating email ✓” (see my above screenshot) and you’ll be good to go, err authenticate!
You’ve just read about Authenticate your Google Apps’ Gmail with DKIM and Namecheap DNS on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>I’ve put a lot of work into my sites, but many of the performance improvements couldn’t have been made so easily without the great ecosystem of open source software and free services available to me. To say that I’m thankful for this is a gross understatement.
Both of my sites are built with a combination of Jekyll and Grunt. They’re hosted on GitHub Pages and their DNS is served by CloudFlare. I wholeheartedly endorse this tech stack for anyone wanting a static website.
What follows is an overview of some performance best practices and how I’ve been able to adhere to them with my development and production setup.
The HTML gets minified by grunt-contrib-htmlmin, which collapses whitespace and removes comments, amongst other small improvements.
keepClosingSlash
, which are needed for my inline SVGs.My Sass is linted with grunt-scss-lint, which ensures that I don’t introduce any inconsistencies, poor practices, or general cruft into my CSS. This results in a well organized stylesheet.
All the vendor prefixes are managed by grunt-autoprefixer so that I have effortless control over which browsers I support when writing my CSS. I no longer need to worry about having unnecessary vendor prefixes in my CSS rules.
The CSS is written in Sass and organized via partials that compile to one stylesheet. If my CSS were in multiple files, I’d use grunt-usemin to send those files to grunt-contrib-concat for concatenation.
My compiled CSS is sorted with grunt-csscomb to improve gzip compression, although my styles are lean enough that this hasn’t made any difference.
Read about the benefits of sorting CSS properties at Reduce file size with CSS Sorting.
The CSS gets minified by grunt-contrib-cssmin, which uses clean-css under the hood.
The above the fold CSS is generated with grunt-penthouse and inlined into the <head>
with an include.
The whole stylesheet is loaded asynchronously with loadCSS. An improvement could be made here to only load the styles that weren’t inlined, although I haven’t found a good way to do that.
I only support the WOFF and WOFF2 font formats and have them asynchronously loaded with fontloader.js (and its loadFont() function) so that they’re no longer blocking the page from loading.
More information about this technique (and related ones) at Better webfont loading with using localStorage and providing WOFF2 support.
My JavaScript is validated with grunt-contrib-jshint, which helps ensure that its error free. I also don’t have very much of it since my websites are relatively simple functionality-wise.
I use grunt-usemin to send my JavaScript files to grunt-contrib-concat for concatenation.
A plugin of many talents, grunt-usemin sends the JavaScript to grunt-contrib-uglify to be minified.
Save for the aforementioned loadCSS() and loadFont() functions, the rest of my JavaScript is loaded just before the closing </body>
tag.
For this website, I use grunt-contrib-imagemin to compress the size of my images. For Webworke.rs I use grunt-imageoptim and find the latter plugin results in smaller filesizes.
For Webworke.rs I’ve implemented jekyll-picture-tag and that allows me to use the <picture>
element with picturefill polyfill.
My SVGs get minified by grunt-svgmin, although I also do some editing by hand before committing them into version control.
I inline all my SVGs with Jekyll, so I save requests at the expense of browsers I don’t support. I’d consider using grunticon for less feature rich browsers.
In and of itself, GitHub Pages is incredibly fast and reliable, as well as free! It makes a lot of sense to take advantage of the hosting, especially when your site’s source code is already put into version control and stored on GitHub.
I host my DNS with CloudFlare, which opens up a whole world of server-side optimizations. I get my site served by a CDN, compression of my assets via gzip, the ability to set the TTL for static resources (the whole site, basically) for browser caching, and SSL (even though the connection from GitHub Pages to CloudFlare is unencrypted, but hey beggars can’t be choosers).
I still have work to do and the following is my shortlist of improvements to implement in these coming months:
srcset
by finding a good workflow to generate the images and markupYou’ve just read about Performant Websites with Jekyll, Grunt, GitHub Pages, and CloudFlare on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>There are many optimizations one can make, but this post will focus on elimating blocking CSS requests from the <head>
by inlining the above-the-fold CSS and then asynchronously loading the site’s stylesheet. We’ll do this with the following tools:
As previously covered, this site was scaffolded by Generator-jekyllrb, a Yeoman generator for building sites with Jekyll. What follows is my implementation, which should be of interest for others with similar development setups for Jekyll.
The first step is to install grunt-penthouse and configure the task in the Gruntfile.
I run the penthouse
task after any change to my Sass files, which ensures that my critical path CSS is up-to-date. This works out well because it doesn’t make my workflow any more complicated than it needs to be.
The critical.css is saved in my _includes directory, which allows me to easily inline it into my site’s markup. I’ve also added the CSS to my .gitignore, since there’s no benefit to versioning it.
I’ve elected to generate the critical CSS with dimensions that are desktop first, which may seem counterintuitive. I’m doing this to ensure that I get the CSS that’s required for my site’s sidebar. On a mobile device it’s most likely below-the-fold, but on a wider viewport it displays above-the-fold.
Your website design will obviously differ from my own, so it would be prudent to test out different dimensions when generating the critical path CSS.
In my header.html include I’ve inlined the critical CSS and then added the loadCSS function, which will asynchronously load my stylesheet.
You can see that I make use of a faux environmental variable to conditionally print markup.
My “development” environment is provided courtesy of grunt serve
, while my “production” environment is grunt build
. These variables are saved in their respective _config files.
I only inline my above-the-fold CSS, print the markup to asynchronously load my stylesheet, and wrap my <link>
tag with a <noscript>
when I’m ready to build the site for deployment.
The stylesheet in our usemin block will be revved, which requires a corresponding revving of the stylesheet within the loadCSS function. This can be resolved with a regular expression in a custom usemin pattern.
Please note that until grunt-usemin 3.0.0, a custom pattern with the same name as a default pattern would replace it, instead of merging it.
Those were the highlights! Feel free to dig through this site’s repository for more context regarding these example snippets of code.
Also, a big thanks to the developers of Penthouse, grunt-penthouse, and loadCSS for simplifying what could potentially be a very complicated workflow.
You’ve just read about Critical Path CSS in Jekyll with Penthouse and loadCSS on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>Per the project’s description:
Generator-jekyllrb wraps the Jekyll static site generator in a Yeoman development workflow. Scaffold your site with Yo, manage front end packages with Bower, and automate development and build tasks with Grunt.
Generator-jekyllrb is ideal for developing performant static sites and prototyping dynamic sites and apps (especially if the final version uses Yeoman too). It’s also a great introduction to Yeoman if you’re not familiar with JavaScript MV* frameworks.
My favorite part to pairing Jekyll with Grunt is that I get the benefits of using both tools, without being locked into their respective disadvantages. I’m able to use Jekyll to write, organize, and build my content into static files, but I don’t let Jekyll handle any of my frontend assets, which is where Grunt comes in.
Sure Jekyll can compile Sass and CoffeeScript, but otherwise I need a plugin, a Ruby gem, and/or a Rakefile to automate my build tasks. All of this is much better done by Grunt via its large ecosystem of plugins. Let Jekyll do the content and templating, but use Grunt for all the build tasks.
What follows are the most interesting Grunt plugins that I use to build this site:
For those who are interested, see my Gruntfile.js and package.json.
You’ve just read about Ode to Grunt, Yeoman, and Generator-jekyllrb on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>_includes/social-icons/
directory and they’re added to the page template with some YAML Front Matter and a Liquid for loop.Each social media account gets a title, url, and a class, which are then used by the Liquid for loop to generate the markup.
We loop through each social media account in the YAML Front Matter. An include prints out the SVG icon markup inline, which essentially results in {%includesocial-icons/github.svg%}
for each SVG icon. The respective URL and title are pulled from the loop as well.
Here’s what the resulting HTML output looks like:
It’s an elegant way to dynamically include the social media icons and links. Thankfully it wasn’t difficult to set up and it has proven easy to maintain. I did spend a lot of time making the dozens of social media icons, but that was all upfront work.
You’ve just read about How to Dynamically Include SVGs Inline with Jekyll on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>##My Previous Implementation You may know this as the “Bulletproof @font-face Syntax.”
The browser support for WOFF is pretty good, so long as you’re comfortable not supporting IE8, Opera Mini, and older versions of Android. I’m more than okay with not supporting those, especially since they’ll still get a readable version of my site, which is really all that matters.
A benefit to including WOFF2 is that the file sizes are 30% smaller on average, although as of today the only browser that supports the format is Chrome. That said, I bet if I forget about this for another year that will change :)
You’ve just read about Update Your @font-face Definitions to Just Use WOFF (and WOFF2) on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>To comment out code, it’s preferable to use hidden comments, which don’t get printed:
<%-- This will never been seen on production. --%>
<!-- But this will, although why would you want that? -->
Both arithmetic and logical operators are supported:
Operator | Description |
---|---|
. | Access a bean property or Map entry |
[] | Access an array or List element |
( ) | Group a subexpression to change the evaluation order |
+ | Addition |
- | Subtraction or negation of a value |
* | Multiplication |
/ or div | Division |
% or mod | Modulo (remainder) |
== or eq | Test for equality |
!= or ne | Test for inequality |
< or lt | Test for less than |
> or gt | Test for greater than |
<= or le | Test for less than or equal |
>= or gt | Test for greater than or equal |
&& or and | Test for logical AND |
|| or or | Test for logical OR |
! or not | Unary Boolean complement |
empty | Test for empty variable values |
Use the set
tag to create a new variable or assign a value to a new or existing variable.
Attribute | Description | Required | Default |
---|---|---|---|
value | Information to save | No | body |
target | Name of the variable whose property should be modified | No | None |
property | Property to modify | No | None |
var | Name of the variable to store information | No | None |
scope | Scope of variable to store information | No | Page |
The following two variables have their respective values assigned with set
:
<c:set var="maxTopics" value="3" />
<c:set var="displayClass" value="hiddenTablet" />
We’d then be able to use the variables like so, ${maxTopics}
and ${displayClass}
within our JSP.
To evaluate an expression, use an if
tag. If the condition is true, it will display the body content.
Attribute | Description | Required | Default |
---|---|---|---|
test | Condition to evaluate | Yes | None |
var | Name of the variable to store the condition's result | No | None |
scope | Scope of the variable to store the condition's result | No | page |
In the following example of an author profile component, we test if the author has a photo and if so, we print it out:
Much like a switch of if else statement, choose
allows you to evaluate multiple conditions by using a combination of when
and otherwise
tags.
This media object component tests if there’s a photo, or a video, or neither and then prints out the appropriate markup:
A ternary operator, which allows for an inline condition that evaluates to true or false:
Using a ternary operator is useful within a template because it allows for the addition of classes for use as styling hooks.
Here we use a ternary operator to print classes that denote whether the layout is one or two columns:
It may also be helpful to print out inline styles, although be weary about relying on this too often, as CSS should really be kept in stylesheets.
In this example we change the background color of the component to red when it’s not authored:
To iterate over a collection, use a forEach
tag. There are a half-dozen attributes for use with the forEach
tag and they can provide quite a bit of flexibility.
Attribute | Description | Required | Default |
---|---|---|---|
items | Information to loop over | No | None |
begin | Element to start with (0 = first item, 1 = second item, …) | No | 0 |
end | Element to end with (0 = first item, 1 = second item, …) | No | Last element |
step | Process every step items | No | 1 |
var | Name of the variable to expose the current item | No | None |
varStatus | Name of the variable to expose the loop status | No | None |
Here we have a component that displays an unordered list of links:
The varStatus
attribute comes with some helpful properties.
Property | Getter | Description |
---|---|---|
current | getCurrent() | The item (from the collection) for the current round of iteration |
index | getIndex() | The zero-based index for the current round of iteration |
count | getCount() | The one-based count for the current round of iteration |
first | isFirst() | Flag indicating whether the current round is the first pass through the iteration |
last | isLast() | Flag indicating whether the current round is the last pass through the iteration |
begin | getBegin() | The value of the begin attribute |
end | getEnd() | The value of the end attribute |
step | getStep() | The value of the step attribute |
A couple useful properties are first
and last
, which are used to delimit a list of authors in the following example from a byline component:
There are a lot of standard functions included in JSTL, although you probably shouldn’t use them. The majority of the functionality they provide is either better done in the model (and not the view) or can be accomplished with CSS. I very seldom find myself using anything other fn:length()
, which I use to find the number of items in a collection.
Function | Description |
---|---|
fn:contains() | Tests if an input string contains the specified substring. |
fn:containsIgnoreCase() | Tests if an input string contains the specified substring in a case insensitive way. |
fn:endsWith() | Tests if an input string ends with the specified suffix. |
fn:escapeXml() | Escapes characters that could be interpreted as XML markup. |
fn:indexOf() | Returns the index withing a string of the first occurrence of a specified substring. |
fn:join() | Joins all elements of an array into a string. |
fn:length() | Returns the number of items in a collection, or the number of characters in a string. |
fn:replace() | Returns a string resulting from replacing in an input string all occurrences with a given string. |
fn:split() | Splits a string into an array of substrings. |
fn:startsWith() | Tests if an input string starts with the specified prefix. |
fn:substring() | Returns a subset of a string. |
fn:substringAfter() | Returns a subset of a string following a specific substring. |
fn:substringBefore() | Returns a subset of a string before a specific substring. |
fn:toLowerCase() | Converts all of the characters of a string to lower case. |
fn:toUpperCase() | Converts all of the characters of a string to upper case. |
fn:trim() | Removes white spaces from both ends of a string. |
In the following example we only print out the search results if there are more than zero, otherwise we tell the user to try a different search term.
You’ve just read about Fun with JSTL in JSPs on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>Within his first email, Ian included a link to test results for davidensinger.com from Webpagetest.org.
A quick look reveals a three second delay in loading the site, which manifests itself in the Initial Connection time, of the second request:
An extended look at the first request reveals our culprit, which is a 302 redirect. We can also verify this via the Facebook Open Graph Debugger:
After a quick search, I found Analyzing the GitHub Pages Waterfall Chart, wherein @helloanselm discovers that GitHub Pages intentionally redirects sites that are setup with DNS A
records.
This is our exact setup since Namecheap doesn’t support the ALIAS
record, which is suggested by Setting up a custom domain with Pages. For more info see my previous post on Setting the DNS for GitHub Pages on Namecheap.
That said, the ALIAS
record doesn’t have robust support amongst registrars. I don’t have a good technical understanding of DNS, so I defer to the following post for a better explanation of the potential pitfalls of the ALIAS
record.
Through his research, Ian came across a post at Higher Order Heroku that subsequently led him to CloudFlare. It seems that a common request amongst users was for an Alias-type record to use with AWS, Heroku, and GitHub Pages. In response, CloudFlare rolled out CNAME Flattening earlier this year, which they introduced with this blog post: Introducing CNAME Flattening.
As previously stated, I don’t understand the DNS specification as well as I’d like, but CloudFlare seems confident that their new CNAME Flattening feature won’t break the Internet. It also won’t interfere with your MX
records, so you need not worry about receiving your emails either. Ask Ian, as I questioned him on this point several times: “Hey still no email problems?”, to which his reply was always in the affirmative.
Okay so you’re ready to make the move to CloudFlare, right? After you sign up (you can do the free account), you’ll then want to add your site:
Once CloudFlare finishes importing your DNS records, you’ll then want to delete both of your A
records and replace them with one CNAME
that points to your username.github.io. Use the @ symbol to denote your root domain:
You should then have the following two CNAME
records, amongst whatever other DNS records you may have:
Once you’ve finished modifying your DNS records with CloudFlare, you’ll want to transfer your DNS away from Namecheap.
To transfer your DNS to CloudFlare, login to your Namecheap account, select the appropriate domain name, and then go to Transfer DNS to Webhost. You’ll see the following screen:
Please note that the nameservers that I used, gail.ns.cloudflare.com and hugh.ns.cloudflare.com, may not be the nameservers that you’ll need to use with CloudFlare.
After a few days with the new DNS settings at CloudFlare, I’m happy to report that the site loads much faster. The 302 redirect is gone, which reduces the Initial Connection time and subsequently the Time to First Byte:
I’m pleased with the new results, although I’m unsure how this affects the site from the perspective of GitHub Pages. I know they offer protection against denial of service attacks, but I don’t know if adding CloudFlare into the mix affects this in any way. If anybody has any perspective on this, please let me know.
More Info: DNSimple has a good write up about the Differences between the A, CNAME, ALIAS and URL records.
You’ve just read about Transferring the DNS from Namecheap to CloudFlare for GitHub Pages on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>The first step is to create an include for your entry footer, within which you’ll put whatever content you’d like your readers to see.
You’ll then want to include your feed footer within the include for your feed’s entries, which will probably look a lot like the following (see the {%includefeed-footer.html%}
):
Also be sure to properly escape the data in your posts. I prefer to use CDATA
, but Jekyll also comes with a Liquid filter to escape XML: {{post.content|xml_escape}}
.
You’ve just read about How to Include a Footer in your Site’s Feed for Jekyll on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>The following are available to use online, for free:
These are my preferred applications when optimizing images. Also I can’t believe that ImageOptim and ImageAlpha are free because they’re that good.
If you’re using Grunt then check out Optimizing Images with Grunt and these plugins:
You’ve just read about Image Optimization Tools Overview on Development, design, and more by @DavidEnsinger.
If you’d prefer to receive your updates in tweet form, please follow me on Twitter, otherwise I hope you’re enjoying the feed!
]]>