storybook: Storybook (webpack 5) breaks images inline loaders

Describe the bug Requiring an image (png/svg) with inline loaders provides wrong output that ignores these loaders.

testImage = require('!file-loader!./images/test-image.png').default;
testIcon = require('!html-loader!image-webpack-loader!./images/test-icon.svg');

To Reproduce

https://github.com/artaommahe/-storybook-webpack5-inline-loaders

  • yarn install
  • yarn storybook
  • see wrong images urls and content in AppComponent’s template (testImage’s require here contains similar path as testIcon)
image:

icon: "static/media/src/app/images/test-icon..svg"
  • yarn start (to run angular dev server)
  • see proper images urls and content in AppComponent’s template
image: "747f39b8dc75b31017d31bca80ccaf2e.png"

icon: { "default": "<svg ...</svg>" }

Same issue with require.context (uncomment it in AppComponent’s OnInit method and comment out requires)

System

Environment Info:

  System:
    OS: Windows 10 10.0.19042
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  Binaries:
    Node: 12.18.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.10 - C:\Program Files\nodejs\yarn.CMD
    npm: 6.14.5 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 91.0.4472.124
    Edge: Spartan (44.19041.1023.0), Chromium (91.0.864.59)
  npmPackages:
    @storybook/addon-actions: ^6.3.2 => 6.3.2
    @storybook/addon-essentials: ^6.3.2 => 6.3.2
    @storybook/addon-links: ^6.3.2 => 6.3.2
    @storybook/angular: ^6.3.2 => 6.3.2
    @storybook/builder-webpack5: ^6.3.2 => 6.3.2
    @storybook/manager-webpack5: ^6.3.2 => 6.3.2

Additional context Worked fine with storybook 6.2.9

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 26 (14 by maintainers)

Most upvoted comments

btw current workaround is to remove images loader in webpack config customisation

config.module.rules = config.module.rules.filter(rule => !rule.test || !rule.test.source.includes('png'));

@artaommahe just venting a bit, thanks for being patient with us on this! 😄

Can you try this and report if this is enough for a solution in your use case?

you cant do this cause angular-cli does not have such configurations and require('./images/test-image.png') will not work there. This is a separate issue that storybook does not use angular-cli’s configuration to build components but something local https://github.com/storybookjs/storybook/issues/11610. This produces wrong behavior due to different environment (webpack configuration) for the same code between framework (angular-cli or any other) and storybook.

!! syntax

yep, it does not work…

works fine, as expected (after downgrading angular to 11.2.0 and html/image-webpack loaders to work with webpack 4)

Ok, it sounds like there’s something in base configuration that breaks between the two in 6.3.2 then. That’s good info for debugging further.

Starting from webpack 5, it’s recommended to not use the inline syntax and use asset modules instead. See here. I’ve also written about the topic if you want to learn more.

To illustrate the usage against your project, I set up configuration as follows:

.storybook/main.js

const { merge } = require("webpack-merge");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  core: {
    builder: "webpack5",
  },
  webpackFinal: async (config) =>
    merge(config, {
      module: {
        rules: [
          {
            resourceQuery: /asset/,
            type: "asset",
          },
          {
            test: /\.svg$/,
            type: "asset",
            use: ["html-loader", "image-webpack-loader"],
          },
        ],
      },
    }),
};

I set up two examples. The first one lets you apply asset type based on ?asset and the second one is matching automatically. In this project I might go with the second form for all unless you prefer more control in which the first type is more handy.

This relies on my tool webpack-merge for composition to keep things simple.

Then on app side I changed things as follows:

  testImage = require('./images/test-image.png?asset');
  testIcon = require('./images/test-icon.svg');

This emits below:

Screen Shot 2021-06-30 at 18 11 40

I think there’s some HTML work possibly missing but the output looks ok to me.