Nuxt.js: Enable pre-processors of global scss variables

Created on 16 Jul 2017  Â·  36Comments  Â·  Source: nuxt/nuxt.js

I would like to apply this preprocessor feature to be able to load SCSS variables globally but not know how to configure this in nuxt.

How can I do it?

https://vue-loader.vuejs.org/en/configurations/pre-processors.html#loading-a-global-settings-file

{
  loader: 'sass-resources-loader',
  options: {
    resources: path.resolve(__dirname, '../src/style/_variables.scss')
  }
}

My nuxt.config.js

module.exports = {
  head: {
    title: 'starter',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto+Mono' }
    ]
  },
  loading: { color: '#3B8070' },
  build: {
    extend (config, ctx) {
      if (ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  }
}

This question is available on Nuxt.js community (#c955)
help-wanted

Most helpful comment

I'm using the nuxt-sass-resources-loader module and it works fine. :grinning:

All 36 comments

I'm running into this issue as well.
I'm using and alias to import all my required sass files (vars, mixins..) in every component
@import ~imports

I wish there was a simplified way to import variables file automatically in all components :)

My solution temporary is load in every vue file a file config of my colors of sass

@import '~assets/vars.scss'

just extend vue-loader

extend (config) {
      const vueLoader = config.module.rules.find((loader) => loader.test.toString() === '/\\.vue$/')
      vueLoader.query.loaders.scss =
        [
          'vue-style-loader',
          'css-loader',
          // 'postcss-loader',
          'sass-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              resources: resolve(__dirname, './assets/sass/base.scss')
            }
          }
        ]
    }

Hi @davidcostadev @farissi @inssitu

It is possible with Nuxt.js of course, but needs a little bit more of work.

Here are the example: https://glitch.com/edit/#!/sass-resources-loader-nuxt
Live demo: https://sass-resources-loader-nuxt.glitch.me/

nuxt.config.js:

const resolve = require('path').resolve

const isVueRule = (rule) => {
  return rule.test.toString() === '/\\.vue$/'
}
const isSASSRule = (rule) => {
  return ['/\\.sass$/', '/\\.scss$/'].indexOf(rule.test.toString()) !== -1
}
const sassResourcesLoader = {
  loader: 'sass-resources-loader',
  options: {
    resources: [
      resolve(__dirname, 'sass/variables.sass')
    ]
  }
}

module.exports = {
  css: ['~/sass/main.scss'],
  build: {
    extend (config) {
      config.module.rules.forEach((rule) => {
        if (isVueRule(rule)) {
          rule.query.loaders.sass.push(sassResourcesLoader)
          rule.query.loaders.scss.push(sassResourcesLoader)
        }
        if (isSASSRule(rule)) {
          rule.use.push(sassResourcesLoader)
        }
      })
    }
  }
}

As you can see, I also added the rule inside the global sass/scss loaders so you don't need to includes your variables/mixins inside your sass files as well :)

This code is very useful, i think that could be implement in the documentations, @Atinux

We might do something better since it's a good feature.

We may add directly into nuxt.config.js a sassResources key :)

@Atinux That soloution above did not work for me on 1.0.0-rc4.

Is there any news on this feature? Seems so basic yet so hard to deal with.

I make some change with @Atinux solution and without sass-resources-loader dependency, but a little more complicated.

const isVueRule = (rule) => {
  return rule.test.toString() === '/\\.vue$/'
}
const isSASSRule = (rule) => {
  return ['/\\.scss$/'].indexOf(rule.test.toString()) !== -1
}
const scssLoaderConfig = {
  loader: 'sass-loader',
  options: {
    includePaths: [__dirname],
    data: '@import "assets/css/base.scss";'
  }
}

module.exports = {
  css: ['~/sass/main.scss'],
  build: {
    extend (config) {
      config.module.rules.forEach((rule) => {
        if (isVueRule(rule)) {
          rule.query.loaders.scss.pop()
          rule.query.loaders.scss.push(sassResourcesLoader)
        }
        if (isSASSRule(rule)) {
          rule.use.pop()
          rule.use.push(sassResourcesLoader)
        }
      })
    }
  }
}

test on 1.0.0-rc4 @dzift .

using 1.0.0-rc5 @funkyLover

➜  biohealth git:(master) ✗ npm run dev

> [email protected] dev /home/zaken/projects/biohealth
> nuxt

  nuxt:build App root: /home/zaken/projects/biohealth +0ms
  nuxt:build Generating /home/zaken/projects/biohealth/.nuxt files... +1ms
  nuxt:build Generating files... +12ms
  nuxt:build Generating routes... +8ms
  nuxt:build Building files... +36ms
  TypeError: Cannot read property 'loaders' of undefined

  - nuxt.config.js:79 config.module.rules.forEach
    /home/zaken/projects/biohealth/nuxt.config.js:79:21

  - nuxt.config.js:77 Builder.extend
    /home/zaken/projects/biohealth/nuxt.config.js:77:27

  - client.config.js:202 Builder.webpackClientConfig
    [biohealth]/[nuxt]/lib/builder/webpack/client.config.js:202:31

  - builder.js:339 Builder._callee5$
    [biohealth]/[nuxt]/lib/builder/builder.js:339:46

  - builder.js:146 Builder._callee$
    [biohealth]/[nuxt]/lib/builder/builder.js:146:16

@funkyLover I get the same error as @dzift in 1.0.0-rc6

@aulneau @dzift

if (rule.test.toString() === '/\\.vue$/') {
  rule.options.loaders.scss.pop()
  rule.options.loaders.scss.push(scssLoaderConfig)
}

the webapck default config got changed in 1.0.0-rc6. next time get error when extend the webpack config in nuxt, can just print the config in console the check the structure.

// nuxt.config.js
module.exports = {
  // ....
  bulid: {
    // ....
    extend (config, ctx) {
      console.log(config)
    }
  }
}

So for me the issue was fixed when I changed rule.query.loaders to rule.options.loaders.

Best
t

For anyone curious, I got it working with:

config.module.rules.forEach((rule) => {
  if (rule.test.toString() === '/\\.vue$/') {
    rule.query.loaders.scss.pop()
    rule.query.loaders.scss.push('sass-loader?sourceMap&data=@import "./assets/constants";')

    rule.query.loaders.sass.pop()
    rule.query.loaders.sass.push('sass-loader?indentedSyntax&sourceMap&data=@import "./assets/constants";')
  }
})

EDIT: Nevermind. I used an old version of nuxt apparently…

Can anyone tell me if this is now part of nuxt? Or is it still hacky?

Tried again, got it working with [email protected] like so:

// nuxt.config.js
module.exports = {
  // ....
  build: {
    // ....
    extend(config, ctx) {
      config.module.rules.forEach((rule) => {
        if (rule.test.toString() === '/\\.vue$/') {
          rule.options.loaders.scss[2].options.data = '@import "./assets/constants";'
        }
      })
    }
  }
}

@bovas85 I would not necessarily call this hacky, basically you're just altering the webpack config to your needs. Doesn't really make a difference if you do it in your webpack.config.js or changing it at some other place…

@thomasaull sure it's not but I think it should come bundled with nuxt templates.
I'll try the above,thanks

Also would you mind going over what you changed and where I should change the code above?
I assume assets/constants is part of your stack but not general?

Hey @bovas85! Sure, basically you just need to change your nuxt.config.js. My constants.scss with all my variables is located in /assets (you need to adjust this path according to your structure). You don't need to add a file extension (although it probably would work with too). My complete nuxt.config.js looks like this:

module.exports = {
  /*
  ** Headers of the page
  */
  head: {
    title: 'starter',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  css: [
  ],
  /*
  ** Customize the progress-bar color
  */
  loading: { color: '#3B8070' },
  /*
  ** Build configuration
  */
  build: {
    /*
    ** Run ESLINT on save
    */
    extend (config, ctx) {
      if (ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })

        config.module.rules.forEach((rule) => {
          if (rule.test.toString() === '/\\.vue$/') {
            rule.options.loaders.scss[2].options.data = '@import "./assets/constants";'
          }
        })
      }
    }
  },
  render: {
    bundleRenderer: {
      shouldPreload: (file, type) => {
        return ['script', 'style', 'font'].includes(type)
      }
    }
  }
}

Let me know if you have any more questions!

Thanks a lot,I managed to load it that way and it works. What's the bundle renderer doing?

I actually have no idea right now 😄

good news?

Ok, apparently I'm getting a NuxtServerError for every Variable/Mixin I'm trying to use. After doing a reload the next Variable/Mixin throws an error. So everytime the app restarts, I have to reload once for every Variable/Mixin I'm using. This is true for both, using @data option and using vue-ressource-loader. Seems to be an issue with nuxt itself… Do you have this aswell @bovas85?

I'm using a mixing 'store' and it works fine. Can you paste your mixin?

I tried the solution proposed by @thomasaull, but receive warning:

[Vue warn]: Error in beforeCreate hook: "Error: Module build failed: 
  max-width: $max-uni-width;
            ^
      Undefined variable: "$max-uni-width".
      in /Sandbox/nuxt/components/about/Employees.vue (line 24, column 14)"

found in

---> <Employees> at components/about/Employees.vue
       <Pages/en/about.vue> at pages/en/about.vue
         <Nuxt> at .nuxt/components/nuxt.vue
           <Default> at layouts/default.vue
             <Root>

I went back to include my constants.css in every Component :-/

Have the same problems as you @thomasaull, getting the NuxtServerError as well.

Post your nuxt config please

nuxt 1.0.0-rc11

module.exports = {
  /*
  ** Headers of the page
  */
  head: {
    title: 'nuxt-project',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  /*
  ** Customize the progress bar color
  */
  loading: { color: '#3B8070' },
  /*
  ** Build configuration
  */
  modules: [
    '@nuxtjs/axios',
  ],
  axios: {
  },
  env: {
    baseUrl: process.env.BASE_URL || 'http://localhost:3000'
  },
  plugins: [
    { src: '~/plugins/vue-scrollto.js', ssr: false}
  ],
  build: {
    vendor: [
      'vue-scrollto',
      'scrollmagic',
      'scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap',
      'scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators'
    ],
    /*
    ** Run ESLint on save
    */
    extend (config, ctx) {
      if (ctx.dev && ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })

        config.module.rules.forEach((rule) => {
          if (rule.test.toString() === '/\\.vue$/') {
            rule.options.loaders.scss[2].options.data = '@import "./assets/scss/base_constants.scss";'
          }
        })

        config.module.rules.push({
          test: require.resolve('scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators'),
          loader: 'imports-loader?define=>false'
        })

        config.module.rules.push({
          test: require.resolve('scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap'),
          loader: 'imports-loader?define=>false'
        })

      }
    }
  }
}

Is there a stylus version of this configuration? I've been looking up online but to no avail. thanks!

I'm using the nuxt-sass-resources-loader module and it works fine. :grinning:

@anteriovieira for stylus too?

@anteriovieira, i tried your plugin, but was not able to get it up and running.. npm run dev just started complaining about variables and mixins that do not exist, even though i have defined them..

@didiself, i used your code sample, and it runs perfectly in development mode, when i do a npm run build it fails..

        const vueLoader = config.module.rules.find((loader) => loader.test.toString() === '/\\.vue$/')
        vueLoader.query.loaders.scss = [
          'vue-style-loader',
          'css-loader',
          'sass-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              resources: resolve(__dirname, './assets/scss/base_constants.scss')
            }
          }
        ]

# complementary:

global stylus variables

I'm using the nuxt-stylus-resources-loader module and it works fine

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

surmon-china picture surmon-china  Â·  3Comments

pehbehbeh picture pehbehbeh  Â·  3Comments

mattdharmon picture mattdharmon  Â·  3Comments

gary149 picture gary149  Â·  3Comments

vadimsg picture vadimsg  Â·  3Comments