Cameron Hotchkies

Categories

  • Coding

Tags

  • javascript
  • react
  • storybook
  • typescript

About once a year or so I create a fresh React project and realize that over the course of the year, everything has changed.

For the benefit of future me, and current day you, I have recorded the most recent process after trying several times to determine the most clear and concise method.

The following tooling is my current preference and target:

  • React
  • TypeScript
  • ESLint
  • AirBnB lint rules
  • VSCode as Editor of choice
  • Jest for testing

Typescript enabled React

For creating a basic React application, the easiest way to get started is with Create-React-App. For adding typed support to JavaScript, the options are generally either Flow or TypeScript. I personally prefer TypeScript, but honestly do not remember why I made the switch from Flow.

Support for generating a TypeScript application is now baked directly into Create-React-App. (source)

yarn create react-app new_app_name --typescript

Storybook

Storybook is a tool that allows presentation layer components to be viewed and interacted with in isolation. This provides developers the ability to rapidly iterate on portions of an application that would normally be difficult to access or require fragile scaffolding to examine.

In the same way that heavily unit tested code tends to shape the structure of testable code, Storybook tends to encourage cleaner boundaries on the visual versus programmatic layers of React applications. This allows the more presentational components the same level of scrutiny and verification unit testing gives to logical layers.

For a period of time, getting storybook into a create react app had some manual steps. At this point, the simplest (and least error prone) method is to just use the CLI tooling provided by the Storybook developers. (source)

npx -p @storybook/cli sb init

With the currect Storybook installation, the only primary difference is that stories are still expected to be in JS files. This can be augmented with a simple update to the .storybook/config.js file (specifically \.stories\.(js|tsx) in the third parameter of require.context()):

import { configure } from '@storybook/react';

// automatically import all files ending in *.stories.js
configure(
  require.context(
    '../src/stories', true, /\.stories\.(js|tsx)$/
  ),
  module
);

ESLint for Linting

This is important. Depending on whatever other blogs you have read or skimmed, stop using TSLint. ESLint is enabled, works correctly for TypeScript and is now the preferred method.

The bulk of this section is originally sourced from Sergio Pedercini’s Blog. The first step is to add additional ESLint packages that will be used and enforce more strict opinions.

yarn add -D eslint-config-airbnb eslint-config-prettier eslint-plugin-jsx-a11y eslint-plugin-prettier prettier

I prefer the default rules, so I keep the base configuration (which is in package.json), but extend it to allowing for tsx files. The final extends entry ensures that imported TypeScript files are linted correctly.

"eslintConfig": {
  "extends": [
    "react-app",
    "plugin:jsx-a11y/recommended",
    "prettier",
    "prettier/react",
    "airbnb",
    "plugin:import/typescript"
  ],
  "plugins": [
    "jsx-a11y",
    "prettier"
  ],
  "rules": {
    "react/jsx-filename-extension": [
      1, { "extensions": [".js", ".jsx", ".tsx"] }
    ]
  }
}

Next update VS Code settings to ensure linting takes place in the editor. This is done by editing the settings.json inside of VS Code and assuming the ESLint extension is already installed.

"eslint.validate": [
    "javascript",
    "javascriptreact",
    { "language": "typescript", "autoFix": true},
    { "language": "typescriptreact", "autoFix": true}
]

Update Jest targets

For the remainder of unit tests, it is helpful to exclude the Storybook stories and the serviceWorker class from standard test coverage measurements. Add the following to the package.json:

"jest": {
  "collectCoverageFrom": [
    "src/**/*.{js,jsx,ts,tsx}",
    "!src/**/*.stories.{js,jsx,ts,tsx}",
    "!src/serviceWorker.ts"
  ]
}

Until this is no longer accurate

This ecosystem changes at a very rapid pace. I will make an effort to keep this post relatively accurate, but err on the side of more up to date information if you are unsure.