Theme Build and Configuration
Topics covered in this tutorial:
1. What Is Webpack?
Webpack allows us to bundle a theme or an application. It’s run in the development set-up in order to create prioritized bundles of modules and files that will then be run as the application starts.
The reason why we need to bundle our application is because assets like (images, styles, modules etc.) are not included by default. Furthermore, there are a number of features that are not unanimously supported by all browsers.
For example, we can type:
Keep in mind that the node_modules
folder is never shared, so we can’t access the exact 'react'
file from there and we would not be able to open this file in a browser.
If we try:
The browser won’t understand the .scss
file, so we will need to transform it into a .css
file. The browser also doesn’t know what 'react'
or the other modules are, so we need to include them into our script as well.
Things like arrow functions ( ) => {…}
, classes and class proposal properties (e.g., prop = 1;
) are not included by default or supported by most browsers, so we need to transform these features into a format that older browsers will understand. Simply put, if the code is written in ECMAScript5, we need to find a way to transform it into ES2015.
Luckily, webpack has a different tool for each of these transformations.
webpack
in itself is responsible for handling the imports and their dependenciesbabel-loader
– helps you compile code from newer versions of JavaScript down to a version that will be supported by your environmentsass-loader
– transforms the more easily maintainable .scss files to .css files
So, what are these loaders? Loaders are webpack features that allow you to load a specific type of asset.
Let’s look at a simple CSS flexbox example, using the shorthand flex
, which combines flex-grow
, flex-shrink
and flex-basis
:
Due to the fact that not all browsers support the shorthand properties of flex
, we need to add certain vendor prefixes to it, in order to make our code render the same way in different browsers. The prefixes are as follows -webkit
for Chrome and Safari, -moz
for Firefox, -o
for Opera and -ms
for Internet Explorer.
Fortunately, webpack has a postcss-loader
, which will do this for you using the autoprefixer
plug-in. So, the processed code will look something like this:
It might be inconvenient in development to import or load CSS files as they are. For example, if we have multiple CSS files, we don’t want them to load one by one. We might want them to load simultaneously or we might want them to load inside JavaScript. This can also be done by different webpack loaders.
To quickly sum up, webpack is a code transformation tool that can handle JavaScript and other files using various loaders. It will take your source files and output transformed files into a destination folder, while also simultaneously optimizing the code, plugging in extensions, or performing other tasks that you’ve set.
webpack: Source And Destination Folders
Let’s look at our folder structure:
So, what happens when you run webpack
? It takes a source with all of its contents, e.g. src/
and outputs it into a destination, for example Magento_Theme/
.
In this case webpack
or more specifically html-webpack-plugin
will take the index.production.phtml
or index.development.phtml
and rename it to root.phtml
and place it into Magento_Theme/templates
folder.
Now Magento will understand that there’s a theme that’ll override the root template. Same with JavaScript and style files, which after processing will appear in the Magento_Theme/web
folder. This is how webpack
helps Magento understand ScandiPWA as a theme.
2. Differences Between Production And Development Set-Up
If we take a look at the root.phtml
and index.production.phtml
files, we can see that they’re very similar. However, the style files will look completely different. This is because, in the process of parsing the code, the babel
plug-in will transform and optimize it.
This is where the differences between the production and development set-up will come in.
PRODUCTION | DEVELOPMENT |
Code Minification And Splitting
In the production set-up code will be minified by the babel
plug-in, i.e. all of the unnecessary characters will be removed, making it appear as a single line.
Webpack
will ensure that the code will get split into multiple parts, in this specific case its 20 bundles. Code splitting allows us to load the code when needed, thus making the website faster and more efficient. Besides bundling, webpack
also ensures that the code is loaded as needed according to priority.
The manifest
manifest
Let’s look at the manifest
a little. It doesn’t differ between the development and production set-ups. The manifest
is a specific feature of PWA or Progressive Web Applications in general. It is automatically generated and allows us to install the application correctly.
PWA manifests usually include things like the app name, author, version, description and a list of resources among other things.
Service Worker Pre-cache
The precache-manifest
, however, is only generated in production. Service Worker Pre-cache will download all of the split code or bundles by itself without a specific request and return the bundles immediately when requested.
The pre-loaded bundles will also ensure that all of the application will be available to you offline even though you haven’t visited it. This only applies to the application’s parts like ‘my account’, ‘card’, ‘checkout’, etc., not the actual data.
The Source Map
One of the things that only appears in development is a source map. Source maps provide a reference for the code, mapping the minified or transformed code to the original source, thus being a handy debugging tool.
The Hot Reload
Not all of the logic can be executed in development mode.
If we go to the source
folder and open the main index.js
file, we can see that some logic runs only in development, more specifically it’s the hot reload.
The value process.env.NODE_ENV === ‘development’
ensures that our React application or any other dependent application will have hot reload enabled, that is - the app will reload automatically any time our code changes.
The app is kept running on the development server with periodic injections of new file versions that are edited at runtime. The main plus of hot reload is the fact that the app’s state is not lost, which is especially useful when customizing a theme.
The Development Server
The development server is what allows us to use hot reload and memory cache. Only changed files are regenerated, which allows us to perform bundling quicker.
This is why if you run npm run build
it takes a long time every time, but if you run npm run watch
it takes a long time only once and any subsequent loads will be quick.
The HTML Entry File
Another thing that differs between the production and development set-up is the HTML entry file. In a production environment, this file is called index.production.phtml
and in development, it’s index.development.html
.
Debugging And Building
It’s worthwhile mentioning that in production set-up, the build process itself is different, i.e. the production set-up application follows a two-step build process where first the Service Worker Pre-Cache is built, after which the actual application is built.
And lastly, the biggest difference in terms of debugging is the fact that no files are generated in development mode, due to the development server’s memory cache. This can be seen by browsing our folder structures. In development mode the Magento-Theme
folder will not appear.
3. The config
Folder
config
FolderA brief overview of the config
folder would be as follows:
webpack.development.config.js
andwebpack.production.config.js
The differences are as mentioned in section 2.
webpack.extract-translations.config.js
Extracts the internationalization strings from the application. We need to do this periodically in order to update the
.json
files with new translations.
We can execute this webpack config file by running the extract-translations
command. We can execute npm commands by typing npm run <name-of-command>
, e.g. npm run extract-translations
, you can read more about npm here. Running a npm command this way ensures that the configuration preset in package.json
file is used.
webpack.sw.config.js
The Service Worker configuration file is a part of the two-step build production set-up.
webpack.core.config.js
Configuration of core contribution.
babel.config.js
Configuration of the
babel-loader
. Read more in webpack documentation, as well as babel documentation.
meta.config.js
Configuration of meta tags that need to be included into our HTML document.
4. Available Commands
npm or Node package manager allows us to use some nifty aliases that are defined in the package.json
file. This file can be found in the main source
folder.
npm run build
is the most valuable command preset in the package.json
file, because running it allows Magento to recognize a production ready theme.
These are only two of the ready made scripts. Check out more npm presets in the package.json
file.
What To Run In Which Situation?
If you’re using our Docker environment you don’t have to run anything. Docker does the job on its own.
However, if you decide to develop on your local machine, the following commands might come in handy:
npm ci
npm ci
If you’re running an existing Magento instance and you want to install a theme you need to run npm ci
first. Not npm install
or npm i
.
npm ci
ensures that you’ll get a more reliable build by firstly deleting your node_modules
folder giving you a fresh start, as well as looking into your package-lock.json
file and installing dependencies of a specified version, instead of modifying the package-lock.json
file like npm i
does.
npm ci
is a security measure that allows us to not break our replication in case of one of the dependencies having a new broken minor release.
npm run build
npm run build
The next command you run will be different depending on your needs. If you want to compile a theme and test if Magento is able to recognize it, you need to run npm run build
. This will build the theme and generate a Magento_Theme
folder.
If you have the Magento_Theme
folder with root.phtml
file and web
folder, it means that Magento should be able to recognize the theme.
If your application has the Magento_Theme
folder with its contents, but Magento is not able to recognize the theme, you should check the Magento tables and look whether your theme’s name is added to the list.
npm run pm2-watch
npm run pm2-watch
This command will start the development server, which will be restarted every time you create a new folder. You need to restart the server when creating a new folder because of the memory cache. If you’re creating a new folder with what you want to override a specific component, you need to recompile and the pm2
or process manager will handle this and restart the watching process.
The development server will be started in the port :3003
, keep in mind that Magento might not function properly, because the request to /graphql
might not be properly sent.
In this case you might need to change the request-URI constant cons REQUEST_URI
in the util-request
which can be found in source
.
Another approach would be by adding a NGINX config, which you can locate in our front-end configuration containers as well.
If none of these solutions work, we would recommend developing your application in our Docker environment which includes everything you need to start building applications seamlessly.
npm run extract-translations
npm run extract-translations
This command will parse through all of your files and find every single template literal ( —(` `); ) that you’ve added. Notice that there should be a simple string in between the backticks, not a variable. After that, the contents of the backticks will be put into the i18n
internationalization folder under the specific language, e.g. all English strings will be appended to the en_US.json
file.
If a language file’s string translation is null
, that means that we don’t have a translation for the specific term at the moment, so feel free to contribute if you know the language.
To Docker Or Not To Docker?
The use of npm run build
, npm run pm2-watch
and npm run extract-translations
is not needed if you choose to develop in our Docker environment. These commands will only be required if you decide to install on your local machine.
However, the command npm ci
is always needed when you pull the latest changes, because we want to make sure that the latest working versions of the packages are installed.
Last updated