3

I have a working configuration for webpack with Angular, so that the scss files are inserted into the bundle.js

{
  test: /\.scss$/,
  use: ['raw-loader', 'resolve-url-loader', 'sass-loader?sourceMap']
}

but then I want instead to get a single css file with all the scss in the app, so I'm using ExtractTextPlugin like this

{
  test: /\.scss$/,
  use: ExtractTextPlugin.extract({
    fallback: ['raw-loader', 'resolve-url-loader', 'sass-loader?sourceMap'],
    use: ['resolve-url-loader', 'sass-loader?sourceMap']
  })
}

Now, I'm not using 'raw-loader' because I understand the files don´t have to be inserted into the bundle.js, but the I get an error in compilation.

ERROR in ./~/resolve-url-loader!./~/sass-loader/lib/loader.js?sourceMap!./app/app.component.scss
    Module parse failed: /Users/david/Documents/work/my-angular-seed/node_modules/resolve-url-loader/index.js!/Users/david/Documents/work/my-angular-seed/node_
modules/sass-loader/lib/loader.js?sourceMap!/Users/david/Documents/work/my-angular-seed/app/app.component.scss Unexpected token (1:0)
    You may need an appropriate loader to handle this file type.
    | .app {
    |   border: 1px solid red;
    | }

If I use raw-loader, build goes fine but then I get an error when loading index.html

Uncaught Error: Expected 'styles' to be an array of strings.

Does anyone know how to fix this and why it's happening? Thanks!

EDIT

I've been checking a bit more and I think I know what the issue is, but I don´t know how to fix it.

If I use this configuration

{
  test: /\.scss$/,
  use: ExtractTextPlugin.extract({
    fallback: 'style-loader',
    use: ['css-loader', 'sass-loader']
  })
}

the app.css is generated, so all good. But then if I check the bundle.js the component has been transformed into this

AppComponent = __decorate([
    core_1.Component({
        selector: 'app-root',
        styles: [__webpack_require__(23)],
        template: "\n    <div class=\"app\">\n      Hello!\n    </div>\n  "
    })
], AppComponent);

And if I check the module 23 I see that it's empty

/* 23 */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ }),

So I'm guessing this is what angular complains about, styles is an empty array. What should be done here I think is remove completely the styles tag, as the css are used as an external separated file, right? is there a way to fix this?

David
  • 3,364
  • 10
  • 41
  • 84

1 Answers1

0

You can use css-loader, which is usually used over raw-loader for CSS. And the fallback is the loader that is used when the CSS won't be extracted (as mentioned in the extract options). I can't think of any other use than style-loader, which would insert the CSS in a <style> tag. The loaders you specify in use are still applied before that, so using raw-loader would not really have any effect.

You'd change the .scss rule to this common one (similar to the example in Extracting Sass):

{
  test: /\.scss$/,
  use: ExtractTextPlugin.extract({
    fallback: 'style-loader',
    use: ['css-loader', 'resolve-url-loader', 'sass-loader?sourceMap']
  })
}

If you don't want the style-loader as a fallback you can leave it off, the CSS will still be in the bundle if it's not extracted, just not injected into a <style> tag, but that probably won't help you.

Michael Jungo
  • 31,583
  • 3
  • 91
  • 84
  • I'm still getting the error message`Uncaught Error: Expected 'styles' to be an array of strings.` so the app.css is generated but the app worn´t work. – David Mar 04 '17 at 06:27
  • How are you using them? If it's in `@Component` it would be `styles: [css.app, css.other]` after importing like `import css from './app.component.scss'`. That would add the classes `app` and `other` to it. – Michael Jungo Mar 04 '17 at 07:31
  • I updated my question with a bit more info; actually it doesn´t matter in the final bundle.js if I use resolve-url-loader or not, the result is the same – David Mar 04 '17 at 07:34
  • The original source is the relevant one, not the generated. Anyway from that it looks like you're passing the entire imported css, which is an object with the classes mapped to the generated hash names for each css class. And using the class name in the template won't work, the classes are replaced with hashes (that's how css modules work) – Michael Jungo Mar 04 '17 at 07:40
  • I'm lost here. In my index.html I have `` and app.css is a bundle with all the css in the app, shouldn´t that be enough? I understand that for development it makes sense to have individual scss files for the components, but after the build, if I have all the styles already bundled in a file and that file is imported in the main index.html, shouldn´t all styles imports be removed from the components? – David Mar 04 '17 at 07:46
  • I'm sorry I got something mixed up, you're not using CSS modules, so forget what I said about importing them. You don't need to specify any styles, as you've already added the classes you want in your template. But you still need to import it (so that webpack knows to process it), just: `import './app.component.scss'`. So leave off the `styles` completely. – Michael Jungo Mar 04 '17 at 07:54
  • That does not sound right to me, I should not have to modify my src files to use webpack or systemjs or any other. – David Mar 04 '17 at 09:54
  • If you want CSS being processed by wepack, you need to import it. You should read the [Concepts of webpack](https://webpack.js.org/concepts/) especially the [loaders section](https://webpack.js.org/concepts/#loaders) and [How CSS is used in webpack](https://webpack.js.org/guides/code-splitting-css/). – Michael Jungo Mar 04 '17 at 10:09