JavaScript code compression causes issues with DOM element selection

I have a JavaScript function that works perfectly on my local machine, but when I deploy it to a platform that compresses the code, it starts failing. The issue seems to be with querySelector not finding elements that definitely exist in the DOM.

function attachProfileHandlers(profileImg) {
  var profileWrapper = profileImg.parentNode;
  console.log(profileWrapper); // This works fine
  var profileDetails = profileWrapper.querySelector('.profile-info');
  console.log(profileDetails); // This returns null after compression
  profileImg.addEventListener('mouseenter', showProfileInfo);
  profileDetails.addEventListener('mouseenter', showProfileInfo);
}

The error I get is: Uncaught TypeError: Cannot read property 'addEventListener' of null

What’s weird is that a similar function in the same script works without problems:

function showProfileInfo() {
  var profileWrapper = this.parentNode;
  var profileDetails = profileWrapper.querySelector('.profile-info');
  console.log(profileDetails); // This finds the element correctly
  changeVisibility(profileDetails, 'hide', 'show');
}

Here’s my complete code:

'use strict';

var profileImages = document.querySelectorAll('.profile-img');

var changeVisibility = function(element, stateOne, stateTwo) {
  element.setAttribute('data-visibility', element.getAttribute('data-visibility') === stateOne ? stateTwo : stateOne);
};

function showProfileInfo() {
  var profileWrapper = this.parentNode;
  var profileDetails = profileWrapper.querySelector('.profile-info');
  changeVisibility(profileDetails, 'hide', 'show');
}

function attachProfileHandlers(profileImg) {
  var profileWrapper = profileImg.parentNode;
  var profileDetails = profileWrapper.querySelector('.profile-info');
  profileImg.addEventListener('mouseenter', showProfileInfo);
  profileDetails.addEventListener('mouseenter', showProfileInfo);
  profileImg.addEventListener('mouseleave', showProfileInfo);
  profileDetails.addEventListener('mouseleave', showProfileInfo);
}

for (var i = 0; i < profileImages.length; i++) {
  attachProfileHandlers(profileImages[i]);
}

And the HTML structure:

<div class="profile-wrapper">
  <div class="profile-img">
    <img src="photo.jpg"/>
  </div>
  <h4 class="profile-name">John Doe</h4>
  <h5 class="profile-role">Developer</h5>
  <div class="profile-info" data-visibility="hide">
    <p>Profile information here</p>
  </div>
</div>

Any ideas why code compression would cause querySelector to fail in one function but not another?

Compression might be breaking your variable names and function references. Try this fallback: profileDetails = profileDetails || profileWrapper.querySelector('.profile-info'); - minifiers sometimes mess with querySelector context in weird ways.

maybe the minified code has changes in loading order; ensure DOM is fully loaded before you call attachProfileHandlers. Also, watch for scope issues that compression might introduce. check console for any errors in the compressed version.

Code compression strips whitespace and comments, which changes execution timing. Your functions run at different times - attachProfileHandlers fires during page load, while showProfileInfo triggers on user clicks. When compressed, your script can run faster than the DOM builds, so .profile-info elements might not exist yet when you’re looking for them. I hit this same issue in production where minified JS ran way faster than the uncompressed version. Fixed it by adding a small delay or using requestAnimationFrame before querySelector calls in my init functions. You could also just check if profileDetails exists before adding listeners - that’ll stop the null reference errors completely.

The timing’s probably your issue. attachProfileHandlers runs right when the page loads, but the DOM elements might not be ready yet. Meanwhile, showProfileInfo runs later when users interact with stuff - everything’s definitely loaded by then. Code compression messes with execution timing and makes this race condition way more obvious. I’ve hit this before where compression changes how fast scripts run compared to DOM rendering. Wrap your initialization in a DOMContentLoaded listener or add a null check before you touch profileDetails. The compressed version likely runs faster than your local code and hits the DOM before .profile-info elements are actually there.

Been there, done that. Everyone’s right about the timing issue, but there’s a way cleaner solution than adding delays or manual checks.

You’re manually juggling DOM timing, element selection, and event binding. That gets messy quick, especially when compression messes with execution order.

You need automation that handles the timing for you. I built a workflow that watches DOM changes, waits for elements to load, then auto-attaches event handlers when everything’s ready.

No race conditions. No null checks everywhere. The automation handles timing so your code works the same compressed or not.

You can also add retry logic for missing elements and chain DOM operations reliably. Way better than guessing when things load.

This DOM automation saved me hours of debugging on similar projects. Check it out: https://latenode.com