Describe the bug
I'm trying to setup a storybook using the guidelines here: https://storybook.js.org/configurations/typescript-config, but this doesn't seem to be accurate (anymore).
To Reproduce
npx create-react-app my-app
yarn add -D typescript @types/node @types/react @types/react-dom @types/jest
Rename react files from .js to .ts/.tsx
npx -p @storybook/cli sb init
yarn add -D awesome-typescript-loader
yarn add -D @types/storybook__react
yarn add -D @storybook/addon-info react-docgen-typescript-webpack-plugin
Results in following depedencies:
{
"dependencies": {
"react": "^16.6.0",
"react-dom": "^16.6.0",
"react-scripts": "2.1.1"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@storybook/addon-actions": "^4.0.4",
"@storybook/addon-info": "^4.0.4",
"@storybook/addon-links": "^4.0.4",
"@storybook/addons": "^4.0.4",
"@storybook/react": "^4.0.4",
"@types/jest": "^23.3.9",
"@types/node": "^10.12.2",
"@types/react": "^16.4.18",
"@types/react-dom": "^16.0.9",
"@types/storybook__react": "^3.0.9",
"awesome-typescript-loader": "^5.2.1",
"babel-loader": "^8.0.4",
"react-docgen-typescript-webpack-plugin": "^1.1.0",
"typescript": "^3.1.6"
}
}
Copy tsconfig.json
+ .storybook/webpack.config.js
from https://storybook.js.org/configurations/typescript-config/
Add simple button component:
// src/components/button/Button.tsx
import * as React from "react";
interface ButtonProps {
label: string
}
export const Button: React.SFC<ButtonProps> = (props) => {
return <button>{props.label}</button>;
}
Add Storybook config
// .storybook/config.ts
import { configure } from '@storybook/react';
const req = require.context('../src/stories', true, /\.tsx$/);
configure(() => {
req.keys().forEach(filename => req(filename));
}, module);
Add story
// src/stories/index.tsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import { Button } from '../components/button/Button';
const stories = storiesOf('Button', module);
stories.add(
'test',
() => <Button>Test</Button>,
);
Expected behavior
yarn storybook
should mount a storybook with one story.
Screenshots
Code snippets
I also had to remove "isolatedModules": true
from tsconfig.json
before I could get the storybook running.
System:
Additional context
Storybook 4 + create-react-app 2.1 without typescript enabled works like a charm :)
CRA 2.0 typescript config wants "jsx": "preserve"
so that it can use babel to transform the JSX. But storybook wants "jsx": "react"
.
Okay @ashutoshrishi , thanks for clearing that out.
It seems like yarn start
in a CRA 2 app alters tsconfig.json
and thus overwrites the suggested Storybook tsconfig:
Is there a way to use the same config for Storybook as CRA 2?
Found the solution here: https://vincenttunru.com/migrate-create-react-app-typescript-to-create-react-app: a custom tsconfig.json
for Storybook.
// .storybook/tsconfig.json
{
"extends": "../tsconfig",
"compilerOptions": {
"jsx": "react",
"isolatedModules": false,
"noEmit": false
}
}
// .storybook/webpack.config.js
const path = require('path');
const TSDocgenPlugin = require('react-docgen-typescript-webpack-plugin');
module.exports = (baseConfig, env, config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('awesome-typescript-loader'),
options: { configFileName: path.resolve(__dirname, './tsconfig.json') } // << added
});
config.plugins.push(new TSDocgenPlugin()); // optional
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
This is incorrect, please follow my guide #4763 you shouldn't use awesome-typescript-loader
you should use babel-loader
which is inside cra2
@mohamedmansour this works like a charm indeed:
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]]
}
});
no need for awesome-typescript-loader
anymore.
For CRA using react-scripts-ts(Microsoft/TypeScript-React-Starter), I had to install:
yarn add -D @babel/preset-typescript
And use the following .storybook/webpack.config.js
module.exports = (baseConfig, env, config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: ['@babel/preset-react', '@babel/preset-typescript']
}
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
@ibrambe
@mohamedmansour this works like a charm indeed:
config.module.rules.push({ test: /\.(ts|tsx)$/, loader: require.resolve('babel-loader'), options: { presets: [['react-app', { flow: false, typescript: true }]] } });
no need for
awesome-typescript-loader
anymore.
It semi-works - It indeed compiles TypeScript but it also doesn't do any type validation, e.g:
const a: number = "d";
In a story works without any error.
you can use fork-ts-checker-webpack-plugin for this.
@vitalybe @igor-dv
Upgraded to storybook 4.0.6 and using this as webpack.config.js:
// .storybook/webpack.config.js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt');
module.exports = (baseConfig, env, config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve('babel-preset-react-app')]
}
});
config.resolve.extensions.push('.ts', '.tsx');
config.plugins.push(
new ForkTsCheckerWebpackPlugin({
async: false,
checkSyntacticErrors: true,
formatter: require('react-dev-utils/typescriptFormatter'),
}),
);
return config;
};
This works and has live type validation, it's based on the config in react-scripts
, so all dependencies are already loaded if you use CRA 2.
@ibrambe: why are you using fork-ts-checker-webpack-plugin-alt
instead of fork-ts-checker-webpack-plugin
?
@ibrambe: why are you using
fork-ts-checker-webpack-plugin-alt
instead offork-ts-checker-webpack-plugin
?
I have no clue, wasn't on purpose :)
@ibrambe how to configure babel-loader with custom tsconfig.json
path? I can't find it.
After following the example here
Cannot find module 'react-scripts\config\webpack.config.dev'
using packages
{
...,
"@storybook/react": "^4.1.3",
"@storybook/addon-actions": "^4.1.3",
"react-docgen-typescript-webpack-plugin": "^1.1.0",
"react-scripts": "2.1.2",
...
}
Has anyone encountered this issue also?
Has anyone encountered this issue also?
@harry-sm Same here, using 4.0.x instead of 4.1.x worked
@osi-oswald
4.0.x works thanks.
In webpack.config.js, I was getting
TypeScript error: Cannot compile namespaces when the '--isolatedModules' flag is provided. TS1208
Worked around this by adding
export function dummy() {}
to the top of that file. It would make more sense to tell CRA to ignore .stories/
, but I don't know how.
@mohamedmansour this works like a charm indeed:
config.module.rules.push({ test: /\.(ts|tsx)$/, loader: require.resolve('babel-loader'), options: { presets: [['react-app', { flow: false, typescript: true }]] } });
no need for
awesome-typescript-loader
anymore.
Hi, @mohamedmansour @ibrambe. This worked for me! Can you please explain this? Didn't quite get my head around this :/
This works:
module.exports = ({config}) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('react-scripts/node_modules/babel-loader'),
options: {
presets: [require.resolve('babel-preset-react-app')]
}
});
config.resolve.extensions.push('.ts', '.tsx');
Most helpful comment
@mohamedmansour this works like a charm indeed:
no need for
awesome-typescript-loader
anymore.