[Solved] Webpack 4 – Module parse failed: Unexpected character ‘@’

I recently upgraded from Webpack 3 to 4. It’s now throwing an error:

Module parse failed: Unexpected character ‘@’ You may need an
appropriate loader to handle this file type. | @import
‘./scss/variables.scss’; | | * { @ ./src/index.js 1:0-22

In my styles.scss file, I am doing the following:

@import 'scss/variables.scss';

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, Helvetica, sans-serif;
}

In my index.js file, I am only doing the following:

import './style.scss';

In my webpack.dev.js, all I changed was an addition of mode: ‘development’:

const StyleLintPlugin = require('stylelint-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Dotenv = require('dotenv-webpack');

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'public/bundle.js'
    },
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                loader: ['babel-loader', 'eslint-loader']
            },
            {
                test: /.scss$/,
                loader: ExtractTextPlugin.extract(['css-loader', 'sass-loader'])
            }
        ]
    },
    plugins: [
        new StyleLintPlugin({
            configFile: '.stylelintrc',
            context: 'src',
            files: '**/*.scss',
            failOnError: false,
            quiet: false,
            syntax: 'scss'
        }),
        new ExtractTextPlugin('public/style.css'),
        new Dotenv()
    ]
};

I don’t know what change from Webpack 3 to 4 has caused this error.

The issue I’m having is very similar to the issue posted here: Webpack 4 Module parse failed: Unexpected character ‘@’ (1:0)

I have been through all related stackoverflow questions and none of them helped.

Here are the relevant dependencies in my package.json:

"babel-loader": "^7.1.4",
"css-loader": "^0.28.11",
"eslint-loader": "^1.9.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"node-sass": "^4.9.0",
"sass-loader": "^6.0.7",
"style-loader": "^0.20.3",
"stylelint-webpack-plugin": "^0.10.5",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack": "^4.8.3",
"webpack-cli": "^2.1.4"

Here are the relevant scripts in my package.json file, for reference in the comments:

"scripts": {
    "watch": "./node_modules/.bin/webpack --mode development --watch --progress",
    "build": "./node_modules/.bin/webpack --mode production"
},
Enquirer: Edward

||

Solution #1:

The problem was the script I was using to run Webpack did not specify the config file. This is what it should look like:

"scripts": {
  "watch": "./node_modules/.bin/webpack --watch --config webpack.dev.js",
},

I believe this was generating the @import problem because it was not loading the css-loader as without specifying the config file like above, it uses a default Webpack development config which does not include the css-loader.

Respondent: Edward

Solution #2:

As I mentioned in a comment on your question there’s an open issue with Webpack 4 compatibility: https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/701

A fix for now is to install the alpha version of the library. I’ve done a small setup just now to test this and it works with webpack 4.

Install the alpha version npm i -D [email protected] --save. Then install css-loader, sass-loader and node-sass.

Then in the webpack config file:

const ExtractTextPlugin = require('extract-text-webpack-plugin');

...

module: {
    rules: [
        {
            test: /.(js|jsx)$/,
            use: {
                loader: 'babel-loader'
            },
            exclude: /node_modules/,
            include: path.join(__dirname, 'src')
        },
        {
            test: /.scss$/,
            loader: ExtractTextPlugin.extract(['css-loader', 'sass-loader'])
        }
    ]
},

plugins: [
    new ExtractTextPlugin('bundle.css'),
]

This correctly worked for me, and also concatenated multiple scss files that were using @import statements.

In package.json it should look like

"extract-text-webpack-plugin": "^4.0.0-beta.0",
"webpack": "^4.8.3"

Edit: Just as a side note, apparently mini-css-extract-plugin works fine with webpack 4.

Respondent: Edward

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.