Como primer paso después de hacer un CRA (create-react-app), instalo Storybook y Bit; los dos me permiten tener mi documentación, toolbox, y sincronización de mis componentes a través de todos mis proyectos.
Recientemente estoy migrando mis apps y las nuevas que voy realizando en React con Typescript. A continuación los pasos para configurar correctamente (según mi manera de ver) React con Typescript y Storybook.
1. Crear el Proyecto con Soporte de Typescript.
Supongamos que mi proyecto se llama MiProyecto:
npx create-react-app MiProyecto --template typescript
Con esto ya tendré mi proyecto configurado en Typescript, pero aun faltan algunas configuraciones para que en VSCode trabaje de la manera correcta:
Instalar dependencias
A continuación estas son todas las dependencias para una integración correcta de Typescript en el proyecto creado:
npm install -D @typescript-eslint/eslint-plugin @typescript-eslint/parser babel-eslint eslint eslint-config-airbnb eslint-config-prettier eslint-plugin-import eslint-plugin-jest eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react husky lint-staged prettier react-test-renderer require-context.macro tslint tslint-config-prettier tslint-plugin-prettier tslint-react
Aquí hay algunas instaladas preparándonos para Storybook. Debemos crear algunos archivos para la configuración del linter en el root del proyecto:
.env
SKIP_PREFLIGHT_CHECK=true
.eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
extends: [
'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
ecmaFeatures: {
jsx: true, // Allows for the parsing of JSX
},
},
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
},
settings: {
react: {
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
},
},
};
.prettierrc
{
"printWidth": 120,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2016",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, // Allow JavaScript files to be compiled
"skipLibCheck": true, // Skip type checking of all declaration files
"esModuleInterop": true, // Disables namespace imports (import * as fs from "fs") and enables CJS/AMD/UMD style imports (import fs from "fs")
"allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export
"strict": true, // Enable all strict type checking options
"forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file.
"module": "esnext", // Specify module code generation
"moduleResolution": "node", // Resolve modules using Node.js style
"isolatedModules": true,
"resolveJsonModule": true, // Include modules imported with .json extension
"noEmit": true, // Do not emit output (meaning do not compile code, only perform type checking)
"jsx": "react", // Support JSX in .tsx files
"sourceMap": true, // Generate corrresponding .map file
"declaration": true, // Generate corresponding .d.ts file
"noUnusedLocals": true, // Report errors on unused locals
"noUnusedParameters": true, // Report errors on unused parameters
"experimentalDecorators": true, // Enables experimental support for ES decorators
"noFallthroughCasesInSwitch": true // Report errors for fallthrough cases in switch statement
},
"include": [
"src/**/*" // *** The files TypeScript should type check ***
],
"exclude": ["node_modules", "build"], // *** The files to not type check ***
"plugins": [{ "name": "typescript-tslint-plugin" }]
}
tslint.json
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"rulesDirectory": ["tslint-plugin-prettier"],
"rules": {
"prettier": true,
"interface-name": false
},
"linterOptions": {
"exclude": ["config/**/*.js", "node_modules/**/*.ts", "coverage/lcov-report/*.js"]
}
}
y en el Package debemos configurar:
scripts: {
...
"lint-ts": "tslint -c tslint.json 'src/**/*.{ts,tsx}'",
"lint-js": "eslint 'src/**/*.{js,jsx}' --quiet --fix",
"lint": "tslint -c tslint.json src/**/*.{ts,tsx} --fix --format verbose",
...
},
...
"husky": {
"hooks": {
"pre-commit": "export CI=true && yarn build && lint-staged && yarn test",
"pre-push": "export CI=true && yarn build && lint-staged && yarn test"
}
},
"lint-staged": {
"*.{ts,tsx}": [
"tslint -c tslint.json"
],
"*.{js,jsx}": [
"eslint --fix"
]
}
...
Ejecutamos los linters para verificar que no tenemos errores, en caso de encontrarlos corregirlos.
npm run lint-ts
npm run lint-js
npm run lint
2. Instalar Storybook
Realizamos la instalación de Storybook, aqui tambien estan los addons que he empleado para mi instalación en este "boiler-plate" (importante tener instalado el cli de Storybook):
npx -p @storybook/cli sb init --story-format=csf-ts
npm install -D @storybook/addon-actions @storybook/addon-docs @storybook/addon-knobs @storybook/addon-links @storybook/addon-storyshots @storybook/preset-create-react-app @storybook/react @types/storybook__addon-knobs @types/storybook__addon-storyshots @types/storybook__reac
Creamos un folder que llamaremos .storybook. En el crearemos 4 archivos:
addon.ts
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-docs/register';
import '@storybook/addon-knobs/register';
config.ts
import { configure } from '@storybook/react';
import requireContext from 'require-context.macro';
const req = requireContext('../src', true, /\.stories\.tsx$/);
function loadStories() {
req.keys().forEach(req);
}
configure(loadStories, module);
main.ts
module.exports = {
stories: ['../src/**/*.stories.(ts|tsx|js|jsx)'],
addons: [
'@storybook/addon-actions',
'@storybook/addon-links',
'@storybook/addon-knobs',
'@storybook/preset-create-react-app',
{
name: '@storybook/addon-docs',
options: {
configureJSX: true,
},
},
],
};
webpack.config.ts
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
y en nuestro package.json adicionar estas dos opciones:
...
scripts: {
...
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public",
...
},
...
Ya estaria lista la configuracion; pero para probarlo corriendo debemos crear un componente, en este caso creamos un componente muy sencillo, como un boton con dos colores amarillo, y verde.
./src/components/buttons/Button/Button.tsx
import React from 'react';
// ?Button Component
export interface IProps {
color: string;
onClick?: (color: string) => void;
}
export default (props: IProps) => {
const { color, onClick } = props;
const handleClick = (): void => {
if (onClick) onClick(color);
};
return (
<button style={{ color }} onClick={handleClick}>
Color Button
</button>
);
};
Este sería nuestro componente pero para visualizarlo en StoryBook necesitamos crear el Storie para este componente:
./src/components/buttons/Button/Button.stories.tsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import Button from './Button';
import { action } from '@storybook/addon-actions';
import { withKnobs, text, select } from '@storybook/addon-knobs';
storiesOf('Button', module)
.addDecorator(withKnobs)
.add('Amarillo', () => (
<Button
color={select('color', { Amarillo: 'yellow', Naranja: 'orange' }, 'yellow')}
onClick={action('Presiono Click')}
/>
))
.add('Verde', () => <Button color={text('color', 'green')} onClick={action('clicked')} />);
Con esto ya creado, vamos a correr nuestro servidor de Storybook para visualizar el componente:
yarn storybook
En el navegador veriamos:
Podemos cambiar el color de acuerdo a lo que configuramos, ver cuando presionamos el botón, ver todos los componentes, y mas.
Ya estamos entonces listos con un proyecto inicial en React, con Typescript, y StoryBook.
Instalaremos Bit, y configuraremos estos componentes también en su versión con Styled Components en un próximo Post.
PS: Sigueme, comparte, comment y da Like si te sirvio este Post.
Top comments (0)