Skip to content
This repository has been archived by the owner on Jul 19, 2021. It is now read-only.

Cannot reference js.liquid files in theme.liquid #720

Closed
johnytotheg opened this issue Aug 29, 2018 · 15 comments
Closed

Cannot reference js.liquid files in theme.liquid #720

johnytotheg opened this issue Aug 29, 2018 · 15 comments

Comments

@johnytotheg
Copy link

Problem

Referencing js.liquid files in theme.liquid returns a 404 (Not Found) error. From my understanding javascript files are supposed to be served from localhost:8080 but the script tag in page source is attempting to fetch from //cdn.shopify.com/s/files/1/0027/8672/1904/t/2/assets/product-filter.js?11934124183750268063 which returns a 404.

product-filter.js.liquid is showing in dist/assets.

Replication steps

I have referenced the file like so <script src='{{ "../assets/static/product-filter.js" | asset_url }}'></script> in theme .liquid. I have added the file 'product-filter.js.liquid' to src/assets/static.

More Information

I have also tried referencing the file in the following ways:

<script src='{{ "product-filter.js" | asset_url }}'></script>

<script src='{{ '../assets/static/product-filter.js' | asset_url }}'></script>

<script src='{{ 'product-filter.js' | asset_url }}'></script>

@callaginn
Copy link

I've been dealing with this same issue all day. If you put JS in any of the /src/assets folders, they don't get compiled to the /dist folder. And if you insert them into the /dist/assets folder, they don't get automatically uploaded. Instead, you have to upload them via the themes manager in the web interface.

Slate v0 was simple, but v1 has been throwing me for a loop. Have you figured out how to insert JS files into the templates yet?

@dan-gamble
Copy link
Contributor

Is there any reason you're trying to add an additional JS file manually instead of letting Webpack handle it? I don't think there are many reason to manually want to include a JS file like this in Slate v1.

If it's a case of only wanting to load it under certain conditions the Slate Webpack build handles this with lazy loading. If you'd like me to elaborate on this, let me know.

@johnytotheg
Copy link
Author

Hi Dan,

Is it possible to elaborate a little further? I basically need the javascript to fire on Collections and Index Templates. Should I be creating a separate modules folder within assets? Cheers

@dan-gamble
Copy link
Contributor

You can create a new file in assets/scripts/templates/collection.js and have your code in here then you could import relevant modules if need be.

This means this file will only load when on the collections page so you have a smaller initial footprint for your users.

If you could show me the contents of your product-filters.js i could show you what the file should look like.

@callaginn
Copy link

callaginn commented Aug 30, 2018

@dan-gamble Usually I build websites using CodeKit frameworks stored on my local machine. Ideally, I'd like to continue pulling files from the same location as my previous framework -- just don't know how via Webpack.

With Slate v0, I was able to use CodeKit to compile JS files to the /src/scripts/ folder and SCSS files to the src/styles/ folder. This no longer works with Slate v1 though; I believe Slate's addition of Webpack has complicated things a bit.

If I'm understanding you correctly, I should create a new javascript file in /src/assets/scripts/templates that mirrors the name of whatever template it needs to be inserted into? So if I'm trying to include javascript code into page.template, I should add imports into a new file called page.js?

I added a simple console.log tag to a new /src/assets/scripts/page.js file while running yarn watch and nothing happened. I would expect it to automatically get uploaded to the assets folder in Shopify, but it doesn't. Adding anything to /src/snippets, on the other hand, DOES get uploaded as expected. Why in the world does Slate v1 make adding JS/CSS so convoluted?

@johnytotheg
Copy link
Author

Thanks for the help!

Essentially it would probably look something like this:

function getFilterProducts(tag){
    $.ajax({
        type: 'GET',
        url: '/products.json',
        dataType: 'json',
        success: function(res){
            filterProducts(res.products, tag)
         },
        error: function(status){
             alert(status);
        }
    })
}

function filterProducts(products, tag) {
    var filteredProducts = products.filter(function(product){
        return product.tags.indexOf(tag) > -1;
    });

}

$(function(){
    $('.js-collection-filter').on('change', function(){
        var tag = $(this).val()
        getFilterProducts(tag)
    });
});

So also making use of jquery for Ajax calls.

@dan-gamble
Copy link
Contributor

dan-gamble commented Aug 30, 2018

Hey @johnytotheg,

So what your src/assets/scripts/templates/collection.js would like like is:

import $ from 'jquery';

function getFilterProducts(tag){
    $.ajax({
        type: 'GET',
        url: '/products.json',
        dataType: 'json',
        success: function(res){
            filterProducts(res.products, tag)
         },
        error: function(status){
             alert(status);
        }
    })
}

function filterProducts(products, tag) {
    var filteredProducts = products.filter(function(product){
        return product.tags.indexOf(tag) > -1;
    });

}

$(function(){
    $('.js-collection-filter').on('change', function(){
        var tag = $(this).val()
        getFilterProducts(tag)
    });
});

This should then work, only thing worth nothing is adding this file before you run yarn start. If you add it while yarn start is running then it won't be found.

If you could add that file and then try yarn start and let me know if that works we can take it from there 🤙

@dan-gamble
Copy link
Contributor

@callaginn

Slate v1 has embraced the current Javascript ecosystem which unfortunately is a little harder to understand and get working but reaps so many rewards so it's definitely worth getting up to speed with it.

Depending on what your page.js file is doing you'd add it to a few different places. If you wanted it to work on certain pages you could do the same as what i mentioned above but save it under src/assets/scripts/templates/page.js. Then this file would get automatically included on your page templates and would only run on them. This helps keep your initial bundle size smaller and provides a better end experience for your users.

Anything else hit me up 😊

@johnytotheg
Copy link
Author

Ah thank you! I hadn't tried re-running yarn start. I'll give this a go 👍

@callaginn
Copy link

@dan-gamble Ok. My tests are showing that page.js is getting compiled to any template / subtemplate of page.liquid. That is, page.liquid, page.contact, page.calendar, etc.

How is Webpack better than simply using liquid if then statements like this? My best guess is that it has something to do with being able to bundle page-specific files, instead of including a bunch of smaller ones. However, Codekit was already capable of doing that with Slate v0:

{% template == 'page' %}
    {{ "page-bundle.min.js" | asset_url | script_tag }}
{% endif %}

I've got a few questions related to that:

  • Is there a way to add these bundles without constantly restarting yarn?
  • Is there any way to make it target page.liquid and NOT any of the subtemplates?
  • How would you add scripts to multiple pages at once? Or does that require creating multiple files?

P.S. Thanks for all your help, by the way. The documentation is as clear as mud on a lot of this stuff.

@dan-gamble
Copy link
Contributor

One of the benefits is that your Javascript is all coming from a single source and is using modules. When you're using separate files like the above any kind of sharing will come from global state.

The way the separate files are also all done automatically for you by just placing a file in a directory instead of having to maintain them in liquid via if statements and then having the file as well. You could in theory change a name in 1 place and forget to change it in the other, a slight benefit.

The above are just references to the way Javascript is included on your page. Webpack as a whole offers tons of benefits over a traditional "include a script on a page Javascript" approach, too many to list here.

  1. If you know what bundles you are intending to add you could just add the Javascript files and leave them blank and then just use them when you come to it. This would stop you having to restart a lot. If you don't know then restarting is unfortunately the only way but you shouldn't be having to add a lot of these as there is only a finite amount you can add.

  2. Not currently but i believe they are looking in to it here(Template and layout bundles are not generating for page.*.liquid templates #707)

  3. See below

The way i approach this is a bit like the dynamic entrypoints but it doesn't actually create a new entry point.

In my theme.js i have:

  Array.from(document.querySelectorAll('[data-module]')).forEach(el => {
    const name = el.getAttribute('data-module')
    const Module = require(`../modules/${name}`).default
    new Module(el)
  })

And then in my liquid files i would add data-module="module-name" where i would be wanting the Javascript to run.

I'd then add src/assets/scripts/modules/module-name.js with the contents of:

export default {
  constructor (el) {
    this.el = el
  }
}

And then any code i wanted would go in this file. Then for each location you wanted it to run you'd just add the data-module="module-name". This way i again don't pollute the main Javascript bundle with stuff that doesn't need to be in it. I only serve this Javascript to the user when they need it. It's particularly helpful if you're including large libraries as the user won't need this on every page, just certain ones.

Again, hope this helps!

@callaginn
Copy link

callaginn commented Aug 30, 2018

I've working through the way you add scripts to multiple pages at once. I've had some success with this, but see an "Uncaught TypeError" in my Chrome console:
screen shot 2018-08-30 at 2 00 18 pm

Changes Made

  1. Inserted your "Array" code to the bottom of my theme.js file.
  2. Assuming the module JS file could be named anything, I inserted the following code into src/assets/scripts/modules/test-module.js:
    export default {
      constructor (el) {
        this.el = el
      }
    }
    
    console.log("This is a custom module")
    
  3. I then inserted this snippet into one of my Shopify templates. It is my understanding that this data-module tag could essentially be added to anything -- whether it by a body tag, section tag, etc:
    <div data-module="test-module"></div>
  4. Quit the current yarn process and restarted: yarn start

What Works

I confirmed that the test code shows up in the correct Shopify template via the JS console statement and that it doesn't show up in any other template.

Possible Issue

However, the Chrome console "Uncaught TypeError" in the screenshot above makes me think something is incorrect. Should I be worried about that?


FYI: Examples like that would be useful to add to the Slate v1 document, for anyone unfamiliar with how Slate v1 works with Webpack. I just know I'm not familiar enough at this yet to be editing the documentation.

@dan-gamble
Copy link
Contributor

Sorry Stephen, my code should have read:

export default class TestModule {
  constructor (el) {
    this.el = el
  }
}

This is purely my own idea on how i've just worked with Webpack before, it's not anything to do with Slate so it makes sense for it not to have been documented.

Could be helpful to have just some generic Javascript help pointed to somewhere as v1 is a very big jump from v0 but i'm sure it will come over time. Remember Slate is still very much in beta.

@t-kelly
Copy link
Contributor

t-kelly commented Oct 25, 2018

@lock
Copy link

lock bot commented Nov 24, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Nov 24, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants