storybook: [Storybook 6] The "zero-config" TypeScript config doesn't work on our project

Describe the bug
A clear and concise description of what the bug is.

Build error for 2 syntaxes:

  1. const enum
  2. declare class fields
ERROR in ./src/plugins/FileService/constants.ts
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /home/jack/workspace/maskbook/src/plugins/FileService/constants.ts: 'const' enums are not supported.
   9 | export const signing = 'https://service.maskbook.com/arweave-remote-signing'
  10 | 
> 11 | export const enum FileRouter {
     |        ^
  12 |     upload = '/upload',
  13 |     uploading = '/uploading',
  14 |     uploaded = '/uploaded',

ERROR in ./src/utils/ObservableMapSet.ts
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /home/jack/workspace/maskbook/src/utils/ObservableMapSet.ts: TypeScript 'declare' fields must first be transformed by @babel/plugin-transform-typescript.
If you have already enabled that plugin (or '@babel/preset-typescript'), make sure that it runs before any plugin related to additional class features:
 - @babel/plugin-proposal-class-properties
 - @babel/plugin-proposal-private-methods
 - @babel/plugin-proposal-decorators
  2 | // Consider switch to libraries like Mobx if this file become too complex.
  3 | export class ObservableWeakMap<K extends object, V> extends WeakMap<K, V> {
> 4 |     declare __brand: 'Map'
    |     ^^^^^^^^^^^^^^^^^^^^^^
  5 | 
  6 |     event = new Emitter<{ delete: [K]; set: [K, V] }>()
  7 |     delete(key: K) {

To Reproduce

Reproduction: https://github.com/DimensionDev/Maskbook/pull/1568

Expected behavior Build successfully

System:
Please paste the results of npx sb@next info here.

Environment Info:

  System:
    OS: Linux 5.8 Arch Linux
  Binaries:
    Node: 14.10.0 - /usr/bin/node
    Yarn: 1.22.5 - /usr/bin/yarn
    npm: 6.14.7 - /usr/bin/npm
  npmPackages:
    @storybook/addon-actions: ^6.0.21 => 6.0.21
    @storybook/addon-docs: ^6.0.21 => 6.0.21
    @storybook/addon-info: ^5.3.21 => 5.3.21
    @storybook/addon-knobs: ^6.0.21 => 6.0.21
    @storybook/addon-links: ^6.0.21 => 6.0.21
    @storybook/addon-viewport: ^6.0.21 => 6.0.21
    @storybook/addons: ^6.0.21 => 6.0.21
    @storybook/react: ^6.0.21 => 6.0.21

Additional context
Add any other context about the problem here.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 56
  • Comments: 26 (3 by maintainers)

Most upvoted comments

If you want this fixed, please upvote by adding a 👍 to the issue description. We use this to help prioritize!

For anyone running into an issue with declare class fields, here is what worked for me:

// Redefine Babel config to allow TypeScript class fields `declare`. Works around issue with stock Storybook configuration.
// See https://github.com/storybookjs/storybook/issues/12479.
babel: async (options) => ({
    ...options,
    plugins: [],
    presets: [
      ['@babel/preset-typescript', { allowDeclareFields: true }],
      ['@babel/preset-react', { runtime: 'automatic' }],
    ],
  }),

I wish I’d be able to preserve more of Storybook’s configuration as-is but turning on allowDeclareFields isn’t enough. This transform also has to be applied before the other conflicting plugins.


I’m surprised this is labeled a “question / support” issue and not bug, considering the two issues reported here literally mean there isn’t “zero configuration needed” for TypeScript projects. I can appreciate there might be more urgent things to fix but surely it wouldn’t take that much effort to amend this documentation with reference to unsupported TypeScript syntax until the issue is fixed.

Similar to other solutions, but this one worked for my project

in main.js

module.exports = {
    stories: ["../**/*.stories.(ts|tsx)"],
    addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-a11y"],
    webpackFinal: async (config, { configType }) => {
        // `configType` 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.

        // Return the altered config
        return config;
    },
    babel: async ({ plugins, ...rest }) => ({
        ...rest,
        // any extra options you want to set
        plugins: ["const-enum", ...plugins],
    }),
};

Babel config is the part that is modified

    babel: async ({ plugins, ...rest }) => ({
        ...rest,
        // any extra options you want to set
        plugins: ["const-enum", ...plugins],
    }),

Had the same issue and was able to fix it by adding babel-plugin-const-enum and a .babelrc file in my .storybook folder as below.

{
  "plugins": ["const-enum", "@babel/transform-typescript"]
}

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!

It seems that you can make it work by using those babel presets: babel-preset-const-enum and babel-preset-typescript.

Then in your .babelrc file, you can add:

"presets": [
    "@babel/typescript",
    [
      "const-enum",
      {
        "transform": "removeConst"
      }
    ]
  ]

It allows you to have a mix of stories written in .mdx and .tsx.

If you have an error mentionning isLeaf, it certainly mean that you have stories with same titles and it should be fixed by having different titles.

Had the same issue with const-enum, patched webpack config such as

// const isLoader = ruleSetUse => typeof ruleSetUse === 'object';

webpackFinal: async config => {
   config.module.rules = config.module.rules.map(rule => {
     // Find the rule containing 'babel-loader'
     const isBabelRule = Array.isArray(rule.use) && rule.use.find(use => isLoader(use) && use.loader.includes('babel-loader'));
     if (isBabelRule) {
       const { presets } = rule.use[0].options;
       // NOTE: need to add `const-enum` for support const enum transpilation.
       // see https://github.com/dosentmatter/babel-preset-const-enum#usage
       if (!presets.includes('const-enum')) {
         rule.use[0].options.presets = [...presets, 'const-enum'];
       }
       return rule;
     }
     return rule;
   });
   ...

Just installing babel-plugin-const-enum not helped.