style-loader: Angular2 - ERROR: Expected 'styles' to be an array of strings.

Why does using style-loader with angular2 components and required css produce this error?

Webpack loaders: ['style', 'css?sourceMap', 'sass?sourceMap']

Angular 2 component styles: [ require('normalize.css'), require('./app.scss') ],

Error: Expected ‘styles’ to be an array of strings. at new BaseException (exceptions.js:17) at Object.assertArrayOfStrings (assertions.js:13) at CompileMetadataResolver.getDirectiveMetadata (metadata_resolver.js:64) at RuntimeCompiler.resolveComponent (runtime_compiler.js:34) at application_ref.js:99 at application_ref.js:292 at ZoneDelegate.invoke (zone.js:323) at Object.NgZoneImpl.inner.inner.fork.onInvoke (ng_zone_impl.js:45) at ZoneDelegate.invoke (zone.js:322) at Zone.run (zone.js:216) at NgZoneImpl.runInner (ng_zone_impl.js:76) at NgZone.run (ng_zone.js:223) at ApplicationRef_.run (application_ref.js:290) at Object.coreLoadAndBootstrap (application_ref.js:96) at Object.bootstrap (platform_browser_dynamic.js:91) at main (main.browser.ts:24) at HTMLDocument.<anonymous> (webpack-hmr.ts:57) at ZoneDelegate.invokeTask (zone.js:356) at Zone.runTask (zone.js:256) at HTMLDocument.ZoneTask.invoke (zone.js:423)

If I use styleUrls instead: styleUrls: [ require('normalize.css'), require('./app.scss') ],

I get a different error:

main.browser.ts:31 Failed to load %5Bobject%20Object%5D

What am I doing wrong?

About this issue

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

Commits related to this issue

Most upvoted comments

I ripped off a solution from the angular class web pack starter. They use the ‘to-string-loader’ for css.

{ test: /\.css$/, loaders: ['to-string-loader', 'css-loader'] }

Haven’t tried a production version yet but it got me going in dev.

This is my workaround:

styles:[require(‘./app.component.css’).toString()]``

@IAMtheIAM to answer your original question:

  1. sass loader compiles your SASS down to CSS,
  2. css loader resolves css imports and url(…)
  3. style loader injects result into DOM within a style tag The style loader is not returning a string as a result. You get the error because Angular 2 Component styles property expects an array of strings. This should work … loaders: ['raw', 'sass'] raw loader returns a string representing your CSS (compiled from SASS), which is what we want. Angular 2 will then take care of injecting your styles into the DOM. See more info here.

Sorry am a total noob on this and am sorry. But I wanted to share my last workaround that finally worked for me.

I started with WebPack Sample here: https://angular.io/docs/ts/latest/guide/webpack.html

Added to-string-loader dependency here -> https://github.com/gajus/to-string-loader

In my wepback.common.js file I added the loader:

{ test: /.css$/, exclude: helpers.root(‘src’, ‘app’), loaders:[ExtractTextPlugin.extract(‘style’, ‘css-loader’), ‘to-string’, ‘css’] },

I am new to all of this so I apologize ahead of time if I suggested something dumb…but it works for me. =)

@dingfengsaniao @borntorun This is a bit of a guess but I don’t think the ExtractTextPlugin is ‘overiding’ Angular2’s behaviour on the styles property, so whilst it’s bundling everything up, Angular isn’t really aware of the changes.

We got it working by importing global styles at the bootstrap level, rather than requiring them in the component style property. That way ExtractTextPlugin knows to pull them into a bundle.

Then we’re explicitly bundling the component specific styles as raw text in the js module, so they’re scoped to the component and get past the ‘array of string’ problem.

//webpack.config

{ // Load sass files from the theme folder only then convert to css and bundle them test: /\.scss$/, include: helpers.root('src/theme'), loader: extractTextPlugin.extract('style', 'css?postcss!sass') }, { // Load sass files from within the application folder then convert to a string, then css and include in the javascript module test: /\.scss$/, include: helpers.root('src/app'), loader: 'raw!postcss!sass' }

In main.ts import '../theme/styles.scss';

In each component (e.g.app.ts) @Component({ ... styles: [require('./app.scss')] })

Sorry, I can’t get the code formatting to work 😮(

What about this (it is what I did)…

{
    test: /\.styl$/,
    loader: 'style-loader!css-loader!stylus-loader'
}
...
styles: [String(require('./app.component.styl'))],

Since webpack 2 runs nothing. The message comes with all solutions. Finding the error in large projects is futile, because Webpack 2 simply does not issue a proper error message.

How can you really find the error. The existing solutions do not help any further. We have now found over 20 such alleged solutions. We look for 2 days the error but always the same error message:

“Expected ‘styles’ to be an array of strings” in the vendor.js

Is there a real solution ?

@Alex-Torres Thank you! This is latest version “@angular/***”: “2.2.3” “angular2-template-loader”: “0.6.0”, “extract-text-webpack-plugin”: “2.0.0-beta.4”, “webpack”: “2.1.0-beta.27”, “css-loader”: “0.26.0”, “to-string-loader”: “1.1.5”

@Component( { selector: ‘my-app’, templateUrl: ‘./app.component.html’, styleUrls: [‘./app.component.css’] } )

{ test: /.css$/, //loader: “to-string-loader!style-loader!css-loader?sourceMap” loaders: [ ExtractTextPlugin.extract( { fallbackLoader: “style-loader”, loader: ‘css-loader’ } ), ‘to-string-loader’, ‘css-loader?sourceMap’ ] },

This configuration works for me

      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loaders: 'file-loader?name=assets/[name]-[hash].[ext]'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loaders: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
      },
      {
        test: /\.sass$/,
        include: helpers.root('src', 'app'),
        loaders: ['css-to-string-loader','css-loader','sass-loader'] 
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loaders: ['css-to-string-loader','css-loader']
      }

@wittibs YES! that did it, thanks man!

It‘s still an issue if you want sourceMaps AND scss (like @IAMtheIAM in the initial comment).

1: This works for css.

2: This works for css + souceMap.

3: This works for scss.

But what‘s with scss + souceMap?

When i try 1 with scss, then i don‘t get my sourceMap:

{
    test: /\.scss$/,
    loaders: ['to-string-loader', 'css-loader?sourceMap', 'sass-loader?sourceMap']
}

When i do 2 with scss, then i am back at the initial issue Expected 'styles' to be an array of strings

{
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
}

When i do 3 with sourceMap, i don’t get a sourceMap.

{
    test: /\.scss$/,
    loaders: ['raw', 'sass?sourceMap']
}

And finally i translated @JefferyHus 's solution to scss.

{
    test: /\.scss$/,
    loaders: [
        ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
    ]
}

but then the command line gives me

ERROR in ./src/components/app/app.component.scss
Module parse failed: /my/project/path/node_modules/extract-text-webpack-plugin/loader.js?{"omit":1,"extract":true,"remove":true}!style-loader!css-loader!sass-loader!/my/project/path/src/components/app/app.component.scss Unexpected token (1:0)
You may need an appropriate loader to handle this file type.

For me this webpack setup works:

...
    let extractCSS = new ExtractTextPlugin('app.css');
...
     // loader config for global css files
     {
          test: /\.scss$/,
          exclude: [/node_modules/, /src\/app/],
          loader: extractCSS.extract('style-loader', 'raw!postcss!sass'),
      },
     // loader config for angular component styles 
      {   
          test: /\.scss$/, 
          exclude: [/node_modules/, /src\/styles/], 
          loader: 'raw!postcss!sass'
      },
...
      plugins: [
        new HtmlWebpackPlugin({
          template: 'src/app/index.html',
          hash: true,
        }),
        extractCSS
      ],

@wittibs answer is correct, so closing.