Storybook: TypeScript modules not resolved when using "baseUrl".

Created on 7 Sep 2018  路  5Comments  路  Source: storybookjs/storybook

Support request summary

@storybook/angular is not resolving non-relative imports. I believe non-relative imports are a relative new feature of TypeScript that allow you to reference imports from a baseUrl rather than always using relative imports to your own code.

I think that support for this feature should be a priority as VS Code will now rename all your modules to use non-relative imports automatically when you move/rename a file so its difficult problem to avoid.

Steps to reproduce

Create a strorybook project with Angular 6.1.1 and use non-relative imports in your code, e.g.

src/app/somefile.ts

import { environment } from 'environments/environment';
// instead of import { environment } from '../environments/environment';

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

"@storybook/addon-actions": "^4.0.0-alpha.20",
"@storybook/addon-centered": "^4.0.0-alpha.20",
"@storybook/addon-knobs": "^4.0.0-alpha.20",
"@storybook/addon-links": "^4.0.0-alpha.20",
"@storybook/addon-notes": "^4.0.0-alpha.20",
"@storybook/addon-storysource": "^3.4.10",
"@storybook/addons": "^4.0.0-alpha.20",
"@storybook/angular": "^4.0.0-alpha.20",

Affected platforms

Windows 10

Workaround

I have managed to work around this using the TsconfigPathsPlugin and modifying my tsconfig.json file to use compilerOptions.paths (note the mappings look slightly ridiculous).

.storybook/tsconfig.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "module": "es2015",
    "paths": {
      "app/*": ["app/*"],
      "pages/*": ["pages/*"],
      "shared/*": ["shared/*"],
      "environments/*": ["environments/*"]
    }
  },
  "exclude": [
    "../src/test.ts",
    "../src/**/*.spec.ts",
    "../src/**/*.stories.ts"
  ],
  "include": ["../src/**/*"]
}

NB: compilerOptions.baseUrl has a value of "./src" in my root tsconfig.json

.storybook/webpack.config.js

const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = (baseConfig, env, config) => {
  config.resolve.plugins = config.resolve.plugins || [];
  config.resolve.plugins.push(
    new TsconfigPathsPlugin({
      configFile: path.resolve(__dirname, '../tsconfig.json')
    })
  );
  return config;
};

NB: The initial build is also excruciatingly slow, but I don't think its related.

angular question / support typescript

Most helpful comment

I highly recommend using tsconfig-paths-webpack-plugin for aliases.

CC: @shilman - i feel like this is worth recommending at least in FAQ or maybe out of the box

setup:

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
  stories: ['../**/*.stories.mdx', '../**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
  webpackFinal: async (config) => {
    config.resolve.plugins.push(new TsconfigPathsPlugin({}));
    return config;
  },
};

All 5 comments

Regarding the absolute paths, there was a similar issue - #3916. Maybe we should add 'baseUrl' to resolve.modules by default 馃

For build time, please check this - #3968

Thanks @igor-dv its all working a treat now. And the build time has gone from 7 minutes down to 20 seconds 馃殫 馃挩

Here's my .storybook/webpack.config.js for anyone that needs it, although hopefully this will be fixed in the angular storybook project soon.

const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = (baseConfig, env, config) => {
  // To get tsconfig baseUrl working
  // There is likely a better way to extract the baseUrl from tsconfig.
  config.resolve.modules.push(path.resolve(__dirname, '../src'));

  // To dramatically increase the build speed.
  let rule = config.module.rules.find(rule => {
    const { loader } = rule.use[0];
    return loader && loader.includes('ts-loader');
  });
  rule.use[0].options.transpileOnly = true;
  config.plugins.push(
    new ForkTsCheckerWebpackPlugin({
      tslint: path.resolve(__dirname, '../tslint.json'),
      tsconfig: path.resolve(__dirname, 'tsconfig.json')
    })
  );
  return config;
};

@cwmrowe
adding this to the storybook webpack config works:

// To get tsconfig baseUrl working
  // There is likely a better way to extract the baseUrl from tsconfig.
  config.resolve.modules.push(path.resolve(__dirname, '../src'));

how does it work though? This seems specific to how webpack resolves module, and may or may not be directly co-related to how tsconfig is setup (?)

If it's useful to anyone, I'm doing this to avoid duplicating resolve.modules and tsconfig.json baseUrl:

// webpack.config.js
const path = require('path');
const { compilerOptions } = require('./tsconfig.json');

module.exports = {
  // other stuff
  resolve: {
    modules: [
      path.resolve(__dirname, 'node_modules'),
      path.resolve(__dirname, compilerOptions.baseUrl),
    ],
  },
};

I highly recommend using tsconfig-paths-webpack-plugin for aliases.

CC: @shilman - i feel like this is worth recommending at least in FAQ or maybe out of the box

setup:

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
  stories: ['../**/*.stories.mdx', '../**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
  webpackFinal: async (config) => {
    config.resolve.plugins.push(new TsconfigPathsPlugin({}));
    return config;
  },
};

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmmarmol picture dmmarmol  路  57Comments

dependencies[bot] picture dependencies[bot]  路  142Comments

firaskrichi picture firaskrichi  路  61Comments

p3k picture p3k  路  61Comments

Olian04 picture Olian04  路  78Comments