Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 6 Expected 'styles' to be an array of strings. #3593

Closed
wuyuanyi135 opened this issue May 16, 2018 · 27 comments
Closed

Angular 6 Expected 'styles' to be an array of strings. #3593

wuyuanyi135 opened this issue May 16, 2018 · 27 comments

Comments

@wuyuanyi135
Copy link

wuyuanyi135 commented May 16, 2018

If you are reporting a bug or requesting support, start here:

Bug or support request summary

I want to use storybook with Angular 6. It turns out I have to use the 4.0.0 alpha branch to make it through (#3044 ). After I managed to make the story server run, I got another error Expected 'styles' to be an array of strings., which I have no idea how to get around.

Steps to reproduce

I followed the instructions in https://storybook.js.org/basics/guide-angular/#docs-content but at the beginning the compilation failed:

node_modules/webpack/lib/DefinePlugin.js:42
		compiler.hooks.compilation.tap(
		               ^

TypeError: Cannot read property 'compilation' of undefined

Then I installed @storybook/angular@4.0.0-alpha.6. I managed to run the server, but when I load my component, it shows

Expected 'styles' to be an array of strings.
            Error: Expected 'styles' to be an array of strings.
    at assertArrayOfStrings (http://localhost:9001/static/preview.bundle.js:8372:19)
    at CompileMetadataResolver../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNonNormalizedDirectiveMetadata (http://localhost:9001/static/preview.bundle.js:17242:13)
    at CompileMetadataResolver../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver._getEntryComponentMetadata (http://localhost:9001/static/preview.bundle.js:17887:28)
    at http://localhost:9001/static/preview.bundle.js:17536:53
    at Array.map (<anonymous>)
    at CompileMetadataResolver../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNgModuleMetadata (http://localhost:9001/static/preview.bundle.js:17536:18)
    at JitCompiler../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._loadModules (http://localhost:9001/static/preview.bundle.js:29551:51)
    at JitCompiler../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._compileModuleAndComponents (http://localhost:9001/static/preview.bundle.js:29532:36)
    at JitCompiler../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler.compileModuleAsync (http://localhost:9001/static/preview.bundle.js:29492:37)
    at CompilerImpl../node_modules/@angular/platform-browser-dynamic/fesm5/platform-browser-dynamic.js.CompilerImpl.compileModuleAsync (http://localhost:9001/static/preview.bundle.js:54699:31)
        

Please specify which version of Storybook and optionally any affected addons that you're running

  • "@ storybook/angular": "4.0.0-alpha.6",
@wuyuanyi135
Copy link
Author

wuyuanyi135 commented May 19, 2018

This is an update for this issue.

In alpha.6, the aforementioned issues can be resolved by extending the webpack.config.json in .storybook directory:
note that the magic is the to-string-loader that adapt the css to what Angular 6 want.

const path = require("path");

module.exports = (baseConfig) => {
  // Extend defaultConfig as you need.

  // For example, add typescript loader:
  baseConfig.module.rules.push({
    test: [/\.stories\.tsx?$/, /index\.ts$/],
    loaders: [
      {
        loader: require.resolve('@storybook/addon-storysource/loader'),
        options: {
          parser: 'typescript',
        },
      },
    ],
    include: [path.resolve(__dirname, '../src')],
    enforce: 'pre',
  });

  baseConfig.module.rules.push({
    test: /\.css$/,
    use: ['to-string-loader', 'css-loader']
  });
  return baseConfig;
};

After getting this config file, the error becomes to failed to load XXXX.html. It seems like storybook still want to load the template page even though it has been bundled. To resolve this issue, add moduleId = module.id to each of the @Component in your Angular components.
I don't really like this workaround. Thankfully, the failed to load html problem seems to be fixed in alpha.7. But still the css files need the to-string-loader to work.

@nglazov
Copy link

nglazov commented May 19, 2018

It fixes "Expected 'styles' to be an array of strings." error, but works not correct.
Components from angular-material (eg form controls) looks bad in this configuration.

@wuyuanyi135
Copy link
Author

@nglazov I suppose that will be taken care of by the dev teams. :) Really hope it to work soon.

@enten
Copy link

enten commented May 27, 2018

Does interface NgStory correct? How about templateUrl and stylesUrl?

// app/angular/src/client/preview/angular/types.ts

export interface NgStory {
  component?: any;
  props: ICollection;
  propsMeta?: ICollection;
  moduleMetadata?: NgModuleMetadata;
  template?: string;
  styles?: string[];
}

Should we update initModule too? It doesn't seem to handle components which use templateUrl or styleUrls.

// app/angular/src/client/preview/angular/helpers.ts

const initModule = (currentStory: IGetStory): Function => {
  const storyObj = currentStory();
  const { component, template, props, styles, moduleMetadata = {} } = storyObj;

  let AnnotatedComponent;

  if (template) {
    AnnotatedComponent = createComponentFromTemplate(template, styles);
  } else {
    AnnotatedComponent = component;
  }

  const story = {
    component: AnnotatedComponent,
    props,
  };

  return getModule(
    [AppComponent, AnnotatedComponent],
    [AnnotatedComponent],
    [AppComponent],
    story,
    moduleMetadata
  );
};

@agalazis
Copy link

agalazis commented Jun 6, 2018

@wuyuanyi135 your workaround seems to work that's the way it should be shipped (In my case I didn't need the id part but your webpack config is a must)

@wuyuanyi135
Copy link
Author

wuyuanyi135 commented Jun 6, 2018

@agalazis True. I believe it was after alpha 7 where the module.id line was no longer necessary. I haven't test the later versions since I switch to Angular playground before storybook is stable for Angular.

@igor-dv
Copy link
Member

igor-dv commented Jun 14, 2018

Has anyone tried the latest alpha? it supports Angular 6.

@DmitryEfimenko
Copy link

I'm still struggling to make it work. A part of the issue might be the fact that I'm using .scss files. @wuyuanyi135 , do you have an idea what webpack configuration to use in this case? I tried the suggested loader, but that didn't work:

{
  test: /\.scss$/,
  use: [
    'style-loader', // creates style nodes from JS strings
    'css-loader', // translates CSS into CommonJS
    'sass-loader' // compiles Sass to CSS
  ]
}

@igor-dv
Copy link
Member

igor-dv commented Jun 27, 2018

If you are using scss and angular-cli, storybook should work without configuring anything.

@ryaninvents
Copy link

I fixed this issue by using text-loader. I'm not using a CSS preprocessor though.

@igor-dv
Copy link
Member

igor-dv commented Jul 12, 2018

I assume we are ok here, right?

@igor-dv igor-dv closed this as completed Jul 12, 2018
@MatissJanis
Copy link
Contributor

MatissJanis commented Jul 16, 2018

I'm using alpha.14 and experiencing the same issue, but with LESS files rather than SASS.

Weback config:

const path = require('path');

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        loaders: ['style-loader', 'css-loader', 'less-loader'],
        include: path.resolve(__dirname, '../'),
      },
      {
        test: /\.(jpe?g|png|gif)$/,
        use: 'file-loader?name=img/[name]-[hash].[ext]'
      },
      {
        test: /\.(eot|woff2?|svg|ttf)([\?]?.*)$/,
        use: 'file-loader',
      },
    ],
  },
};

@igor-dv
Copy link
Member

igor-dv commented Jul 16, 2018

AFAIR, less is also treated out-of-the-box by angular-cli, if so, you don't need to define any extra rules for the .less files.

@MatissJanis
Copy link
Contributor

Sadly, removing the .less rule does not resolve the issue, but introduces a new one:

ERROR in ./.storybook/container.less 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type.
> @import '~@org/fe-webapp-styling/src/main.less';
|
 @ ./.storybook/config.js 10:0-26
 @ multi ./node_modules/@storybook/core/dist/server/config/polyfills.js ./node_modules/@storybook/core/dist/server/config/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

ERROR in ./src/components/molecules/progress-bar/progress-bar.component.less 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> .progress-bar-warning {
|   width: 0;
| }
 @ ./src/components/molecules/progress-bar/progress-bar.component.ts 61:21-61
 @ ./src/components/molecules/progress-bar/index.ts
 @ ./src/components/molecules/index.ts
 @ ./src/components/index.ts
 @ ./src/components.module.ts
 @ ./.storybook/config.js
 @ multi ./node_modules/@storybook/core/dist/server/config/polyfills.js ./node_modules/@storybook/core/dist/server/config/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

By the looks of it, angular-cli does not add the less loader to storybook, but it does work when running ng build.

@igor-dv
Copy link
Member

igor-dv commented Jul 17, 2018

I've added this 👇 to an official storybook angular example

image

The only error I got was about the lack of less-loader, because we didn't choose this option when created our angular-cli example. After manually installing a less-loader, everything started working for me.

@MatissJanis
Copy link
Contributor

Could you please give me a URL to the example commit? I'm trying to reproduce it locally, but failing.

@MatissJanis
Copy link
Contributor

I fixed the issue by changing the LESS loader to this:

{
	test: /\.less$/,
	loaders: ['text-loader', 'style-loader', 'css-loader', 'less-loader'],
	include: path.resolve(__dirname, '../'),
}

Honestly - no idea why it works now.

@igor-dv
Copy link
Member

igor-dv commented Jul 18, 2018

I didn't commit this specific example. since there was nothing special. The official example app is here , though, you need to bootstrap the whole monorepo to be able to run it.

Anyway, to understand what is wrong in your setup we need a reproduction 🤷‍♂️

@MatissJanis
Copy link
Contributor

Yeah, that's completely understandable. Since I somehow managed to solve the issue on my project, I'll get out of your hair. Thanks for the patience! :)

@jkyoutsey
Copy link

FYI, this issue will arise if you misspell any part of the file name as well. Like, leaving off the .scss extension.

@westandy-dcp
Copy link
Contributor

westandy-dcp commented Oct 5, 2018

I followed @wuyuanyi135 solution.

  1. I added a .storybook/webpack.config.js file. The code is below.
  2. I added to-string-loader and @storybook/addon-storysource (alpha 4.0.0 version)

Here's my webpack code (same as @wuyuanyi135):

const path = require('path');

module.exports = baseConfig => {
  // Extend defaultConfig as you need.

  baseConfig.module.rules = [
    ...baseConfig.module.rules,
    {
      test: [/\.stories\.tsx?$/, /index\.ts$/],
      loaders: [
        {
          loader: require.resolve('@storybook/addon-storysource/loader'),
          options: {
            parser: 'typescript'
          }
        }
      ],
      include: [path.resolve(__dirname, '../src')],
      enforce: 'pre'
    },
    {
      test: /\.css$/,
      use: ['to-string-loader', 'css-loader']
    }
  ];

  return baseConfig;
};

Adding .less to my project looks straightforward now as well. Thank you, @wuyuanyi135 !

@iftkharhussain
Copy link

i have fixed this issue with changing
styleUrls: ['./app.component.CSS'] to styleUrls: ['./app.component.css']

just lower case styles extensions
now it works fine :)

@haskelcurry
Copy link

@DmitryEfimenko Hi Dmitry! How did you solve your issue with .scss back then? I know that it should "just work", but it doesn't in my case, just like in yours

@jlowcs
Copy link

jlowcs commented Jun 26, 2019

This error could be caused by a improper (ie too new) version of raw-loader.

See TheLarkInn/angular2-template-loader#86

Setting it to 1.0.0 fixed the issue in my project.

@Aviw13
Copy link

Aviw13 commented Jul 5, 2019

This error could be caused by a improper (ie too new) version of raw-loader.

See TheLarkInn/angular2-template-loader#86

Setting it to 1.0.0 fixed the issue in my project.

Thanx man! You saved my day

raw-loader v. 3.0.0 also has the same issue

@omares
Copy link

omares commented Aug 5, 2019

To fix the Expected 'styles' to be an array of strings error, i followed the Custom Webpack Config chapter of the storybook documentation and added a custom rule that handles scss parsing.

The debug flag --debug-webpack revealed that storybook adds a scss rule which needs to removed, as that rule would still take priority of our custom one.

Using the angular-cli setup was not an option for us as we run a custom webpack build.

The final version of the customization looks as follow.

  • JavaScript (webpack.config.js) version
// Export a function. Accept the base config as the only param.
module.exports = async ({config, mode}) => {
    // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    r = config.module.rules.filter(rule => rule.test != '/\\.s(c|a)ss$/');

    // Make whatever fine-grained changes you need
    r.push({
        test: /\.scss$/,
        // test: /\.s(c|a)ss$/,
        use: [
            'to-string-loader',
            {
                loader: 'style-loader',
                options: {
                    sourceMap: true,
                },
            },
            {
                loader: 'css-loader',
                options: {
                    sourceMap: true,
                },
            },
            {
                loader: 'sass-loader',
                options: {
                    sourceMap: true,
                },
            },
        ],
    });

    config.module.rules = r;

    // Return the altered config
    return config;
};
  • TypeScript (webpack.config.ts) version with type hints
import {Configuration, RuleSetRule} from 'webpack';

module.exports = async ({config, mode}: {config: Configuration, mode: string}) => {
    // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    if (!config.module) {
        return config;
    }

    var rules = config.module.rules.filter((rule: RuleSetRule) => rule.test != '/\\.s(c|a)ss$/');

    rules.push({
        test: /\.scss$/,
        use: [
            'to-string-loader',
            {
                loader: 'style-loader',
                options: {
                    sourceMap: true,
                },
            },
            {
                loader: 'css-loader',
                options: {
                    sourceMap: true,
                },
            },
            {
                loader: 'sass-loader',
                options: {
                    sourceMap: true,
                },
            },
        ],
    });

    config.module.rules = rules;

    // Return the altered config
    return config;
};

@gn-sky
Copy link

gn-sky commented Jan 6, 2020

Instead of ‘style-loader’, ‘css-loader’, ‘sass-loader’
I went with ‘to-string-loader’, ‘css-loader’, ‘sass-loader’
I used this article:
https://www.freecodecamp.org/news/how-to-configure-webpack-4-with-angular-7-a-complete-guide-9a23c879f471/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests