Codesplitting with webpack in a Laravel project

Consider a typical Laravel project in which we mainly use PHP in combination with blade views to render the pages. However, as time goes by, more and more interactivity is required for the website to work smoothly: A bunch of pages is enhanced with Javascript. Some Javascript runs on all pages (i.e. sliding menu, a twitter widget, google analytics script), other Javascript just runs on a single page or a specific set of pages. To decrease the number of scripts to load, we use a module bundler to create a single bundle to serve to our visitors. We minify that bundle. That’s it.

But wait, stopping right there is not optimal for the performance of your pages. Since we have a single bundle, this bundle is loaded and executed on every page. When you have a lot of pages and each page has some specific javascript, the bundle may become very large. And, all that code is loaded on each page, including the parts that are not even needed for the current page! With a few changes in your code you can utilise code splitting to solve this problem and only load the Javascript needed for a page. A quick win on performance!

Code splitting with Webpack

I make the strong assumption here that you use webpack to bundle your code, which is the default bundler in Laravel. Perhaps you can configure other module bundlers as well, but I only have experience with webpack.

According to the documentation of webpack on code splitting, there are three ways to apply code splitting to your code. This post will discuss the way I implemented code splitting using the ‘dynamic imports’ approach in our codebase. We use this approach as it seems easier compared to the other options.

Our current codebase already uses a single entry point for the Javascript, app.js.

In app.js, we load jQuery into the page followed by the responsive menu (on every page). On the homepage we require a slider and on a bunch of other pages we load a module scrollArrow.

Before watching the lightning talk by Sean Larkin at Vue Conf US, I had no idea where to begin with code splitting. As it turns out, code splitting comes in very handy when you have specific pieces of code on specific pages (split per route). Additionally, a piece of code that is only executed after clicking a button (‘temporal’ is how Sean Larkin called it) is also ready to be code splitted.

Splitting code on routes

If we want to apply code splitting to the my-owl-carousel module, (line 10–13 in app.js) it has to be written as an ES6 module. Then we need to use the dynamic import syntax inside the if statement that defines the homepage ‘route’:

We use a regular expression to check that we are on the homepage. Then we apply the new import syntax (note that it is not a function). Additionally, we use some special, recommended comments that are used by webpack: webpackChunkName defines the name of the compiled chunk of code. In this case we end up with a named chunk my-owl-carousel.js, while leaving this comment out will enumerate the chunks (1.js, 2.js etc).

The webpackPrefetch comment tells webpack that the module may be prefetched. This means the module will be loaded in the idle time of the browser, so the user won’t notice it! However, this is a Laravel project where Laravel-mix (wrapper around webpack) is used to compile the code. The webpackPrefetch comment is available from webpack >= 4.6. Unfortunately, Laravel-mix uses an older version of webpack at the moment. However Laravel-mix support for webpack 4 is in the works. Hence, I already add the webpack comment to benefit from once it comes to Laravel-mix.

The import syntax returns a promise. Once it resolves, we grap the module and apply the default function we exported in the module.

Compiled bundles

To make the property webpackChunkName work, I had to extend the output property of webpack in the webpack.mix.js file. I added the property chunkFilename like this (line 18):

This way, the compiled modules arrive neatly in my public/js folder as you see below.

Webpack output, all chunks have descriptive names and are placed in the public/js directory

Splitting ‘temporal’ code

We have a responsive menu on the website, but the code that shows and hides the menu only has to be available after clicking the menu button. A perfect way to apply code splitting on this ‘temporal’ code. The code looks like this:

Once the mobile menu link, defined by the selector #header_mobile a is clicked, the menu-mobile module is imported dynamically.

Routes and temporals

In the final example we’ll use code splitting twice. The use case here is that we have a bunch of pages where we have a button. Clicking the button scrolls down the page and shows a form. Hence, the scroll-and-show-form module is dynamically imported only on these pages:

The scroll-and-show-form module itself looks like this:

Hence, only after a button click, the form is shown to the user and the form-validation module is imported.

Summary and wrap up

In this post I discussed two ways to apply code splitting using dynamic imports. The first example treated code splitting based on the route to make sure we only load the code on pages that need it. The second example treated code splitting on ‘temporal code’. This enables us to only load the code once it is needed (comparable to lazy loading of images). The last example combines these two approaches.

Like what you read? Give Pim Hooghiemstra a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.