Dennis
Dennis

Reputation: 818

Angular 4 with Webpack - SCSS file not loading

My Situation:

While developing an Angular 4 application, I wanted to make use of angular material. Since they only offer a few themes I had the need to create a custom theme. Their docs explain that in order to override the default theme you should create an scss file, so that's what I did. However, since my project didn't make use of scss files before, I had to adjust my webpack configuration. I tried to import the scss file on different places like in the styleUrls of the app component, or just with an import, nothings seems to work. Angular material keeps using the default theme.

My Webpack base file:

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path');

module.exports = {
    entry: {
        'polyfills': './src/polyfills.ts',
        'vendor': './src/vendor.ts',
        'app': './src/main.ts'
    },

    resolve: {
        extensions: ['.js', '.ts'],
        modules: [
            path.join(__dirname, 'node_modules')
        ]
    },

    resolveLoader: {
        modules: [
            path.join(__dirname, 'node_modules')
        ]
    },

    module: {
        loaders: [{
            test: /\.ts$/,
            loaders: ['ts-loader', 'angular2-template-loader']
        }, {
            test: /\.html$/,
            loader: 'html-loader'
        }, {
            test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
            loader: 'file-loader?name=assets/[name].[hash].[ext]'
        }, {
            test: /\.css$/,
            exclude: path.join(__dirname, 'src', 'modules'),
            loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader?sourceMap' })
        }, {
            test: /\.css$/,
            include: path.join(__dirname, 'src', 'modules'),
            loader: 'raw-loader'
        }, {
          test: /\.scss$/,
          exclude: /node_modules/,
          loaders: ['raw-loader', 'sass-loader']
        }
      ]
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['app', 'vendor', 'polyfills']
        }),

        new webpack.ContextReplacementPlugin(
            /angular(\\|\/)core(\\|\/)@angular/,
            path.join(__dirname, 'src')
        ),

        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }),

        new webpack.ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery',
            jquery: 'jquery'
        })
    ]
};

The webpack development file:

var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var baseConfig = require('./webpack.config.base.js');
var path = require('path');

module.exports = webpackMerge(baseConfig, {
    devtool: 'cheap-module-eval-source-map',

    output: {
        path: path.join(__dirname, 'dist'),
        publicPath: 'http://localhost:8080/',
        filename: 'js/[name].js',
        chunkFilename: 'js/[id].chunk.js'
    },

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

    devServer: {
        historyApiFallback: true,
        stats: 'minimal'
    }
});

The webpack production file:

var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var baseConfig = require('./webpack.config.base.js');
var path = require('path');

const ENV = process.env.NODE_ENV = process.env.ENV = 'production';

module.exports = webpackMerge(baseConfig, {
    devtool: 'source-map',

    output: {
        path: path.join(__dirname, 'dist'),
        publicPath: '/',
        filename: 'js/[name].[hash].js',
        chunkFilename: 'js/[id].[hash].chunk.js'
    },

    htmlLoader: {
        minimize: false // workaround for ng2
    },

    plugins: [
        new webpack.NoErrorsPlugin(),
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin('css/[name].[hash].css'),
        new webpack.DefinePlugin({
            'process.env': {
                'ENV': JSON.stringify(ENV)
            }
        })
    ]
});

The scss file in which I define my cusotm Angular Material theme:

@import '~@angular/material/theming';
@include mat-core();

$my-app-primary: mat-palette($mat-blue-grey);
$my-app-accent:  mat-palette($mat-orange, 300);
$my-app-warn:    mat-palette($mat-red, 600);

$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn);

@include angular-material-theme($my-app-theme);

How I am currently trying to import the scss file in my component's decorator:

@Component({
  selector: 'app-property-detail',
  templateUrl: './property.detail.component.html',
  styleUrls: ['./property.detail.component.css', '../../assets/css/ngMaterialTheme.scss']
})

I already did some research before posting this question.

What I found but didn't help:

Any help would be greatly appreciated!

Edit:

I have a general styles.css file that gets imported in the app module. I tried to import the scss file over there:

@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
@import './ngMaterialTheme.scss';

However, I then get a webpack error saying:

./~/css-loader?sourceMap!./src/assets/css/ngMaterialTheme.scss Module not found: Error: Can't resolve '@angular/material/theming' in ...

I figured this might be useful because they advise this in:

Upvotes: 2

Views: 3855

Answers (2)

taylorswiftfan
taylorswiftfan

Reputation: 1517

For Webpack 5 (and above?)

  module: {
     rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.scss$/, use: 'scss-loader' } //etc.
    ]
  }

Upvotes: 0

Dennis
Dennis

Reputation: 818

I have solved my issue by replacing

        {
          test: /\.scss$/,
          exclude: /node_modules/,
          loaders: ['raw-loader', 'sass-loader']
        }

with:

        {
            test: /\.scss$/,
             use: [
                  { loader: "style-loader" },
                  { loader: "css-loader" },
                  { loader: "sass-loader" }
              ]
        }

I now import both the styles.css and the scss file in the app module:

import '../../assets/css/styles.css';
import '../../assets/css/ngMaterialTheme.scss';

Upvotes: 1

Related Questions