Running Gatsby with TypeScript + ESLint + Prettier — 2020 Fall version
tl;dr — I’ve successfully migrated gatsby-starter-blog to full TypeScript compatible with ESLint + Prettier. See the repository below:
Introduction
I had been looking for the best practice to make my (not finished yet) Gatsby site to full TypeScript. I had tried multiple times in last one year but every time the best practice was different and it was too hard to accomplish the goal by a novice in Gatsby or TypeScript or React or any modern JavaScript ecosystem, like me.
My acceptance criteria for this work were below:
- All code are written in TypeScript (except
gatsby-*.js
). - All code are typed and checked by IDE (WebStorm) automatically.
- All code are formatted/linted automatically by IDE and commit hook.
Since I’m a newbie to the modern JS world (disclaimer: I’m a pure backend/server-side engineer who are operationally inclined), I’d like to use better tooling as much as possible from the beginning so that I can avoid unnecessary mistakes, I thought. However, the tooling in this world is just chaos due to the volume of ecosystem and velocity of the developments. I don’t want to refresh my learning of its history here, but I’d like to give you a few examples:
- Prettier becomes a kind of de facto of formatter but ESLint has ability to format as well.
- TSLint was the de facto linter but it’s now ESLint.
- Gatsby required to add TypeScript plugin explicitly, but now it’s included out-of-the-box.
- However, the plugin doesn’t use tsc and there is no type checking.
- npm vs yarn vs yarn2. Gatsby is not ready for yarn2 yet.
Also, you can find tons of similar information about “Gatsby + TypeScript” in the Internet but all (including this post) are just snapshot at the moment when written. So, you need to understand each step and apply the best practice by yourself at the time you’re doing. This post was written in November 2020.
Key items
To achieve my acceptance criteria, these were the key items I accomplished:
- Automatic type generation of GraphQL result by
gatsby-plugin-typegen
and overridinggatsby-node.js
by TypeScript usingts-node
. - Using
tsconfig.json
for type checking. Built-in TypeScript support by WebStorm. eslint-config-prettier
to resolve conflicts between ESLint and Prettier,husky
+lint-staged
for pre-commit hook, built-in ESLint and Prettier support by WebStorm.
Acknowledgments
My work was mostly just cloned from two Japanese entries. The former one gave me 95% of the steps I did. The latter provides me the history and all information around ESLint and Prettier. A huge thanks to them.
Implementations
Let’s walk through each step.
Add lint-staged
and husky
by mrm
: The easiest way to setup the pre-commit hook for Prettier. I also enabled WebStorm feature to run Prettier at saving the file. (Note: There was a bug that it was not working with Vim plugin but now fixed.) I did this as a first step so that every single file changed afterward were automatically formatted by Prettier.
Add typescript
and tsconfig.json
: I used tsc --init
to generate tsconfig.json
since it’s just enough. tsc
isn’t used for transpiling, so--noEmit
. --jsx preserve
has no meaning for type checking but jsx
parameter is required to check JSX/TSX files.
Add eslint
and .eslintrc.js
: I also used eslint --init
to generate config and install packages. The input of its wizard is recorded in the commit message. (Note: eslint --init
won’t support yarn so that I decided not to use yarn.)
Add eslint-config-prettier
to avoid conflicts: Simply I added eslint-config-prettier
and configs to extends
. I also checked the conflicts by npx eslint --print-config src/pages/using-typescript.tsx | npx eslint-config-prettier-check
Add .graphqlconfig
for WebStorm: This is not required to achieve the goal, but helps GraphQL query itself typed. The boilerplate of config was generated by WebStorm. See also this post (even it is in Japanese, its screenshots must be helpful.)
Add gatsby-plugin-typegen
and migrate to TypeScript!: Now, I just added gatsby-plugin-typegen
and migrated pages
and components
to TypeScript! Thanks to WebStorm with TypeScript / ESLint / Prettier, this step was pretty easy and had no ambiguity. Sweet.
Add ts-node
and migrate gatsby-node.js
and templates
to TypeScript: This is tricky because Gatsby doesn’t support TypeScript with gatsby-*.js
yet. Also, gatsby-plugin-typegen
seems not generating types for GraphQL query here.
Add npm
tasks and enable ESLint in pre-commit: Since now our codes are all ESLint-certified, I enabled ESLint in pre-commit hook delegated to lint-staged
. (Note: tsc
is not supporting single file with tsconfig.json
so that I can’t add it to pre-commit since it runs per file. I rely on WebStorm.)
Workaround a bug of gatsby-plugin-typegen
: The last commit is just a workaround for a bug of gatsby-plugn-typegen
.
Conclusion
Although there are still some gaps like ts-node
is needed or gatsby-plugin-typegen
doesn’t generate all types yet (and a bug), the repository has clean but all type checked and formatted code which are perfectly working with WebStorm.
Finally I can start learning TypeScript! It was long Yak Shaving, but worth to go thorough since I’m now confident about modern JavaScript ecosystem a little:)
If there is anything wrong (I believe there is), feel free to comment here or ping me.