Introduction

I was always interested in optimizing page load speed on websites that I was working on.

Imagine that you came to the grocery store to buy walnuts because you've heard that walnuts are extremely beneficial for your brain. You see a pack of walnuts for $20 and a pack for $8. The first pack has walnuts without shell and the second pack has nuts with shell.

2 packs of walnuts

It's up to you what to choose. If you go with the first pack, you'll save time because you don't need to clean all of them. If you go with the second pack, you'll save money but lose time.

That's the same dilemma that we should face when we start a new website project. We can take our time and work on a project with optimization in mind, or we can rush through it and make it work. In the first scenario, we'll have an optimized website with fast page load. In the second we'll have the same but slow.

2 macbook laptops

When people use the optimized website, they don't need to wait for the page to be loaded, you'll save many users' time, but it's pricier to build. The slow website takes less time to build, and as the result, the development of such a website costs more.

Of course, if people hired you to build a website, and they are serious about it, they should understand that fast websites take more time to build. In case they don't understand it, and want a fast website full of cool features for nearly free, I would avoid working with these people. Unless you are eager to work for the minimum possible salary.

In this article, I'm gonna share with you 5 techniques that I use for building fast websites, independent of the programming language or framework. I will also share some free and useful resources that help me in my journey.

5 rules for building fast websites

  1. Compress images
  2. Keep all files on one server
  3. Compress and minimize assets
  4. Cache database results
  5. Use lazy loading to display images

1. Compress images

The most important step that you can make to increase the page load speed of your website is to compress all the images. If you analyze your website with tools like WebPageTest or Pingdom, you'll notice that loading images takes a lot of time. Especially if you check the page that has many of them.

There is a great and free website called Optimizilla that I have used for about 2 years for compressing images.

Screenshot of the optimizilla website

This website is my favorite, I haven't seen anything like this. But there are, of course, alternatives. One of these alternatives is called Toolur, it's not only compresses images but also resizing them. I, personally, use Optimizilla because it allows me to tweak the image quality exactly how I want.

2. All files on one server

This one is the shortest because I hope everybody is doing it. Never include fonts, images, styles, or JavaScript files from other servers. There is no need for opening other connections. Unless you include files from Content Delivery Network (CDN), in this case a new connection will not be opened. Loading images from CDN will be even faster than loading them from your server storage.

The other thing is that, if you have a dedicated server for hosting all the assets, then referring to another server is totally fine. Because in case like this, the opened connection is not pointless. It's pretty obvious, but it wasn't clear for me at the beginning of my journey.

3. Minimal assets

I have a rule that I always follow while building a website, to have 1 JavaScript file, 1 CSS file and 1 font. Of course, it depends on the project and every so often the client wants 5 fonts instead of one. With CSS and JavaScript things are different, clients don't care how many files you're including in your HTML.

If I have JavaScript code that will be executed only on 1 or 2 pages, then I would extract it to a separate file, and include it only on pages where I need. Like in this example where I have hightlight.js script with styles.

<link href="css/app.css" rel="stylesheet">
<link href="css/light-theme.css" rel="stylesheet">
<script src="js/app.js" defer></script>
<script src="js/highlight.js" defer></script>

app.css and app.js are my main files, and hightlight.js and light-theme.css are used only for 1 page.

I use module bundlers for compiling my assets. While Webpack configuration can be pretty overwhelming, I'm using something called Laravel Mix in most of my projects.

Logo of Laravel mix

Laravel Mix is the wrapper around Webpack that allows you to compile your TypeScript, Vue, JavaScript, Sass, Less or other CSS preprocessors into plain CSS and JS with simple configuration steps. Here is the example of a configuration file from one of my projects.

let mix = require('laravel-mix')

mix.sass('resources/sass/app.scss', 'assets/main.css')
    .js('resources/ts/main.ts', 'assets/main.js')
    .sourceMaps()
    .disableNotifications()

Even though it's called Laravel Mix, you can use it in any project with any programming language.

4. Caching database results

As your project grows, caching database results becomes necessary, especially if you have queries with multiple joins. Take a look at the query I have in one of my projects:

select
        CA.*,
        Client.*,
        Subs.*,
        UserKlm.display_name as klm_user_name,
        UserFranchise.display_name as franchise_user_name
from mp_clients as Client
left join mp_client_article as CA
    on Client.id = CA.client_id
inner join mp_subscriptions as Subs
    on Client.id = Subs.client_id
inner join users as UserKlm
    on Subs.klm_user_id = UserKlm.ID
left join users as UserFranchise
    on Subs.franchise_user_id = UserFranchise.ID;

Every programming language has a library or package that does this job for you. Implementation is pretty similar in all the languages that you can use for the web. You simply have a function that excepts cache key name, time to live and a callback.

In Laravel, caching looks like this:

$post = Cache::remember('posts', 240, function () {
    return Post::query()
        ->with('tags:id,color,name')
        ->withCount('pageViews')
        ->get()
        ->toArray();
});

After the first request Cache::remember() will run the callback that fetches needed data from the database. The query results will be stored in memory for 240 seconds.

When the second request comes, instead of running the callback and hitting the database, the remember() method will return results from memory. Pretty simple and very effective.

5. Lazy loading images

Lazy loading is a functionality that allows loading only those images that are visible to the user. Images that are not visible will not be rendered until the user sees them.

There are different NPM packages that offer you this functionality.

NPM search result

One of those packages is called smooth-loader. This is a tiny package that I use in all of my projects.

I've built it because I couldn't find anything that would be basic and small. Plus, I wanted it in TypeScript. The package is very straightforward and simple to use.

Bonus for Laravel devs

This section applies only for Laravel developers. I think every Laravel developer must know about Laravel's built-in caching functionality. If you run php artisan list | grep :cache, you'll see something like this:

  config:cache         Create a cache file for faster configuration loading
  event:cache          Discover and cache the application's events and listeners
  route:cache          Create a route cache file for faster route registration
  view:cache           Compile all of the application's Blade templates

Use these commands only in your production, there is no need to run them in development.

If you want to go more in-depth on the current state of your website, you can use services like Sitechecker. You can get a detailed SEO audit on how to improve your website and get on the top of Google.

Conclusion

The most important thing that I wish to leave you with, is that after compressing images and adding lazy loading, you'll increase the page loading speed up to 100%. Occasionally, it's even more than 100%.

Because websites are full of images and icons nowadays. You can apply lazy loading even on background images if you'll use my package.

If your web app uses plenty of SQL queries, then it's better to cache the results of those queries. You can gain lots of speed just out of it.

If you're a Laravel developer, then you're lucky because, in my opinion, Laravel is the best tool for creating fast and scalable websites. I've tried other languages and frameworks, and I haven't found anything better and simpler.

❤️ Thanks to flo222 for the beautiful photo for this post.

Keywords: speed, loading, compress, lazy, optimize, improve, fullstack, sitechecker