Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSS from multiple layouts is being included on individual pages #3877

Open
markplewis opened this issue Sep 11, 2018 — with CMTY · 41 comments
Open

CSS from multiple layouts is being included on individual pages #3877

markplewis opened this issue Sep 11, 2018 — with CMTY · 41 comments

Comments

Copy link

@markplewis markplewis commented Sep 11, 2018 — with CMTY

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)
@cmty cmty bot added the cmty:bug-report label Sep 11, 2018
@markplewis markplewis changed the title CSS from other layouts is being included on pages that specify a layout [Edge] CSS from other layouts is being included on pages that specify a layout Sep 11, 2018
@markplewis markplewis changed the title [Edge] CSS from other layouts is being included on pages that specify a layout [Edge] CSS from multiple layouts is being included on pages Sep 11, 2018
@markplewis markplewis changed the title [Edge] CSS from multiple layouts is being included on pages [Edge] CSS from multiple layouts is being included on individual pages Sep 11, 2018
@manniL

This comment has been minimized.

Copy link
Member

@manniL manniL commented Sep 11, 2018

Can confirm this bug (production).

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

 build: {
    splitChunks: {
      layouts: true
    }
}
@markplewis

This comment has been minimized.

Copy link
Author

@markplewis markplewis commented Sep 12, 2018

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.

@Legym

This comment has been minimized.

Copy link

@Legym Legym commented Sep 14, 2018

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

#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>
@hareku

This comment was marked as off-topic.

Copy link

@hareku hareku commented Sep 27, 2018

I have same issue.

@Legym

This comment has been minimized.

Copy link

@Legym Legym commented Sep 27, 2018

@hareku I was able to solve my issue using

 build: {
    splitChunks: {
      layouts: true
    }
}
@hareku

This comment was marked as off-topic.

Copy link

@hareku hareku commented Oct 1, 2018

@Legym
Thanks!!!

@markplewis

This comment has been minimized.

Copy link
Author

@markplewis markplewis commented Oct 2, 2018

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.

@Legym

This comment has been minimized.

Copy link

@Legym Legym commented Oct 3, 2018

@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 <style> tags and inline them to the document. Apparently vue-style-loader doesn't remove inline styles when you switch back so the last inline css always takes effect. You'll need to bind to a node that changes when switching layouts.

@sumeshkmp

This comment has been minimized.

Copy link

@sumeshkmp sumeshkmp commented Oct 12, 2018

This issue is reproducible in Nuxt 2.2.0 when loading the layout dynamically.

build: {
splitChunks: {
layouts: true
}
}

Did not worked.

screen shot 2018-10-15 at 11 57 52 am

@fbrbovic

This comment was marked as off-topic.

Copy link

@fbrbovic fbrbovic commented Oct 25, 2018

Still experiencing this problem too, any solutions? , layouts true doesn't fix it.

@Atinux

This comment has been minimized.

Copy link
Member

@Atinux Atinux commented Nov 9, 2018

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

@fbrbovic

This comment has been minimized.

Copy link

@fbrbovic fbrbovic commented Nov 9, 2018

Thanks, my temporary solution was to import scss or styl file inside <script> tag which doesn't seem to leak css

This comment was marked as off-topic.

Copy link

@hareku hareku commented Nov 16, 2018 — with CMTY

I want to use splitChunks with extractCSS option.

@rikoz

This comment was marked as off-topic.

Copy link

@rikoz rikoz commented Nov 17, 2018

Any solution yet, I'm experiencing same here. Please I'm seeing a lot of temporaty fix but no detailed explanation of them. I need your help

Thanks

@jaredreich

This comment was marked as off-topic.

Copy link

@jaredreich jaredreich commented Dec 17, 2018

Issues that are labeled as 🕐Pending will not be automatically marked as stale.

Oops Stale Bot - you had one job! 😂

Really excited for the Nuxt team to fix this one. Go team go! 😄
(please don't stale/expire this issue...)

@stale stale bot removed the stale label Dec 17, 2018
@menthol

This comment has been minimized.

Copy link
Contributor

@menthol menthol commented Dec 22, 2018

I find a way to make it work on production, (no way yet for development).

in nuxt.config.js

import crypto from 'crypto';

const BUILDID = crypto.randomBytes(10).toString('hex');

module.exports = {
   // ...
  build: {
    extractCSS: true,
    // ...
    filenames: {
      css: `${BUILDID}.[name].css`,
    },
    // ...
  },
  env: {
    BUILDID,
  },
};

in layouts/*.vue

<template>
  <nuxt />
</template>
<script>
  // Fake import, make extract css create a new file with specific chunkName
  export function css() { import(/* webpackChunkName: 'theme-default' */ '~/assets/style.css'); }

  export default {
    head() {
      return {
        link: [
          // integrate compiled file into current layout
          { type: 'text/css', rel: 'stylesheet', href: `/_nuxt/${process.env.BUILDID}.theme-default.css` },
        ],
      };
    },
  };
</script>

As the dev server use in-memory compilation, i wasn't able to find the correct path for integrate compiled css file into current page in development. If you want to try, make sure you freeze the extractCSS property, ex: ...Object.defineProperty({}, 'extractCSS', { value: true }),;

@menthol

This comment has been minimized.

Copy link
Contributor

@menthol menthol commented Dec 22, 2018

So, after some investigation, I succeeded make it work in dev :

in nuxt.config.js

import crypto from 'crypto';

const BUILDID = crypto.randomBytes(10).toString('hex');

module.exports = {
  // ...
  modules: [
    // ...
    '~/modules/ForceExtractCSS',
  ],
  // ...
  build: {
    extractCSS: true,
    // ...
    filenames: {
      css: `${BUILDID}.[name].css`,
    },
    // ...
  },
  env: {
    BUILDID,
  },
};

in modules/ForceExtractCSS.js

export default function ForceExtractCSSModule() {
  this.nuxt.hook('ready', () => {
    this.options.build.extractCSS = true;
  });
}

and in layouts/*.vue

<template>
  <nuxt />
</template>
<script>
  // Fake import, make extract css create a new file with specific chunkName
  export function css() { import(/* webpackChunkName: 'theme-default' */ '~/assets/style.css'); }

  export default {
    head() {
      return {
        link: [
          // integrate compiled file into current layout
          { type: 'text/css', rel: 'stylesheet', href: `/_nuxt/${process.env.BUILDID}.theme-default.css` },
        ],
      };
    },
  };
</script>

Canvas : HMR isn't working, head() isn't recalculated after HRM call

@manniL manniL changed the title [Edge] CSS from multiple layouts is being included on individual pages CSS from multiple layouts is being included on individual pages Jan 29, 2019
@fbrbovic

This comment has been minimized.

Copy link

@fbrbovic fbrbovic commented Jan 30, 2019

This is still broken in 2.4.0

@b02505048

This comment was marked as off-topic.

Copy link

@b02505048 b02505048 commented Jan 31, 2019

Yeah, still a problem in 2.4.0

@nuxt nuxt deleted a comment from stale bot Jan 31, 2019
@markplewis

This comment has been minimized.

Copy link
Author

@markplewis markplewis commented Feb 17, 2019

FYI: I just updated my demo project to Nuxt 2.4.3.

@nick-lawrence

This comment has been minimized.

Copy link

@nick-lawrence nick-lawrence commented Feb 27, 2019

@markplewis Are you still experiencing this issue in the latest version?

I am currently in the middle of build using Nuxt 2.4.0 and undesired multiple Layout/CSS cross-compilation is still an issue.

@markplewis

This comment has been minimized.

Copy link
Author

@markplewis markplewis commented Mar 21, 2019

@nick-lawrence I just upgraded my demo project to Nuxt 2.5 and I'm still experiencing this issue.

@ryanwinchester

This comment has been minimized.

Copy link

@ryanwinchester ryanwinchester commented Mar 29, 2019

So, I wanted my login page to have a coloured background and the default layouts to have a white background.

This silly workaround does the trick for me.

  // login.vue
  beforeCreate() {
    document
      .getElementsByTagName('html')[0]
      .setAttribute('style', 'background-color: #4fc08d')
  }
  // default.vue
  beforeCreate() {
    document.getElementsByTagName('html')[0].removeAttribute('style')
  }
@TomFrajer

This comment has been minimized.

Copy link

@TomFrajer TomFrajer commented Apr 1, 2019

Default.vue layout should have <style scoped> in it AND all other custom layouts should NOT HAVE scoped styles... this fixed it for me.

@er1x

This comment has been minimized.

Copy link

@er1x er1x commented Apr 4, 2019

+1 (Nuxt v 2.4.0)

In my case not only the layout "leaks" CSS, "pages/index.vue" too.
I'm adding an extra layout and extra pages (using this layout) through a Nuxt module, as a some sort of sub-application:

this.addLayout(path.resolve(__dirname, 'custom/layout.vue'), 'custom')
this.extendRoutes((routes, resolve) => {
  routes.push({
    path: '/subapp',
    name: 'subapp',
    component: resolve(__dirname, 'custom/subapp.vue')
  })
})
@padinko

This comment has been minimized.

Copy link

@padinko padinko commented Apr 5, 2019

my workaround for now is

nuxt.config.js

build: {
    splitChunks: {
      layouts: true
    }
}

and then reload page beafore each layout change, mixin in all layouts:

    beforeCreate() {
        if (!process.server) {
            if (window.__NUXT_LAYOUT__ && window.__NUXT_LAYOUT__ !== this) {
                window.location.reload();
            }
            window.__NUXT_LAYOUT__ = this;
        }
    },
@christopherblack

This comment has been minimized.

Copy link

@christopherblack christopherblack commented Oct 3, 2019

Hello!
Is there any solution yet? Still experiencing the issue in Nuxt 2.9.2

@donni106

This comment has been minimized.

Copy link

@donni106 donni106 commented Oct 14, 2019

We have the same problem. It seems to work for us with scoping every layout <style>s. Can there be a problem with <style scoped> per layout?

@fachreza73

This comment has been minimized.

Copy link

@fachreza73 fachreza73 commented Oct 25, 2019

+1

Nuxt 2.10.1

@UtopiaBe

This comment has been minimized.

Copy link

@UtopiaBe UtopiaBe commented Oct 30, 2019

I am having 2 languages, with RTL and LTR...
So i wanted to build 2 layouts to load RTL.CSS or LTR.CSS
And it uploads both of them :( so the website brokes...

Waiting for a solution.

@matrunchyk

This comment has been minimized.

Copy link

@matrunchyk matrunchyk commented Nov 4, 2019

Without this feature layouts are unusable for our projects.... Can we help you guys somehow?

@SHxKM

This comment has been minimized.

Copy link

@SHxKM SHxKM commented Nov 28, 2019

Any progress on this? I was sure I was doing something wrong. It's pretty much useless to use more than one layout if CSS is getting merged. scopeing default didn't help in my case.

@paulvonber

This comment has been minimized.

Copy link

@paulvonber paulvonber commented Dec 3, 2019

Without this feature layouts are unusable for our projects.... Can we help you guys somehow?

exactly same here, we stuck totally with this, I already blaming myself for switching to nuxt.
Overall layout styles should be scoped for everything what is included in that particular layout, otherwise they are just unusable.

@necony286

This comment has been minimized.

Copy link

@necony286 necony286 commented Dec 9, 2019

is this going to be fixed anytime soon please?

@matrunchyk

This comment has been minimized.

Copy link

@matrunchyk matrunchyk commented Dec 9, 2019

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

Dear @Atinux, @alexchopin, @manniL, would you mind to give some feedback on this ticket. I'm sorry I'm and others bothering you here, but as you could probably see, this is a very important feature for us. For someone like me, it's a show-stopper.

Please note, that I'm just asking about some feedback, not the implementation itself. For a project with 24k stars a year w/o a feedback doesn't make it trustworthy.

Have you started working on it? Could you please share some details of the implementation so we could potentially join? Or if you haven't, we would know that we can start our own research and potentially propose some PR?

Again, thank you guys for all you work you're doing here! This is very worthy and today it is the best SSR framework for Vue. Sorry for my impatience and curiosity.

@MLDMoritz

This comment has been minimized.

Copy link

@MLDMoritz MLDMoritz commented Dec 15, 2019

I would love to help too, if there's anything people can do please tell us.

@gambolputty

This comment has been minimized.

Copy link

@gambolputty gambolputty commented Jan 4, 2020

This is still broken in 2.11.0

@julpat

This comment has been minimized.

Copy link

@julpat julpat commented Jan 5, 2020

I think this is related with Issue with template styles not unmounting on programmatic navigation #2561 and the problem is in vue-loader when does not remove unused css in different layout/page (when you have build.splitChunks.layouts === true ).

@gambolputty

This comment has been minimized.

Copy link

@gambolputty gambolputty commented Jan 5, 2020

Another workaround could be to assign a class to the <body>-element (or another ancestor) and make sure, that all layout-related styles are part of that class-scope, e. g.

body.layout1 .menu {  }

If this is not fixable, could somebody mention this limitation in the docs (inheritance of css styles between layouts)?

@Atinux

This comment has been minimized.

Copy link
Member

@Atinux Atinux commented Jan 6, 2020

Hi there,

Sorry for the late answer and happy new year at the same time!

Actually one possibility is to use @gambolputty suggestion with bodyAttrs:

<script>
// layouts/dark.vue
export default {
  head: {
    bodyAttrs: {
      class: "dark-theme"
    }
  }
};
</script>

And to prefix your style with .dark-theme .my-class { ... }.

Please find a live example here: https://codesandbox.io/s/nuxt-layouts-theming-ru954

We will beta test Vue 3 to test better layout scoping, will keep this thread updated.

@manniL manniL mentioned this issue Jan 6, 2020
3 of 7 tasks complete
@aloiki

This comment has been minimized.

Copy link

@aloiki aloiki commented Jan 9, 2020

I am using nuxt v.2.10 for a project and unfortunately it does not work with style files included in different layouts.

Layout A:

<template />

<style lang="scss">
  @import '@/assets/scss/layout-a.scss';
</style>

Layout B:

<template />

<style lang="scss">
  @import '@/assets/scss/layout-b.scss';
</style>

I tried it with the options in nuxt.config splitChunks.layout and extractCss but both configurations do not work. If the user switches the layout from Layout A to Layout B
the style of the former layout is loaded. Our workaround at the moment is a hard page reload.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.