barba icon indicating copy to clipboard operation
barba copied to clipboard

CSS file doesn't load on page transition

Open Damiano31 opened this issue 6 years ago • 32 comments

Hi, I have a problem with the css and js files. I would like to use different style sheets and scripts on the various pages. when I open the page everything normally works, but when I change the page using the transition it is not loaded. How can I solve it?

for example in the contact page i want to use contact.css. contact.css is used only in this page. when I access the page directly the css works correctly but when i came from (for example) index.html that doesn't have contatti.css the style doesn't load.

Damiano31 avatar Jun 19 '19 10:06 Damiano31

As far as I'm aware, everything will need to be loaded outside of the container. Combine your CSS files into one and it'll work fine. In my opinion, this is only adding more http requests every time the user goes to another page, increasing the load time.

As for JS, it won't be re-evaluated when a transition completes, so it too will have to be compiled and loaded outside of the container. You'll have to reinitialize any functions using barba hooks.

On barba v1:

Barba.Dispatcher.on('newPageReady', function(currentStatus, oldStatus, container) {
  // JS functions here
});

on barba v2:

barba.hooks.afterEnter( ( data ) => {
  // JS functions here
} );

codymx avatar Jun 19 '19 13:06 codymx

I agree with @c0mrx,

Just one file for CSS and another one for JS = no more https requests when you switch between pages.

Anyway, this is a feature that will be implemented soon in the v2, called @barba/head, allowing Barba to automatically fetch head files that are not in the cache, mostly scripts and stylesheets.

:wink:

xavierfoucrier avatar Jun 20 '19 08:06 xavierfoucrier

Any update about the @barba/head addition?

I have a similar issue.

I have some 'detail' pages that get some inline styles injected. The styles get inject in the head and are specific for each 'detail' page. So it should reload the head on every 'detail' page.

Geestig avatar Oct 10 '19 09:10 Geestig

Hi @Geestig,

Still a feature to implement into the library, but no roadmap specified for the moment.

Thanks for using Barba and for your patience :wink:

xavierfoucrier avatar Oct 10 '19 09:10 xavierfoucrier

Do you happen to have a temporary solution/idea for my issue?

I was thinking on using the beforeEnter hook to check the incoming HTML for the style tag en inject it into the head of the page. And remove it afterwards with the afterLeave hook.

Geestig avatar Oct 10 '19 10:10 Geestig

Using the beforeEnter hook to inject styles using <link> into the <head> seems to be the appropriate solution :+1:

Be sure to properly remove the styles on the afterLeave hook and it will work just fine :+1:

For a complete example, see: https://github.com/barbajs/barba/issues/485#issuecomment-580158426

xavierfoucrier avatar Oct 10 '19 10:10 xavierfoucrier

I was thinking on using the beforeEnter hook to check the incoming HTML for the style tag en inject it into the head of the page. And remove it afterwards with the afterLeave hook.

@Geestig there's no need,technically or otherwise, to make things more complicated and parse out <style> or <link> elements to move them or their contents to the <head>. Generally speaking: CSS within style/link elements anywhere on the page is not scoped but follows the cascade and whatever @media rules within it apply even if added after the fact (page load). If you include CSS (snippets) to the incoming HTML to only format that additional content it'll be automatically enabled by the browser for the whole rendered page; remove the HTML and style elements/CSS and all is gone. Using ids to easy select these element will simplify your code.

Since you already fetch additional files from the server, using sth. like

<style>@import "page-foo.css"</style>
<style>.bar {color:fuchsia}</style>
... the remaining HTML for that page ...

or

<link rel="stylesheet" href="page-foo.css" media="all" >
... the remaining HTML for that page ...

None of this would bring down the page (nor server), yet @import just like <link> -- in this case -- will be cached and allows you to use and reuse external .css chunks on various "pages". If you prefer CSS code inline, you're also good to go, but loose caching. You're unlikely to experience FOUC with this approach.

Don't be too religious about minimizing HTTP requests :) Your server probably runs with http2 anyways.

Enjoy.

WebMechanic avatar Dec 11 '19 21:12 WebMechanic

@WebMechanic thanks for the reply, but it was a style that was added upon load automatically. I solved it by simply filtering it out of the head and adding it to the currect active head as @xavierfoucrier had suggested.

Geestig avatar Dec 12 '19 07:12 Geestig

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 23 '20 06:02 stale[bot]

Hi there, just wondering if @barba/head is still planned? Barba.js is amazing but fight with

and loading additional scripts & styles is a hughe hassle. Would be amazing to get that "official" solution.

ouun avatar Nov 24 '20 10:11 ouun

Hi @ouun,

It steel planned of course, but not in the next few months, sorry. For now, you should use a workaround to properly manage styles inside your head.

Thanks for your interest into Barba :wink:

xavierfoucrier avatar Nov 24 '20 11:11 xavierfoucrier

As far as I'm aware, everything will need to be loaded outside of the container. Combine your CSS files into one and it'll work fine. In my opinion, this is only adding more http requests every time the user goes to another page, increasing the load time.

As for JS, it won't be re-evaluated when a transition completes, so it too will have to be compiled and loaded outside of the container. You'll have to reinitialize any functions using barba hooks.

On barba v1:

Barba.Dispatcher.on('newPageReady', function(currentStatus, oldStatus, container) {
  // JS functions here
});

on barba v2:

barba.hooks.afterEnter( ( data ) => {
  // JS functions here
} );

So I'm a very new and young dev can someone explain me how should I implement it in my JS code.

outdatedx avatar Dec 14 '20 14:12 outdatedx

Hi @OutdatedDesigns,

Please use the Slack workspace in order to ask the whole community for support. Join using the invite link here: https://barba.js.org/docs/getstarted/useful-links/#Developer.

Thanks! :wink:

xavierfoucrier avatar Dec 14 '20 16:12 xavierfoucrier

This is also an issue for seo! Barba does not keep the head title and meta tags current with the page content.

mudlabs avatar Mar 07 '21 01:03 mudlabs

Hi @mudlabs,

This if off-topic here :wink:

And no, this is not a problem for SEO to not have head title and meta tags updated with the current page, see https://barba.js.org/faq/#What-about-SEO-concerns.

xavierfoucrier avatar Mar 07 '21 12:03 xavierfoucrier

A solution I came up with for my needs here:

I had a problem with web components (custom HTML elements) not initializing when their script tags were in the barba-container. Here's what worked:

barba.init({
    ...whatever settings you have,
    transitions:[{
       name: : "your-transition-name",
       
       beforeEnter(data) {
           const nextEl = data.next.container;
           if (nextEl) { //Just a little check to make sure we don't run this on an error
               // Find all scripts in the next container
               const nextScripts = nextEl.querySelectorAll('script');
    
               //Iterate over incoming script tags
               nextScripts.forEach(nextScript => {
                  const src = nextScript.src;
                  //Duplicate check - no need to re-execute scripts that are already loaded.
                  if (document.head.querySelector('script[src="' + src + '"]') == undefined) {

                    //Have to create a new script element in order for the browser to execute the code
                    const newScript = document.createElement('script');
                    newScript.src = src;
                    newScript.async = true; 
                    document.head.append(newScript);

                    nextScript.remove(); // Cleaning up the script in the container;
                  }
           }
       },
       (...whatever other transition functions you need, like after(), once(), etc.)



});

I'm pretty sure this solves the primary problem of the script not being executed, by creating a new script tag in the header for each script tag being loaded in the body. (It seems as if the body HTML is being loaded in such a way that re-executing scripts doesn't happen, which is normal for AJAX replacement).

Some thoughts:

  • This obviously doesn't help with inline scripts, but it could easily be modified to create new script tags with the content of inline scripts from the barba-container.
  • I don't see any reason to remove scripts which were injected in previous barba lifecycles, is there a good reason to do this?
  • I also didn't have any need to reload <link> elements in the head, they seem to execute just fine from the incoming barba container.
  • What else is needed for @barba/head? Meta Tags are probably the biggest other tag to iterate over, and then probably JSON metadata.

evankford avatar Jan 21 '22 18:01 evankford

Hi guys, I needed to load inline scripts on each Barba transition. Inspired by @evankford, I came up with the solution below. Also related to #485.

window.Barba.currentInlineScripts = []
window.Barba.init({
    transitions: [{
        sync: false,
        afterLeave({
            current,
            next
        }) {
            if (next.container) {
                // Remove old scripts appended to the head
                window.Barba.currentInlineScripts.forEach((currentInlineScript) => {
                    currentInlineScript.remove()
                })

                // Find all new scripts in the next container
                const nextScripts = next.container.querySelectorAll('script');

                // Iterate over new scripts
                nextScripts.forEach((script) => {
                    // Check if it is an inline script
                    if (!script.src) {
                        // Clone the original script
                        const newScript = script.cloneNode(true)
                        // Create a new <script> element node
                        const newNode = document.createElement('script');
                        // Assign it innerHTML content
                        newNode.innerHTML = newScript.innerHTML
                        // Append to the <head>
                        const element = document.head.appendChild(newNode)
                        // Save for later
                        window.Barba.currentInlineScripts.push(newNode)
                    }
                    // Remove the inline script
                    script.remove()
                })
            }
        }
    }]
})

I hope it helps. Any progress on the @barba/head plugin by the way?

stepanjakl avatar Mar 03 '22 19:03 stepanjakl

I hope it helps. Any progress on the @barba/head plugin by the way?

Bumping this request

carlaiau avatar Jun 01 '22 11:06 carlaiau

Yes, it's still planned, no need to bump again. I am reopening the issue in order for everyone to know.

Thanks again for your patience 😉

xavierfoucrier avatar Jun 01 '22 13:06 xavierfoucrier

Thanks @stepanjakl I'm also working to get link[rel=stylesheet] elements from head! It would be nice if it were included in @barba/head

dacmail avatar Jul 14 '22 09:07 dacmail

WIll we ever get the head we deserve?

sbme123 avatar Nov 09 '22 15:11 sbme123

Any further updates on this?

I think now with http2, there's not as much need to have everything bundled into a single file and progressively load scripts based on the page your on, including using CDNs.

Forgive me if I'm wrong, but hasn't this been planned for 2 years or more?

aaronstezycki avatar Nov 24 '22 09:11 aaronstezycki

@aaronstezycki As soon as we will find time to work on this, but since Barba v2 release, it is not a priority: this explained why we haven't worked on this since the beginning. Even with http2, it's still a good practice to bundle everything into a single file, especially when working with dynamic imports. And finally, it really depends on the app you are building.

Anyway, the issue is still opened and we know that in certain cases, the head plugin could be useful. Thanks for your patience! :wink:

:wave: Keep in mind that:

  • this project is open source / still maintained
  • not sponsored (as of today we have no sponsors)
  • contributors are working on it on their own free time (for free)

xavierfoucrier avatar Nov 29 '22 00:11 xavierfoucrier

Okay, that's a fair answer. :)

I would say though, the everything in this statement could be argued against. Http2 was created to allow for more freedom to separate files and suffers less from multi-file bottlenecks. Like you proceed to say, depends on the app though. Large libraries/scripts would preferably be only downloaded on the page they are being used on, i.e login scripts, large SPA's etc.

Anyway, thanks for reply, .ps I'd be up for donating page.

aaronstezycki avatar Nov 29 '22 16:11 aaronstezycki

Thanks @aaronstezycki :wink:

I am not an expert in http2, but as I said, it depends on the application, and today with code splitting / three shaking / dynamic imports, it's still possible to have a consistent+robust app with only one bundle. But, it also depends on what you want to do for your clients, because needs / possibilities can differ from a project to another.

Currently, there is no donating / collective page for the BarbaJS project, but you can support maintainers using Github Sponsors, what I highlighted in the beginning of 2022 here on Slack: https://barbajs.slack.com/files/TFDHZ8NN5/F030B08EB8U.

I will probably update the README to make this more clear in the future.

Thanks anyway for your support in open source projects! :v:

xavierfoucrier avatar Nov 29 '22 18:11 xavierfoucrier

I'm trying to integrate Barba in a Shopify theme. Even though I bundle css & js to a single file, Shopify also ads their own script tags to the head depending on the page type. (For example: On product page support for accelerated payment methods like Apple Pay, Marketing pixels for tracking, Cart functionality etc)

The head plugin would be a perfect use case for this. Would be great if this could be considered again. Thank you!

driespieters avatar Feb 14 '23 07:02 driespieters

+1

Messa1 avatar Mar 13 '23 12:03 Messa1

+1 :)

dsplz avatar Jul 16 '23 10:07 dsplz

+1

dviate avatar Jul 22 '23 20:07 dviate

+1

fifle avatar Aug 01 '23 07:08 fifle

+2 ? ... :trollface:

xavierfoucrier avatar Aug 01 '23 07:08 xavierfoucrier