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

Full-control webpack config with default results in duplicate style loader rules #4296

Closed
Yogu opened this issue Oct 5, 2018 · 9 comments
Closed

Comments

@Yogu
Copy link
Contributor

Yogu commented Oct 5, 2018

We use storybook with angular in full-control webpack.config mode (to configure ts aliases). In v4.0.0-alpha.20 this worked fine, but sincd v4.0.0-alpha.21, we get the error "Module build failed: Unknown word" while loading CSS file. This is because module.rules includes css rules twice - once from angular-cli and once from the storybook's default webpack. I guess this should be migitgated by applyAngularCliWebpackConfig which extracts rulesExcludingStyles for this reason. However, this function is no longer called to generate the default config passed to our custom webpack function.

I guess this problem was introduced with presets (#4027), but I have not looked further into it.

Steps to reproduce

If the description is not clear enough, I can try to make an MCVE.

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

  • @storybook/angular 4.0.0-alpha.21 through alpha.24
@jfsiii
Copy link
Contributor

jfsiii commented Oct 5, 2018

These symptoms sound just like what I'm seeing in a React project, although we are pinned at alpha.16.

We use the full control + default mode and our setup looks roughly like

import ourConfig from 'path/to/config'

module.exports = (baseConfig, env, defaultConfig) => {
  const merged = {
    // keep storybook's defaults
    ...defaultConfig,

    // add our rules (required for SASS loaders, js/happypack, etc)
    module: {
      rules: [
        ...baseConfig.module.rules,
        ...ourConfig.module.rules
      ]
    },

    // add our plugins (babel transforms, etc)
    plugins: [...defaultConfig.plugins, ...ourPluginsFiltered ],

    // our changes to `resolve`
    resolve: { ...defaultConfig.resolve, ...ourConfig.resolve }
  }

  return merged
}

In our case the error is coming from postcss-loader

storybook unknown word css error

which is added by defaultConfig.module.rules. I switched the rules section to use baseConfig.module.rules, leaving defaultConfig for the other parts and things work as expected.

Definitely a workaround but posting in case it unblocks someone else.

@igor-dv
Copy link
Member

igor-dv commented Oct 7, 2018

@Yogu, I don't know what is MCVE is, but if it will help me to reproduce that'd be great. Also, please share your custom webpack.config for Storybook.

@jfsiii, It looks not related to the Angular issue. BTW, defaultConfig contains some rules for css, so merging it as you did could mess things up. Can you please open another issue for this with a bit more details - for example, what is the content of ourConfig.

@jfsiii
Copy link
Contributor

jfsiii commented Oct 7, 2018

@igor-dv Here's more info about our setup

Failing `webpack.config.js` (extends default config)

worked until a story imported a component which had an import from 'some/package/dist/style.css

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ourConfig = require('../webpack')

const ourPluginsFiltered = ourConfig.plugins
  // filter our HMR plugin since Storybook has its own
  // otherwise get a `SyntaxError: Maximum call stack exceeded` error
  .filter(p => !(p instanceof webpack.HotModuleReplacementPlugin))
  // exclude any of our `HtmlWebpackPlugin` entries
  // they're for creating our own entry points (index.html, unsupported.html, etc)
  // This also prevents _our_ `index.html` from clobbering storybook's file
  .filter(p => !(p instanceof HtmlWebpackPlugin))

const storySourceRule = {
  test: /(\b|\.)stories\.js$/,
  exclude: /node_modules/,
  loaders: [
    {
      loader: require.resolve('@storybook/addon-storysource/loader'),
      options: {
        uglyCommentsRegex: [
          /^eslint-.*/,
          /^global.*/,
        ]
      }
    }
  ],
  enforce: 'pre',
}

module.exports = (baseConfig, env, defaultConfig) => {
  const merged = {
    // keep storybook's defaults
    ...defaultConfig,

    // add our rules (required for SASS loaders, js/happypack, etc)
    module: {
      rules: [
        ...defaultConfig.module.rules,
        ...ourConfig.module.rules,
        storySourceRule
      ],
    },

    // add our plugins (babel transforms, etc)
    plugins: [...defaultConfig.plugins, ...ourPluginsFiltered ],

    // our changes to `resolve` which allow `import`s like
    // import Button from 'components/interactive/LinkButton'
    // vs
    // import Button from './client/components/interactive/LinkButton'
    resolve: { ...defaultConfig.resolve, ...ourConfig.resolve }
  }

  return merged
}
Working `webpack.config.js` (extends base config)

worked after changing rules section to use baseConfig instead of defaultConfig

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ourConfig = require('../webpack')

const ourPluginsFiltered = ourConfig.plugins
  // filter our HMR plugin since Storybook has its own
  // otherwise get a `SyntaxError: Maximum call stack exceeded` error
  .filter(p => !(p instanceof webpack.HotModuleReplacementPlugin))
  // exclude any of our `HtmlWebpackPlugin` entries
  // they're for creating our own entry points (index.html, unsupported.html, etc)
  // This also prevents _our_ `index.html` from clobbering storybook's file
  .filter(p => !(p instanceof HtmlWebpackPlugin))

const storySourceRule = {
  test: /(\b|\.)stories\.js$/,
  exclude: /node_modules/,
  loaders: [
    {
      loader: require.resolve('@storybook/addon-storysource/loader'),
      options: {
        uglyCommentsRegex: [
          /^eslint-.*/,
          /^global.*/,
        ]
      }
    }
  ],
  enforce: 'pre',
}

module.exports = (baseConfig, env, defaultConfig) => {
  const merged = {
    // keep storybook's defaults
    ...defaultConfig,

    // add our rules (required for SASS loaders, js/happypack, etc)
    module: {
      rules: [
        // using `baseConfig` instead of `defaultConfig` because 
        // default included additional CSS rules which caused errors
        // when importing a component which imported a CSS file, like
        // `import from 'read/dist/style.css'`
        ...defaultConfig.module.rules,
        ...ourConfig.module.rules,
        storySourceRule

      ],
    },

    // add our plugins (babel transforms, etc)
    plugins: [...defaultConfig.plugins, ...ourPluginsFiltered ],

    // our changes to `resolve` which allow `import`s like
    // import Button from 'components/interactive/LinkButton'
    // vs
    // import Button from './client/components/interactive/LinkButton'
    resolve: { ...defaultConfig.resolve, ...ourConfig.resolve }
  }

  return merged
}

ourConfig is a webpack config object which has different values depending on the environment

CSS rules from `ourConfig`
[ { loader: 'style-loader', options: { sourceMap: true } },
  { loader: 'css-loader',
    options: { sourceMap: true, minimize: false } },
  { loader: 'resolve-url-loader', options: { sourceMap: true } } ]
CSS rules from `defaultConfig`
[ '/Users/jfsiii/work/stae-product/node_modules/@storybook/core/node_modules/style-loader/index.js',
  { loader:
     '/Users/jfsiii/work/stae-product/node_modules/css-loader/index.js',
    options: { importLoaders: 1 } },
  { loader:
     '/Users/jfsiii/work/stae-product/node_modules/@storybook/core/node_modules/postcss-loader/lib/index.js',
    options:
     { ident: 'postcss', postcss: {}, plugins: [Function: plugins] } } ]

When I use baseConfig, which has no CSS rules, the error disappears

`baseConfig` rules
[ { test: /\.js$/,
    use: [ [Object] ],
    include: [ '/Users/jfsiii/work/stae-product' ],
    exclude: [ '/Users/jfsiii/work/stae-product/node_modules' ] }

@kroeder kroeder self-assigned this Oct 15, 2018
@kroeder
Copy link
Member

kroeder commented Oct 15, 2018

For documentation
This happens in alpha.25 with an fresh ng new my-project, sb init, build-storybook

Stack trace

info @storybook/angular v4.0.0-alpha.25
info 
info => Loading presets
info => Loading custom addons config.
info => Found custom tsconfig.json
info => Loading angular-cli config.
info => Get angular-cli webpack config.
info => Using default webpack setup based on "angular-cli".
info Building storybook ...
Starting type checking service...
Using 1 worker with 2048MB memory limit
ERR! Failed to build the storybook
ERR! ./src/styles.css (./node_modules/raw-loader!./node_modules/postcss-loader/lib??embedded!./node_modules/@storybook/core/node_modules/style-loader!./node_modules/css-loader??ref--17-1!./node_modules/@storybook/core/node_modules/postcss-loader/src??postcss!./src/styles.css)
ERR! Module build failed (from ./node_modules/postcss-loader/lib/index.js):
ERR! Syntax Error 
ERR! 
ERR! (2:1) Unknown word
ERR! 
ERR!   1 | 
ERR! > 2 | var content = require("!!../node_modules/css-loader/index.js??ref--17-1!../node_modules/@storybook/core/node_modules/postcss-loader/src/index.js??postcss!./styles.css");
ERR!     | ^
ERR!   3 | 
ERR!   4 | if(typeof content === 'string') content = [[module.id, content, '']];
ERR! 
ERR!  @ ./src/styles.css 2:14-325
ERR!  @ multi ./node_modules/@storybook/core/dist/server/config/polyfills.js ./node_modules/@storybook/core/dist/server/config/globals.js ./.storybook/config.js ./src/styles.css
info Building storybook completed.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! cli62@0.0.0 build-storybook: `build-storybook`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the cli62@0.0.0 build-storybook script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\kro\AppData\Roaming\npm-cache\_logs\2018-10-15T11_58_51_257Z-debug.log

Process finished with exit code 1

@igor-dv
Copy link
Member

igor-dv commented Oct 15, 2018

Maybe we are not filtering out our default css rules well for angular-cli?

@Yogu
Copy link
Contributor Author

Yogu commented Oct 15, 2018

Maybe we are not filtering out our default css rules well for angular-cli?

That's what I think, too. The code for this is still there (applyAngularCliWebpackConfig), but apparently it's not executed in the right spot anymore since alpha 21.

@kroeder
Copy link
Member

kroeder commented Oct 18, 2018

Fixed by #4431
Published in 4.0.0-rc.1

@kroeder kroeder closed this as completed Oct 18, 2018
@issue-sh issue-sh bot removed the merged label Oct 18, 2018
@artaommahe
Copy link

artaommahe commented Oct 18, 2018

@kroeder with this update there is no way to adjust angular-cli plugins/loaders cause they are merged after custom config.
We need to adjust includePaths option for scss loader and remove CopyWebpackPlugin that copies assets from angular.json that are not related to working components (monorepo with different angular projects with one angular.json at the repo root)

@igor-dv
Copy link
Member

igor-dv commented Oct 19, 2018

@artaommahe, it will be fixed with #4405

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

5 participants