Storybook: TypeScript imports are not resolved from addons.ts

Created on 25 Jun 2019  路  7Comments  路  Source: storybookjs/storybook

Bug or support request summary
Non-js modules cannot be imported into addons.js/addons.ts.
Webpack throws

ModuleNotFoundError: Module not found: Error: Can't resolve './addon-selectButton/register' in '/path/to/project/packages/game/.storybook'

To Reproduce
Import any not-js (tsx in my case) module into addons.ts.
In case I rename imported file to .js, it is being loaded, however doesn't seem to be transpiled and fails to load other dependencies.
With that import commented out everything works fine.

Expected behavior
Module is imported without any errors.

Code snippets
Webpack config from output with --debug-webpack param

Preview webpack config
{ resolve:
   { modules:
      [ 'node_modules',
        '/path/to/project/packages',
        '/path/to/project/packages/game/.storybook' ],
     extensions: [ '.mjs', '.js', '.jsx', '.json', '.ts', '.tsx' ],
     alias:
      { ...nothing related to that path... } },
  plugins:
   [ HtmlWebpackPlugin {
       options:
        { template:
           '/path/to/project/node_modules/@storybook/core/dist/server/templates/index.ejs',
          templateContent: false,
          templateParameters: [Function: templateParameters],
          filename: 'iframe.html',
          hash: false,
          inject: false,
          compile: true,
          favicon: false,
          minify: undefined,
          cache: true,
          showErrors: true,
          chunks: 'all',
          excludeChunks: [],
          chunksSortMode: 'none',
          meta: {},
          title: 'Webpack App',
          xhtml: false,
          alwaysWriteToDisk: true },
       childCompilerHash: undefined,
       childCompilationOutputName: undefined,
       assetJson: undefined,
       hash: undefined,
       version: 4 },
     DefinePlugin {
       definitions:
        { 'process.env':
           { NODE_ENV: '"development"',
             NODE_PATH: '""',
             PUBLIC_URL: '"."',
             STORYBOOK_IS_RUNNING: '"true"' },
          NODE_ENV: '"development"' } },
     WatchMissingNodeModulesPlugin {
       nodeModulesPath:
        '/path/to/project/packages/game/node_modules' },
     HotModuleReplacementPlugin {
       options: {},
       multiStep: undefined,
       fullBuildTimeout: 200,
       requestTimeout: 10000 },
     CaseSensitivePathsPlugin { options: {}, pathCache: {}, fsOperations: 0, primed: false },
     ProgressPlugin {
       profile: false,
       handler: undefined,
       modulesCount: 500,
       showEntries: false,
       showModules: true,
       showActiveModules: true },
     DefinePlugin { definitions: {} },
     NormalModuleReplacementPlugin { resourceRegExp: /core-js/, newResource: [Function] },
     DefinePlugin {
       definitions:
        { 'process.env': { STORYBOOK: 'true' },
          'window.EVO_VERBOSE': '(function() { return false; })' } },
     ExtractCssChunks {
       options:
        { filename: '[name].css',
          orderWarning: true,
          chunkFilename: '[name].css' },
       hotLoaderObject:
        { loader:
           '/path/to/project/node_modules/extract-css-chunks-webpack-plugin/dist/hotLoader.js',
          options: { cssModules: undefined, reloadAll: undefined } } },
     HappyPlugin {
       name: 'HappyPack',
       state:
        { loaders: [],
          baseLoaderRequest: '',
          foregroundThreadPool: null,
          verbose: false,
          debug: false },
       config:
        { id: '/\\.tsx?$/',
          compilerId: 'default',
          threads: 3,
          verbose: true,
          threadPool:
           { size: 3,
             start: [Function: start],
             isRunning: [Function: isRunning],
             compile: [Function: compile],
             stop: [Function: stop] },
          use:
           [ { loader: 'ts-loader',
               options:
                { transpileOnly: true,
                  compilerOptions: { declaration: false },
                  happyPackMode: true } } ] },
       id: '/\\.tsx?$/' } ],
  module:
   { rules:
      [ { test: /\.(mjs|jsx?)$/,
          use:
           [ { loader: 'babel-loader',
               options:
                { cacheDirectory:
                   '/path/to/project/packages/game/node_modules/.cache/storybook',
                  presets:
                   [ [ '/path/to/project/node_modules/@babel/preset-env/lib/index.js',
                       { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' } ],
                     '/path/to/project/node_modules/@babel/preset-react/lib/index.js',
                     '/path/to/project/node_modules/@babel/preset-flow/lib/index.js' ],
                  plugins:
                   [ '/path/to/project/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                     '/path/to/project/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                     '/path/to/project/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                     [ '/path/to/project/node_modules/babel-plugin-emotion/dist/babel-plugin-emotion.cjs.js',
                       { sourceMap: true, autoLabel: true } ],
                     '/path/to/project/node_modules/babel-plugin-macros/dist/index.js',
                     '/path/to/project/node_modules/@babel/plugin-transform-react-constant-elements/lib/index.js',
                     '/path/to/project/node_modules/babel-plugin-add-react-displayname/index.js',
                     [ '/path/to/project/node_modules/babel-plugin-react-docgen/lib/index.js',
                       { DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES' } ] ] } } ],
          include: [ '/path/to/project/packages/game' ],
          exclude:
           [ '/path/to/project/packages/game/node_modules' ] },
        { test: /\.md$/,
          use:
           [ { loader:
                '/path/to/project/node_modules/@storybook/core/node_modules/raw-loader/dist/cjs.js' } ] },
        { test: /\.css$/,
          sideEffects: true,
          use:
           [ '/path/to/project/node_modules/style-loader/index.js',
             { loader:
                '/path/to/project/node_modules/css-loader/dist/cjs.js',
               options: { importLoaders: 1 } },
             { loader:
                '/path/to/project/node_modules/postcss-loader/src/index.js',
               options:
                { ident: 'postcss', postcss: {}, plugins: [Function: plugins] } } ] },
        { test: /\.tsx?$/, use: 'happypack/loader?id=/\\.tsx?$/' },
        { test: /\.(png|jpg|svg|ttf|eot|woff|woff2|gif|mp3|ogg|mp4)$/,
          loader: 'file-loader' },
        { test: /\.pcss$/,
          use:
           [ '/path/to/project/node_modules/extract-css-chunks-webpack-plugin/dist/loader.js',
             { loader: 'css-loader',
               options:
                { modules: 'local',
                  localIdentName: '[local]--[hash:base64:5]',
                  url: true,
                  importLoaders: 1 } },
             { loader: 'postcss-loader' } ] },
        { test: /lib\/polyfills.js$/,
          loaders: [ 'imports-loader?this=>window' ] } ] },
  node: { fs: 'empty', net: 'empty' },
  mode: 'development',
  bail: false,
  devtool: '#cheap-module-source-map',
  entry:
   [ '/path/to/project/node_modules/@storybook/core/dist/server/common/polyfills.js',
     '/path/to/project/node_modules/@storybook/core/dist/server/preview/globals.js',
     '/path/to/project/packages/game/.storybook/config.ts',
     '/path/to/project/node_modules/@storybook/core/node_modules/webpack-hot-middleware/client.js?reload=true' ],
  output:
   { path:
      '/path/to/project/node_modules/@storybook/core/dist/public',
     filename: '[name].[hash].bundle.js',
     publicPath: '' },
  optimization:
   { splitChunks: { chunks: 'all' },
     runtimeChunk: true,
     minimizer:
      [ TerserPlugin {
          options:
           { test: /\.m?js(\?.*)?$/i,
             chunkFilter: [Function: chunkFilter],
             warningsFilter: [Function: warningsFilter],
             extractComments: false,
             sourceMap: true,
             cache: true,
             cacheKeys: [Function: cacheKeys],
             parallel: true,
             include: undefined,
             exclude: undefined,
             minify: undefined,
             terserOptions:
              { output: { comments: /^\**!|@preserve|@license|@cc_on/i },
                mangle: false,
                keep_fnames: true } } } ] },
  performance: { hints: false } }

This very config uses happypack loader, however the same issue is when using ts-loader

addons.ts

// tslint:disable:no-import-side-effect
import "@storybook/addon-actions/register";
import "@storybook/addon-knobs/register";
import "@storybook/addon-options/register";
import "@storybook/addon-viewport/register";
import "@storybook/addons";

import "./addon-selectButton/register"; // this module comes from .tsx file

System:

  • Storybook: [5.1.9]
  • Webpack: [4.35.0]
addons inactive question / support typescript

Most helpful comment

Ok, after some more digging I finally solved this issue. It is not about "preview", but "manager" config.
After I added custom preset as described at https://github.com/storybookjs/storybook/issues/4995#issuecomment-447270973, everything became fine.

.storybook/presets.js

const path = require("path");

module.exports = [
    path.resolve(__dirname, "./ts-preset"),
];

.storybook/ts-preset.js

async function managerWebpack(baseConfig, options) {
    baseConfig.resolve.extensions.push(".ts", ".tsx");
    baseConfig.module.rules.push({ test: /\.tsx?$/, use: "ts-loader" });
    return baseConfig;
}

module.exports = {
    managerWebpack: managerWebpack,
};

However this workaround doesn't help in case TS modules used in middleware, as it looks like presets are applied later 馃槥

Are there any plans to allow manager config extensions in some more straightforward way?

All 7 comments

https://github.com/atsikov/storybook-addons-ts
Repo with minimal repro case

Ok, after some more digging I finally solved this issue. It is not about "preview", but "manager" config.
After I added custom preset as described at https://github.com/storybookjs/storybook/issues/4995#issuecomment-447270973, everything became fine.

.storybook/presets.js

const path = require("path");

module.exports = [
    path.resolve(__dirname, "./ts-preset"),
];

.storybook/ts-preset.js

async function managerWebpack(baseConfig, options) {
    baseConfig.resolve.extensions.push(".ts", ".tsx");
    baseConfig.module.rules.push({ test: /\.tsx?$/, use: "ts-loader" });
    return baseConfig;
}

module.exports = {
    managerWebpack: managerWebpack,
};

However this workaround doesn't help in case TS modules used in middleware, as it looks like presets are applied later 馃槥

Are there any plans to allow manager config extensions in some more straightforward way?

cc @ndelangen

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

Was this page helpful?
5 / 5 - 1 ratings

Related issues

shilman picture shilman  路  3Comments

MrOrz picture MrOrz  路  3Comments

tlrobinson picture tlrobinson  路  3Comments

tirli picture tirli  路  3Comments

rpersaud picture rpersaud  路  3Comments