React 17 with Typescript starter kit without create-react-app (incl. Webpack, ESLint & Prettier) ⚛


*Recently updated*

There are many advantages of using create-react-app. With just few clicks you are ready to go, but some doesn’t want all that magic and tons of boilerplate code (me included). With CRA approach you’ll end up with massive “blackbox” which you will have to eject in most of the times.

If you are looking for clean and simple React + Typescript + Webpack (including dev server) + ESLint and Prettier starter kit, you’ve just found the right one. Follow the steps below or jump straight to the repository at:

Use this repo as a template:

If you find that helpful you can star the repository.

Initialize your project

yarn init --yesornpm init --yes

Install TypeScript

yarn add typescript -Dornpm i typescript --save-dev

Create tsconfig.json in root directory

"compilerOptions": {
"sourceMap": true,
"noImplicitAny": false,
"module": "commonjs",
"target": "es5",
"lib": [
"removeComments": true,
"allowSyntheticDefaultImports": true,
"jsx": "react",
"allowJs": true,
"baseUrl": "./",
"esModuleInterop": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"downlevelIteration": true,
"paths": {
"components/*": [
"include": [

Add React dependencies and types

yarn add react react-dom
yarn add @types/react @types/react-dom -D
ornpm i react react-dom --save
npm i @types/react @types/react-dom --save-dev

Create initial App files in your project’s root directory


<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>React TypeScript App</title>
<div id="root"></div>


import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));


import React from "react";
import HelloWorld from "components/HelloWorld";

const App = () => <HelloWorld />;

export default App;

As you can see, i’ve used path bind to components directory — this also needs to be sorted out in webpack’s config in order to work.


import React from "react";

const HelloWorld = () => (
<h1>Hello World</h1>

<hr />

<h3>Environmental variables:</h3>
process.env.PRODUCTION: <b>{process.env.PRODUCTION.toString()}</b>
process.env.NAME: <b>{process.env.NAME}</b>
process.env.VERSION: <b>{process.env.VERSION}</b>

export default HelloWorld;

Adding Webpack

Add dependencies

yarn add webpack webpack-cli webpack-dev-server ts-node @types/node @types/webpack @types/webpack-dev-server tsconfig-paths-webpack-plugin -Dornpm i webpack webpack-cli webpack-dev-server ts-node @types/node @types/webpack @types/webpack-dev-server tsconfig-paths-webpack-plugin --save-dev

We will run type checking through webpack (thanks to the great fork-ts-checker-webpack-plugin)

yarn add ts-loader fork-ts-checker-webpack-plugin html-webpack-plugin -Dornpm i ts-loader fork-ts-checker-webpack-plugin html-webpack-plugin --save-dev

Create webpack.config.ts in your project’s root directory

import path from "path";
import webpack, {Configuration} from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import {TsconfigPathsPlugin} from "tsconfig-paths-webpack-plugin";

const webpackConfig = (env): Configuration => ({
entry: "./src/index.tsx",
...(env.production || !env.development ? {} : {devtool: "eval-source-map"}),
resolve: {
extensions: [".ts", ".tsx", ".js"],
//TODO waiting on
plugins: [new TsconfigPathsPlugin()]
output: {
path: path.join(__dirname, "/dist"),
filename: "build.js"
module: {
rules: [
test: /\.tsx?$/,
loader: "ts-loader",
options: {
transpileOnly: true
exclude: /dist/
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
new webpack.DefinePlugin({
"process.env.PRODUCTION": env.production || !env.development,
"process.env.NAME": JSON.stringify(require("./package.json").name),
"process.env.VERSION": JSON.stringify(require("./package.json").version)
new ForkTsCheckerWebpackPlugin({
eslint: {
files: "./src/**/*.{ts,tsx,js,jsx}" // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`

export default webpackConfig;

HtmlWebpackPlugin is used in order to simply point out to our index.html template. With webpack.DefinePlugin we can set and access environment variables inside our app (i.e check whether we are in dev or production mode, print out the version tag)

Add npm scripts to package.json

"scripts": {
"start:dev": "webpack-cli serve --mode=development --env development --open --hot",
"build": "webpack --mode=production --env production --progress",
"lint": "eslint './src/**/*.{ts,tsx}'",
"lint:fix": "eslint './src/**/*.{ts,tsx}' --fix"

Adding Prettier

Install dependencies

yarn add prettier -Dornpm i prettier --save-dev

Configure .prettierrc

"printWidth": 100,
"trailingComma": "none",
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"bracketSpacing": false,
"jsxBracketSameLine": false,
"arrowParens": "always",
"endOfLine": "auto",
"jsxSingleQuote": false,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"useTabs": false,
"htmlWhitespaceSensitivity": "css"

Also, I recommend setting up Prettier to run on each save. See:

Adding ESLint

Install dependencies

yarn add eslint eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-prettier eslint-config-prettier eslint-plugin-import -Dornpm i eslint eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-prettier eslint-config-prettier eslint-plugin-import --save-dev

Create .eslintrc.json file in your project’s root directory

"parser": "@typescript-eslint/parser",
"plugins": [
"env": {
"browser": true
"extends": [
"parserOptions": {
"project": [
"ecmaVersion": 2020,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-unused-vars": "off",
"react/jsx-filename-extension": [
"extensions": [
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
"settings": {
"react": {
"version": "detect"

Create .eslintignore file and add webpack config file to it


And voilà — we are ready to go. Start your app with start:dev script.




Lead Developer @TDSOFT

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Angular Notes (for beginners)

How to use a ‘for loop’ to divide an array into subarrays dynamically ?

Implementing Facebook, Google and Email Authentication in NodeJS

Is It Necessary to Use Semicolons in JavaScript?

How to make side income with Javascript

Underestimating the Power of the Event Object

ApiBlaze: UI-Interactions for Searching APIs

Javascript ES6 and coding style

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adrian Celczyński

Adrian Celczyński

Lead Developer @TDSOFT

More from Medium

Build and Package an NPM Component with esbuild, React and TypeScript

ESBuild, React and Typescript

Redux With Typescript Example

ESLint + Prettier + Typescript and React in 2022

A Vue Developer’s Guide to Redux