Skip to main content
Prevent js.Build from removing un-used Javascript functionality

Prevent js.Build from removing un-used Javascript functionality

Today, I reworked my theme changer script from vanilla JavaScript to an Alpine.js-based component. This change cut down the code lines by 50%. However, initially, it didn’t work. The console error messages indicated that my theme switcher function was unrecognized. Intrigued, I decided to investigate.

My setup uses js.Build, which integrates ESBuild into GoHugo.

Initially, my script was:

1import './scripts/theme-toggle';
2import Alpine from 'alpinejs';
3
4window.Alpine = Alpine
5Alpine.start();

The theme switcher function was within theme-toggle.js:

1function themeSwitcher() {
2  // function details
3};

And in my template, I initialized the theme switcher like this:

1<li class="nav-item" id="themeswitcher" x-data="themeSwitcher()">
2  ...
3</li>

The final JavaScript was built using js.Build and loaded into the page:

 1{{- $scripts := resources.Get "js/script.ts" |
 2      js.Build (dict "targetPath" "assets/js/script.js") |
 3      minify |
 4      fingerprint "sha512" -}}
 5<script
 6  src="{{- $scripts.Permalink -}}"
 7  async
 8  defer
 9  integrity="{{- $scripts.Data.Integrity -}}"
10></script>

Nothing too complicated, I thought, but still, on the console, I could see that while Alpine.js was properly initialized, the themeSwitcher function was not being recognized or found.

It turned out ESBuild was excluding the themeSwitcher function from the final build. I suspect it’s because the function wasn’t explicitly “used” elsewhere in the script, although it was clearly utilized in the theme.

After several trials (including an unsuccessful attempt to directly call themeSwitcher() in my JavaScript), I stumbled upon a straightforward solution. I registered the function in the window object, similar to how I did with Alpine:

1import Alpine from 'alpinejs';
2window.Alpine = Alpine
3function themeSwitcher() {
4  // function details
5}
6window.themeSwitcher = themeSwitcher;
7Alpine.start();

However, a minor issue arose with this change: Alpine.js generated a warning about being loaded before the <body> was fully available. To address this, and to ensure proper script loading order, I modified the Alpine.start() call to be done on DOMContentLoaded:

1import Alpine from 'alpinejs';
2window.Alpine = Alpine
3function themeSwitcher() {
4  // function details
5}
6window.themeSwitcher = themeSwitcher;
7document.addEventListener('DOMContentLoaded', () => {
8  Alpine.start();
9});

With this adjustment, everything fell into place smoothly. Feel free to maniacally toggle the theme switcher in the top right corner of this page to see the result.

Back to top