laravel-mix: Vuetify 2 sass compile error

  • Laravel Mix Version: 4.1.2
  • Node Version: 10.16
  • NPM Version: 6.9.0
  • OS: Windows 10

Description:

When i try to compile vuetify 2 i get this error:

ERROR in ./node_modules/vuetify/src/styles/main.sass (./node_modules/css-loader!./node_modules/postcss-loader/src??ref--7-2!./node_modules/sass-loader/lib/loader.js??ref--7-3!./node_modules/vue-style-loader!./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js??ref--10-2!./node_modules/vuetify/src/styles/main.sass)
Module build failed (from ./node_modules/sass-loader/lib/loader.js):

undefined
                                                                                                                ^
      Expected newline.
  ╷
4 │ var content = require("!!../../../css-loader/index.js!../../../sass-loader/lib/loader.js??ref--10-2!./main.sass");
  │                                                                                                                  ^
  ╵
  stdin 4:114  root stylesheet
      in C:\xampp72\htdocs\testvuetify\node_modules\vuetify\src\styles\main.sass (line 4, column 114)
 @ ./node_modules/vuetify/src/styles/main.sass 2:14-269
 @ ./node_modules/vuetify/lib/framework.js
 @ ./node_modules/vuetify/lib/index.js
 @ ./app.js
 @ multi ./app.js

Steps To Reproduce:

Create a simple vuetify app:

import Vue from 'vue'
import Vuetify from 'vuetify/lib'

Vue.use(Vuetify)

export default new Vuetify()

and try to compile it.

I asked on laracasts too, https://laracasts.com/discuss/channels/elixir/vuetify-sass-compile-error-with-laravel-mix.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 8
  • Comments: 32 (1 by maintainers)

Most upvoted comments

@saibotk, your solution worked. Here is the mix configuration:

mix.webpackConfig({
    module: {
        rules: [
		{
		  test: /\.s(c|a)ss$/,
		  use: [
			'vue-style-loader',
			'css-loader',
			{
			  loader: 'sass-loader',
			  options: {
				implementation: require('sass'),
				fiber: require('fibers'),
			  }
			}
		  ]
		}
	  ]
    },
	plugins: [
		new VuetifyLoaderPlugin()
	],
}); 

Mix.listen('configReady', webpackConfig => {
  // Exclude vuetify folder from default sass/scss rules
  const sassConfig = webpackConfig.module.rules.find(
    rule =>
      String(rule.test) ===
      String(/\.sass$/)
  );

  const scssConfig = webpackConfig.module.rules.find(
    rule =>
      String(rule.test) ===
      String(/\.scss$/)
  );

  sassConfig.exclude.push(path.resolve(__dirname, 'node_modules/vuetify'))
  scssConfig.exclude.push(path.resolve(__dirname, 'node_modules/vuetify'))
});

mix.js('app.js', 'dist/js');

Thanks.

Check this repo by one of the Vuetify devs: https://github.com/nekosaur/laravel-vuetify. It uses Laravel Mix and Vuetify 2.

Hey,

that is a problem similar to the one, i had tonight and got finally fixed now after many hours and the solution is “pretty” simple.

But keep in mind, that this is not a Laravel Mix bug.

First, you will need to understand, how Mix works, eg. it will add some predefined rules / webpack configs. Secondly, webpack’s rules usually match based on a RegEx, and it will execute all rules. Big note on the ALL here, so no “matching the most specific rule only”, as i thought earlier.

So as the error suggests, the sass-loader got some input, which as we can see in your logs, is already processed (it already contains javascript instructions), and suddenly finds some instructions, it cannot handle (var content = ....). So that is what the error is all about.

How to fix your webpack config:

Mix adds rules matching all .sass and .scss files, by default. So you can either remove the custom rule you found on the vuetify documentation (and you may need to adjust some configs, but it should work out-of-the-box), or you will need to exclude the vuetify folder from the default rules, like so:

Mix.listen('configReady', webpackConfig => {
  // Exclude vuetify folder from default sass/scss rules
  const sassConfig = webpackConfig.module.rules.find(
    rule =>
      String(rule.test) ===
      String(/\.sass$/)
  );

  const scssConfig = webpackConfig.module.rules.find(
    rule =>
      String(rule.test) ===
      String(/\.scss$/)
  );

  sassConfig.exclude.push(path.resolve(__dirname, 'node_modules/vuetify'))
  scssConfig.exclude.push(path.resolve(__dirname, 'node_modules/vuetify'))

Which is, what i did, to also apply some custom PostCSS settings (parent prefixing, to restrict vuetify css, to only be valid inside a specific parent css identifier 😃 )

Side note: Then you would need to separate rules for .scss and .sass since sass-loader has an option called, indentedSyntax which has to be true for sass files and false for scss files.

I hope this explanation is helpful, as it would have been for me before researching for hours. 👍

I agree that the repos get outdated quick, especially all the 1.x templates out there. But I do think a 2.x repo right now would be a useful scaffold for many of us that just a need a starting point. I’m hoping it’s not a major effort, since I already feel bad asking. If there is anything I can do assist, let me know. I was hoping to document the process, but it was much more complicated than I anticipated and I haven’t been able to get a stable example running. Thanks again for your direction thus far.

Thanks for sharing. I’ve been struggling with this for the past few days. My apologies upfront for asking, but would it possible to post a basic repo with a working example of Laravel 5.8 using Vuetify with Sass variable customizations? Once complete, I’m hoping to document the process for the Vuetify team in hope of adding a Laravel + Vuetify section to the Vuetify docs. It’s pretty complex for those without deep webpack knowledge, but it’s such a powerful combination if we can get it working. Thank you again for your time.

I had to update @filipembcruz 's solution to the following code:

// Dependencies
{
        "laravel-mix": "^6.0.6",
        "sass": "~1.32",
        "sass-loader": "^11.1.1",
        "vue": "^2.5.17",
        "vue-loader": "^15.9.6",
        "vue-template-compiler": "^2.6.10",
        "vuetify": "^2.6.1",
        "vuetify-loader": "^1.7.3"
}
// webpack.mix.js
const mix = require('laravel-mix');

Mix.listen('configReady', webpackConfig => {

    // scss
    const scssRule = webpackConfig.module.rules.find(
        rule =>
            String(rule.test) ===
            String(/\.scss$/)
    );

    scssRule.oneOf.forEach(o => {
        const scssOptions = o.use.find(l => l.loader.includes('sass-loader')).options
        scssOptions.additionalData = '@import "./resources/scss/variables.scss";'
    })

    // sass
    const sassRule = webpackConfig.module.rules.find(
        rule =>
            String(rule.test) ===
            String(/\.sass$/)
    );

    sassRule.oneOf.forEach(o => {
        const scssOptions = o.use.find(l => l.loader.includes('sass-loader')).options
        scssOptions.additionalData = '@import "./resources/scss/variables.scss"'
    })
});

mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/gift.js', 'public/js')
    .vue()
    .postCss('resources/css/app.css', 'public/css', [
        require('postcss-import'),
        require('tailwindcss'),
        require('autoprefixer'),
    ])
    .webpackConfig(require('./webpack.config'));

if (mix.inProduction()) {
    mix.version();
};
// webpack.config.js
module.exports = {
    resolve: {
        alias: {
            '@': path.resolve('resources/js'),
        },
    },
    plugins: [
        new VuetifyLoaderPlugin()
    ]
};

The loader property contains a full path now, so we changed this to check if it contains the sass-loader substring. Sass-loader has a new API for the more recent versions and requires an option additionalData instead of prependData now.

Why did I pick this solution instead of declaring the rules directly in the webpack config? VuetifyLoaderPlugindeclares it’s own rules which I haven’t been able to find or alter yet, and I didn’t find any way to define the variables.sass file by configuration. Adding the rules in the webpack config triggers errors as the following:

SassError: Expected newline.
SassError: expected "{".

because the rules are executed twice (1x from vuetify loader plugin, 1x manually added in webpack.config.js).

Altering the rules generated by the vuetify loader plugin with Mix.listen() was the only solution that worked for me.

After many issues, I solve this on Laravel 8.

// Dependencies
{
        "laravel-mix": "^6.0.6",
        "sass": "^1.20.1",
        "sass-loader": "^8.0.0",
        "vue": "^2.5.17",
        "vue-loader": "^15.9.5",
        "vue-template-compiler": "^2.6.10",
        "vuetify": "^2.4.3",
        "vuetify-loader": "^1.7.1",
}
// webpack.mix.js
const mix = require('laravel-mix');
const webpack = require('./webpack.config');
Mix.listen('configReady', webpackConfig => {
    // scss
    const scssRule = webpackConfig.module.rules.find(
        rule =>
            String(rule.test) ===
            String(/\.scss$/)
    );
    scssRule.oneOf.forEach(o => {
        const scssOptions = o.use.find(l => l.loader === 'sass-loader').options
        scssOptions.prependData = '@import "./resources/sass/_variables.scss";'
    })

    // sass
    const sassRule = webpackConfig.module.rules.find(
        rule =>
            String(rule.test) ===
            String(/\.sass$/)
    );

    sassRule.oneOf.forEach(o => {
        const scssOptions = o.use.find(l => l.loader === 'sass-loader').options
        scssOptions.prependData = '@import "./resources/sass/_variables.scss"'
    })
})
mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/gift.js', 'public/js')
    .vue()
    .sass('resources/sass/pages/home.scss', 'public/css')
    .sass('resources/sass/pages/gift.scss', 'public/css')
    .webpackConfig(Object.assign(webpack))
    .copyDirectory('resources/images/', 'public/images');

if (mix.inProduction()) {
    mix.version();
};
// webpack.config.js
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
module.exports = {
    plugins: [
        new VuetifyLoaderPlugin(),
    ]
};