How do .js and .js.liquid file types differ in Shopify themes?

I’m working on a Shopify theme and noticed two types of JavaScript files in the assets folder: .js and .js.liquid. What’s the main difference between these? Which one should I use for adding JavaScript to my theme?

I’m trying to create a string with Liquid variables in a .js.liquid file, but it’s not showing up when I add it to the DOM. Here’s what I’ve got:

let itemString = '';
{% for item in cart.items %}
itemString += `qty=${item.quantity}&id=${item.product_id}&price=${item.price}&weight=${item.weight}&image=${item.image|img_url|escape}&name=${item.title|escape}&`;
{% endfor %}

document.body.innerHTML += itemString;

Any ideas why this isn’t working? Thanks for your help!

Hey there! I’ve been working with Shopify themes for a while now, and I can shed some light on this. The main difference is that .js.liquid files allow you to use Liquid tags, which is super handy for injecting dynamic data from your store into your JavaScript.

For your specific issue, I’d suggest a couple of things. First, make sure you’re escaping your output properly. Liquid’s | escape filter might not be sufficient for JavaScript strings. Try using | json instead, which will properly encode the data for use in JS.

Also, instead of directly manipulating the DOM, it’s often better to use a hidden input or data attribute to pass the data from Liquid to JavaScript. Something like this:

<script type="text/javascript">
  var cartItems = {{ cart.items | json }};
</script>

Then in your JS, you can work with the cartItems object directly. This approach is cleaner and less error-prone in my experience. Hope this helps!

The key distinction lies in the processing of these files. Standard .js files are served directly to the browser, while .js.liquid files are processed server-side before being sent. This allows you to incorporate dynamic Shopify data into your JavaScript.

For your specific issue, I’d recommend a different approach. Instead of building a string with Liquid and injecting it into the DOM, consider serializing the cart data on the server and passing it to your JavaScript. You could do this in your theme’s layout file:

<script>
  var cartData = {{ cart.items | json }};
</script>

Then in your .js file, you can work with this data directly:

let itemString = cartData.map(item => `qty=${item.quantity}&id=${item.product_id}&price=${item.price}&weight=${item.weight}&image=${item.image}&name=${encodeURIComponent(item.title)}`).join('&');
console.log(itemString);

This approach is more robust and easier to debug. Remember to use appropriate encoding for the parameters to avoid issues with special characters.

yo, .js files are plain js while .js.liquid lets u use liquid tags to access shopify data. try using single quotes instead of backticks and check if ur file is loaded properly. maybe check the console for errors.

hey man, .js.liquid lets u use liquid tags in js, which is neat for dynamic stuff. for ur issue, try this:

let itemString = ‘’;
{% for item in cart.items %}
itemString += ‘qty=’ + {{ item.quantity | json }} + ‘&id=’ + {{ item.product_id | json }} + ‘&price=’ + {{ item.price | json }} + ‘&weight=’ + {{ item.weight | json }} + ‘&image=’ + {{ item.image | img_url | json }} + ‘&name=’ + {{ item.title | json }} + ‘&’;
{% endfor %}

console.log(itemString); // check if it works

As someone who’s been in the Shopify trenches, I can tell you that .js.liquid files are a game-changer when you need to mix Shopify data with your JavaScript. They’re processed server-side, so you can inject dynamic content before it hits the browser.

For your specific issue, I’d suggest a slightly different approach. Instead of building that string directly, try serializing the cart data in your theme’s layout file:

<script>
  window.cartItems = {{ cart.items | json }};
</script>

Then in your JavaScript, you can work with this data more easily:

let itemString = window.cartItems.map(item => 
  `qty=${item.quantity}&id=${item.id}&price=${item.price}&weight=${item.weight}&image=${encodeURIComponent(item.image)}&name=${encodeURIComponent(item.title)}`
).join('&');

console.log(itemString); // Check the output

This method is cleaner and less prone to errors. Plus, it keeps your Liquid and JavaScript logic separate, which is always a good practice. Give it a shot and let me know if you run into any issues!