Search code examples
angularsasswebpack-2

Angular 2: Scss won't load in production with webpack


In develop mode all works fine:

enter image description here

In production:

enter image description here

My webpack.config.common.js:

var webpack = require('webpack');

module.exports = {
    entry: {
        'app': './assets/app/main.ts'
    },

    resolve: {
        extensions: ['.js', '.ts']
    },

    module: {
        rules: [
            {
                test: /\.html$/,
                use: [{ loader: 'html-loader' }]
            },
            {
                test: /\.css$/,
                use: [{ loader: 'raw-loader' }]
            },
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                loaders: ['raw-loader', 'sass-loader'] 
            }
        ],
        exprContextCritical: false

    }
};

webpack.config.dev.js:

var path = require('path');

var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.config.common.js');

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

    output: {
        path: path.resolve(__dirname + '/public/js/app'),
        publicPath: "/js/app/",
        filename: 'bundle.js',
        chunkFilename: '[id].chunk.js'
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    {loader: 'awesome-typescript-loader', options: {
                        transpileOnly: true
                    }},
                    {loader: 'angular2-template-loader'},
                    {loader: 'angular-router-loader'}
                ]
            }
        ]

    }
});

webpack.config.prod.js:

var path = require('path');

var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.config.common.js');

module.exports = webpackMerge.smart(commonConfig, {
    entry: {
        'app': './assets/app/main.aot.ts'
    },

    output: {
        path: path.resolve(__dirname + '/public/js/app'),
        filename: 'bundle.js',
        publicPath: '/js/app/',
        chunkFilename: '[id].[hash].chunk.js'
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    'awesome-typescript-loader',
                    'angular2-template-loader',
                    'angular-router-loader?aot=true'
                ]
            }
        ]
    },

    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            sourceMap: false
        })
    ]
});

The scripts in the package.json:

  "scripts": {
    "start": "node ./bin/www",
    "build": "del-cli public/js/app && webpack --config webpack.config.dev.js --progress --profile --watch",
    "build:prod": "del-cli public/js/app && ngc -p tsconfig.aot.json && ngc -p tsconfig.aot.json && webpack --config webpack.config.prod.js --progress --profile --bail && del-cli 'public/js/app/**/*.js' 'public/js/app/**/*.js.map' '!public/js/app/bundle.js' '!public/js/app/*.chunk.js' 'assets/app/**/*.ngfactory.ts' 'assets/app/**/*.shim.ts' 'assets/app/**/*.ngsummary.json' 'assets/app/**/*.ngstyle.ts'",
    "build:sass": "node-sass assets/app/ -o assets/app",
    "watch:sass": "npm run build:sass && node-sass assets/app/ -wo assets/app/"
  }

In the end an example of import of the styles in .ts file:

styleUrls: ['./auth.component.scss','../common/common.scss']

Obviously i called the script to compile scss, before...

Does someone see something wrong or missing? Thanks

Update: In development works because the watch is active and the webpack is running (or something like that, because i can see in chrome's developer bar), if i run without it css are not served.

Update 2:

I found a way to make it works in production, but it crashes in development:

var webpack = require('webpack');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSass = new ExtractTextPlugin({
    filename: "bundle.css",
    disable: process.env.NODE_ENV === "development"
});

module.exports = {
    entry: {
        'app': './assets/app/main.ts'
    },

    resolve: {
        extensions: ['.js', '.ts']
    },

    module: {
        rules: [
            {
                test: /\.html$/,
                use: [{ loader: 'html-loader' }]
            },
            {
                test: /\.css$/,
                use: [{ loader: 'raw-loader' }]
            },
            {
                test: /\.scss$/,
                use: extractSass.extract({
                    use: [{
                        loader: "css-loader"
                    }, {
                        loader: "sass-loader"
                    }],
                    fallback: "style-loader"
                })
            }],
        exprContextCritical: false
    },
    plugins: [
        extractSass
    ]
};

Solution

  • SOLVED:

    Just import SCSS files instead of use "styleUrls" into the component. So it works both in developement and production.

    import './auth.component.scss';
    import '../common/common.scss';
    
    @Component({
      selector: 'tep-auth',
      templateUrl: './auth.component.html'
      providers: []
    })
    

    Remarks:

    1) In production i created a bundle of Css (see Webpack config)

    2) It's necessary to import the bundle into the views as we do with normal css file.