Nuxt.js: CSS from multiple layouts is being included on individual pages

Created on 11 Sep 2018  ·  63Comments  ·  Source: nuxt/nuxt.js

Version

v1.4.2 - v2.4.2 (see below).

Reproduction link

https://github.com/markplewis/nuxt-layout-css-issue

Steps to reproduce

  1. Clone the following example repo.
  2. Run npm install then npm run dev.
  3. Navigate between the pages and inspect the CSS that's applied to the <body> element via your browser's dev tools.

https://github.com/markplewis/nuxt-layout-css-issue

What is expected ?

When a page specifies a layout, like this:

pages/index.vue:

<script>
  export default {
    layout: "home"
  }
</script>

Only the CSS from the corresponding layout file should be included in the page:

layouts/home.vue:

<style>
  body {
    background-color: steelblue;
  }
</style>

What is actually happening?

The CSS from every layout file is being included on every page, regardless of which layout is specified in the page's .vue file.

screenshot

Additional comments?

My example repo is using Nuxt Edge.

This bug report is available on Nuxt community (#c7723)
bug-report pending

Most helpful comment

We are currently working on a solution that could work without any changes, for both critical CSS and extractCSS modes. Stay tuned :)

All 63 comments

Can confirm this bug (production).

"Workaround" which only hides the problem and works for just 1st render ☹️ :

 build: {
    splitChunks: {
      layouts: true
    }
}

This is also a problem in Nuxt v1 (see the v1 branch of my demo repo). Styles from multiple layouts are being pulled into the page, but at least I'm not seeing styles from the default layout anymore:

screen shot 2018-09-12 at 7 55 33 am

On initial page load, the CSS is correct. It's only after I navigate to "page 2" then back again that the CSS from the other layout ends up on the page.

It appears that vue-loader, the actually dependency vue-style-loader, is parsing the scss in each component (regardless of what component is being mounted) and is inlining them into the html document. I am currently running into this problem with themes in different layouts

https://github.com/nuxt/nuxt.js/issues/3852

My solution was to include a css file in the layout and have a hook to prevent themes from leaking into one another. I had to pull in a gulp file and have a separate build to compile my scss.

Layout A:

export default {
  name: 'LayoutA',
  head() {
    return {
      link: [
        { rel: 'stylesheet', href: '/css/LayoutA/app.min.css' }
      ],
      bodyAttrs: {
        class: 'LayoutA'
      }
    }
  }
}
</script>

Layout B:

export default {
  name: 'LayoutB',
  head() {
    return {
      link: [
        { rel: 'stylesheet', href: '/css/LayoutB/app.min.css' }
      ],
      bodyAttrs: {
        class: 'LayoutB'
      }
    }
  }
}
</script>

I have same issue.

@hareku I was able to solve my issue using

 build: {
    splitChunks: {
      layouts: true
    }
}

@Legym
Thanks!!!

I upgraded my demo project to Nuxt 2.1.0 and I'm still experiencing this problem. As @manniL stated above, adding splitChunks: { layouts: true } solves the problem for first render (i.e. loading the page directly or hard refreshing your browser), but the problem persists when navigating back and forth between pages after that.

@markplewis I had a different folder setup than you. We created a theme system inside our nuxt build and each theme was locked into their own URL. We didn't go from one theme to another directly and so we didn't run into your issue.

screen shot 2018-10-02 at 7 50 31 pm

splitChunks: { layouts: true } did solve our issue because originally our styles in Layout would bleed into other themes. I.e Styles from Desktop were leaking into Mobile.

However I would say the issue you are having is definitely a bug. The only suggestion I have is to do something like this or include it's own css file until it's fixed.

Layout 1

<template>
  <div>
    <nuxt/>
  </div>
</template>

<script>
export default {
  head() {
    return {
      bodyAttrs: {
        class: 'layout1'
      }
    }
  }
}

</script>

<style>
  .layout1 {
    background-color: steelblue;
  }
</style>

Layout 2

<template>
  <div>
    <nuxt/>
  </div>
</template>

<script>
export default {
  head() {
    return {
      bodyAttrs: {
        class: 'layout2'
      }
    }
  }
}

</script>

<style>
  .layout2 {
    background-color: steelblue;
  }
</style>

Vue-style-loader will take any css in the