Hi, I am Artem and I am front-end developer. In my everyday work, I face with the styling of Drupal sites.
In this article, I am going to share my experience in integrating dynamic imports, splitting code into small chunks in Drupal 8. Also, I am going to show you how to write a webpack plugin that automatically connects these chunks with Drupal. With this plugin, you will not worry about the new chunk that needs to be connected, whether it is some js module or a piece of CSS.
What you need for comfortable usage of sites
When you open a web page, you definitely pay attention to its loading speed. Of course, no one wants to look at a blank page that is going to show you a super design with interesting animations but it takes ages to load. There can be many reasons for the long loading and not all of them are directly related to the size of the code that the browser is trying to load and execute. But the size of a bundle still plays a big role, especially with the advent of http2, where the main emphasis is put on speeding up multi-threaded loading of small packages.
So how can we deliver the code to the browser as efficiently as possible so that it does not overload and does not get anything else instead of the desired content? Try to answer this question by considering the chunks and dynamic imports solution.
Chunks and dynamic imports in Drupal
What we mean by “Chunks and dynamic imports”: it is splitting one large piece into smaller ones and having them lazy loaded if needed. Let's see how it can be implemented in Drupal 8 with examples.
I decided to keep up with the trends in our beloved front end world and write a config for the webpack dividing our bundle into two, to begin with: one for the Browser-That-Must-Not-Be-Named, the other for modern browsers that support all the main features of ES6 without compiling.
This will allow us to reduce the size of our bundle even more, even without chunks optimization. Such magic is possible thanks to the type=”module” attributes and the nomodule script tag. Modern browsers see the script with the type = ”module” attribute and execute it. I insert these chunks into the head tag to start loading the script as quickly as possible and this happens asynchronously without blocking the page rendering because the type = ”module” is asynchronous by default. If the browser is old (IE), then it does not know about the script with the type = ”module”: it skips it and executes the script with the nomodule attribute.
As a result, we obtain approximately the following document structure:
The problem is that each chunk connects to Drupal using yaml files. With this method of code separation, it becomes inconvenient for us to write every dependency manually, so we will write a small webpack plugin that solves this problem. It uses the hook that provides the HtmlWebpackPlugin and at the stage of forming the “link” and “script” tags, our webpack plugin writes the generated tags in the libraries.yml and info.yml files.
We form link tags by adjusting the paths:
The writeCSSAsset function has a simple view and saves the resulting CSS assets.
We form script tags by adjusting the paths and dividing the bundles into 2, one for modern browsers, the other for IE. Also, here each of these bundles is divided into chunks:
The writeJSAsset function is simple and it saves the resulting js assets.
After that, we write the resulting chunks in our yaml files.
As a result, we get the structure of our generated yaml files:
We received all of this automatically and with further work and compilation of new chunks, they will be updated. Dynamic imports are not added here because we do not want them to be pushed to our page right away so that they remain dynamic.
Approximately this file structure is obtained at the output, here you can notice the 0.js and import2.js files that are not registered in libraries.yml. These are just dynamic imports that are written in the code, for example, like this:
Here, the import-2.js module will be dynamically loaded onto the page by clicking on the document (don’t ask me when it may be needed, it is just for the sake of example).
If you assign a name to the module’s import as shown in the example above, webpack will use it, if not, then it will be just the id of the chunks starting with 0.
Thus, you can come up with an interesting logic of lazy loading scripts using this technology and all of this will work in Drupal.
For example, when you click on a submit button, you can launch a pop-up code that will be pushed to the page and immediately executed.
I deliberately omitted an internal implementation of functions not to inflate the article, you can familiarize yourself with the sample code through the link to the repository which I will leave below.
Conclusion and a little gift
In this article, I showed a possible way to optimize the client side of Drupal. I hope that you will be inspired by the examples presented above to create new and easy-to-use modules that make the Drupal front-end developer’s life easier.
To check what I have made, you need to create a Drupal project and then put this repository to the theme folder.