Nuxt.js: Global Sass mixins and functions

Created on 15 Mar 2017  路  9Comments  路  Source: nuxt/nuxt.js

It seems that only compiled CSS is available globally.

For example, something like this included globally would work:

// assets/scss/main

@mixin createGrid() { ... }

.container {
  @include createGrid()
}

But this wouldn't work:

// assets/scss/main

@mixin createGrid() { ... }

// components/someComponent

.container {
  @include createGrid()
}

Would it be possible to inject sass mixins and functions globally? Or is there a reason they need to be imported individually for each file/component?

If the latter, another alternative would be to have sass @import statements resolve node_modules so that components that use them don't all have to do @import 'node_modules/somePlugin/dist/someFile'.

This question is available on Nuxt.js community (#c333)

Most helpful comment

Here is my solution that loops through all loaders and allows for more fine-grained filtering based on loader type. For example, to add includePaths to sass / scss, as well as stylus:

const path = require('path')
const util = require('util')

module.exports = {
  build: {
    extend(config, ctx) {
      const vueLoader = config.module.rules.find(
        rule => rule.loader === 'vue-loader')
      const { options: {loaders} } = vueLoader || { options: {} }
      if (loaders) {
        for (const loader of Object.values(loaders)) {
          changeLoaderOptions(Array.isArray(loader) ? loader : [loader])
        }
      }
      config.module.rules.forEach(rule => changeLoaderOptions(rule.use))
      // console.log(util.inspect(config.module.rules, { depth: 6 }))
    }
  }
}

function changeLoaderOptions(loaders) {
  if (loaders) {
    for (const loader of loaders) {
      let options
      switch (loader.loader) {
      case 'sass-loader':
        options = {
          includePaths: ['./styles'],
          data: '@import "_imports";'
        }
        break
      case 'stylus-loader':
        options = {
          paths: [path.resolve('./styles')],
          import: ['_imports']
        }
        break
      }
      if (options) {
        Object.assign(loader.options, options)
      }
    }
  }
}

All 9 comments

I use stylus ( yarn add stylus and stylus-loader )

I also import in every vue file

for my example

assets/css/variables.styl

production = true

components/Footer.vue

<template lang="pug">
div
  h1
<template>
<style lang="stylus" scoped>
@import = '~assets/css/variables.styl'
if production
  h1
    background red
// background red only production ( manually modify on variables.styl ) ...
</style>

as another sample ( with scss )

I have use bootstrap 4 , but I only need reboot grid visibility

yarn add node-sass sass-loader --dev

assets/css/bs4.scss

/**
 * Bootstrap build only reboot grid visibility
 */

@at-root {
  @-ms-viewport { width: device-width; }
}

html {
  box-sizing: border-box;
  -ms-overflow-style: scrollbar;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

@import "../../node_modules/bootstrap/scss/variables";
@import "../../node_modules/bootstrap/scss/mixins";

@import "../../node_modules/bootstrap/scss/normalize";
@import "../../node_modules/bootstrap/scss/reboot";

@import "../../node_modules/bootstrap/scss/grid";

@import "../../node_modules/bootstrap/scss/utilities/visibility";

nuxt.config.js

css: [
    { src: '~assets/css/bs4.scss', lang: 'scss' },
  ]

Are you using the CSS in Vue component files?

I tried following your example, I have a global CSS file configured in nuxt.config.js, and I imported the sass plugins in that file, but any non-css still does not work.

For example:

// ~assets/global.scss
.background
  background-color: blue

@mixin background() {
  background-color: blue 
}

// nuxt.config.scss
css: [
    { src: '~assets/scss/global.scss', lang: 'scss' },
  ]

I verified that normal selector styles work; if I use .background then the background will be blue.

However, I get errors for any variables, mixins, and functions that I try to use; if try to @include background() it will not work until I do @import '~assets/scss/global.scss in the respective Vue component file.

@alidcastano I wirte stylus

I think my English not good enough 馃懚
I just want say I also need import var.styl file in my each vue file .
I think that don't have global import for sass/scss/stylus

I had looking for global import for stylus
https://github.com/vuejs/vue-loader/issues/328
but it look like need @import 'file' for vue file you need .

Hi @alidcastano

We depend on vue-loader for this, and indeed, you need to import your mixins/variables everytime you need to use them, it's better for clarity and also does not make your bundle bigger since it's only helpers. See https://github.com/vuejs/vue-loader/issues/328#issuecomment-269915030

if you use node modules, you can use directly:

@import "bootstrap/scss/variables"

BTW, thank you @ausir0726 for helping us to find the answer 馃憤

See here for a more up-to-date answer, working with at least alpha4: https://github.com/nuxt/nuxt.js/issues/1092#issuecomment-316365016

@alidcastano There's a fitting solution to this exact problem. It's been something that I have been looking for a while. Let me share the solution with you-
https://stackoverflow.com/a/46015906/5013932

Here is my solution that loops through all loaders and allows for more fine-grained filtering based on loader type. For example, to add includePaths to sass / scss, as well as stylus:

const path = require('path')
const util = require('util')

module.exports = {
  build: {
    extend(config, ctx) {
      const vueLoader = config.module.rules.find(
        rule => rule.loader === 'vue-loader')
      const { options: {loaders} } = vueLoader || { options: {} }
      if (loaders) {
        for (const loader of Object.values(loaders)) {
          changeLoaderOptions(Array.isArray(loader) ? loader : [loader])
        }
      }
      config.module.rules.forEach(rule => changeLoaderOptions(rule.use))
      // console.log(util.inspect(config.module.rules, { depth: 6 }))
    }
  }
}

function changeLoaderOptions(loaders) {
  if (loaders) {
    for (const loader of loaders) {
      let options
      switch (loader.loader) {
      case 'sass-loader':
        options = {
          includePaths: ['./styles'],
          data: '@import "_imports";'
        }
        break
      case 'stylus-loader':
        options = {
          paths: [path.resolve('./styles')],
          import: ['_imports']
        }
        break
      }
      if (options) {
        Object.assign(loader.options, options)
      }
    }
  }
}

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maicong picture maicong  路  3Comments

nassimbenkirane picture nassimbenkirane  路  3Comments

shyamchandranmec picture shyamchandranmec  路  3Comments

VincentLoy picture VincentLoy  路  3Comments

mattdharmon picture mattdharmon  路  3Comments