Skip to main content

Theme Bootstrap Process

When using Nx-Shopify, the theme's CSS styles and JavaScript scripts are loaded automatically for you. You do not need to move a finger. However, is still important to understand how this process is done in case of needed modifications.

tip

If you want to follow this explanation step-by-step, it is recommended to generate a theme so you can read the code by your self ๐Ÿ™‚

nx g @trafilea/nx-shopify:theme my-theme

The main.ts file#

The main.ts file is the, well, main entrypoint of a Nx-Shopify theme. This is the very first code that is executed when a theme is loaded by a web browser.

For a recently generated theme, the main.ts content should look something similar to this:

src/main.ts
__webpack_public_path__ = window['__webpack_public_path__'];
import { themeBootstrapFactory } from '@my-org/my-theme/core/theme-bootstrap';
import { themeLayouts } from '@my-org/my-theme/theme/layout';
import { themeTemplates } from '@my-org/my-theme/theme/templates';
window['themeBootstrap'] = themeBootstrapFactory(themeLayouts, themeTemplates);

This file fullfills two key responsabilities:

  1. Make the webpack public path available to webpack.
  2. Define the global themeBootstrap function that will load the rest of our code.

Let's break this down...

Webpack public path#

The top-level __webpack_public_path__ variable is used to tell webpack, at run-time, what URL path it should look to download the rest of the chunks that will be loaded later (lazy loaded chunks).

As you may notice, this URL path comes from a window global variable called the same way. But, where does the value come from? The answer is that Nx-Shopify does this for you:

For every built theme, two special snippets are created:

dist/apps/my-theme
โ”œโ”€โ”€ assets
โ”‚ โ”œโ”€โ”€ (...)
โ”‚ โ””โ”€โ”€ main.77d0b739d857080b2b1e.js
โ”œโ”€โ”€ config
โ”‚ โ””โ”€โ”€ (...)
โ”œโ”€โ”€ config.yml
โ”œโ”€โ”€ layout
โ”‚ โ””โ”€โ”€ (...)
โ”œโ”€โ”€ locales
โ”‚ โ””โ”€โ”€ (...)
โ”œโ”€โ”€ sections
โ”‚ โ””โ”€โ”€ (...)
โ”œโ”€โ”€ snippets
โ”‚ โ”œโ”€โ”€ (...)
+โ”‚ โ”œโ”€โ”€ script-tags.liquid
+โ”‚ โ””โ”€โ”€ webpack-public-path.liquid
โ””โ”€โ”€ templates
โ””โ”€โ”€ (...)

snippets/script-tags.liquid#

This snippet renders the webpack-public-path snippet content and also adds the script tag that loads the main.ts entrypoint generated by webpack.

{% render 'webpack-public-path' %}
<script
type="text/javascript"
src="{{ 'main.77d0b739d857080b2b1e.js' | asset_url }}"
defer="defer"
></script>

snippets/webpack-public-path.liquid#

This particular snippet executes a liquid code in charge of getting the base path of the Shopify's CDN url where the assets are located and assign it to the window.__webpack_public_path__ global variable.

{% assign randomFile = 'randomFile.js' | asset_url %} {% assign cdnPath =
randomFile | split: 'assets/randomFile.js' | first %}
<script>
window.__webpack_public_path__ = '{{ cdnPath }}';
</script>

Once the above runs, webpack knows where to download the rest of our code chunks.

themeBootstrap function#

As shown in the main.ts assignment, the themeBootstrap function is created using a factory function inside the src/core directory called themeBootstrapFactory.

The themeBootstrapFactory function is a high order function that receives the theme registeredLayouts and registeredTemplates as arguments (see next section) and returns a function that takes a ShopifyBootstrapOptions object used to initialize the theme, which will be the themeBootstrap function.

Theme layouts & templates Objects#

The registeredLayouts and registeredTemplates objects are reponsible of making the layout and templates TypeScript code available to the themeBootstrap function.

The composition of these objetcs are a key-value pairs. Each key corresponds to the name of the layout or template that will be loaded and the value is a function that uses webpack's dynamic import syntax to load the respective theme block, that function will be invoked by the themeBootstrap function.

Example:

const registeredTemplates = {
index: () => import('./index/index.template').then((m) => m.IndexTemplate),
blog: () => import('./blog/blog.template').then((m) => m.BlogTemplate),
};

These objects are defined, by default, in the following files:

  • src/theme/layout/theme-layouts.ts
  • src/theme/templates/theme-templates.ts

Calling the themeBootstrap function#

The themeBootstrap global function defined in the src/main.ts file is wired to take care of the theme initialization as explained above. Now, when is this function called?

At the end of every layout liquid file, a script tag contains the JavaScript code that calls the themeBootstrap function.

<html>
...
<body>
...
<script>
window.addEventListener('DOMContentLoaded', function() {
window.themeBootstrap({
themeLayoutName: 'theme',
themeTemplateName: '{{ template }}',
themeContext: {% render 'theme-context' %},
loadGlobal: true,
});
});
</script>
</body>
</html>

Notice that the ShopifyBootstrapOptions argument is passed and it contains:

  • The layout name that should be loaded
  • The template name that should be loaded
  • The ThemeContext object (rendered by a snippet)
  • The loadGlobal flag
tip

Learn more about the ThemeContext object at the Liquid To TypeScript Context guide

When the loadGlobal flag is set to true, the ThemeGlobalModule found in the ./src/global will be loaded for any layout/template.