DEV Community

Renato Rocha
Renato Rocha

Posted on • Updated on

Setup a React.JS Project with TypeScript, ESLint and Prettier without create-react-app

When we initializing the study of react and searching by a tutorial in many cases the create-react-app is used to create de application. However, some people cite some negatives in this approach like: hard configuration, maintainability and soon.

So in this post we will desmonstrates how to setup a React project without the create-react-app.

For this task we need install and configure: a JavaScript compiler (transpiler) to convert our source code in a way that the browser understand; a model bundler to loading and compile modules to a single file.

JavaScript compiler (babel)

We use Babel is a to convert new JavaScript code into compatible version that the browsers can understand. As an alternative we can use sucrase.

Plugins and presets

All transformations that Babel apply are informed to it through plugins and an array of plugins can be informed as a preset.

Install Babel, plugins and presets


mkdir your_project_folder && cd your_project_folder

yarn init -y

yarn add @babel/core @babel/cli @babel/preset-env
@babel/preset-react @babel/plugin-transform-typescript -D

yarn add @babel/polyfill core-js

Now at root of project, create the file babel.config.js with the content:

module.exports = {
  presets: ["@babel/preset-env", "@babel/preset-react"],
  plugins: ["@babel/plugin-transform-typescript"]
};

Model bundler (webpack)

Webpack is a module bundler for JavaScript applications. Webpack will mapping all modules dependencies creating a bundle file.

Install webpack

yarn add webpack webpack-cli -D

Now we need create a file called webpack.config.js at root project. Inside that file we will see some configurations:

  • resolve: help to find models that are required by the application.
  • devServer: use to configure the webpack-dev-server
  • entry: says to webpack what is the entry point.
  • module.rules: an array of rules that determine the loader to each file.

Install loaders and dev sever

yarn add babel-loader style-loader css-loader file-loader source-map-loader ts-loader webpack-dev-server eslint-loader -D

Put in the webpack.config.js file the content:

const path = require("path");

module.exports = {
  resolve: {
    extensions: [".tsx", ".ts", ".js"]
  },
  devServer: {
    contentBase: path.join(__dirname, "public"),
    compress: true,
    port: 3000
  },
  entry: path.resolve(__dirname, "src", "index.tsx"),
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: ["babel-loader", "eslint-loader"]
      },
      {
        test: /\.ts(x?)$/,
        exclude: /node_modules/,
        use: [{ loader: "ts-loader" }, { loader: "eslint-loader" }]
      },
      {
        test: /\.css$/,
        use: [{ loader: "style-loader" }, { loader: "css-loader" }]
      },
      {
        test: /\.(png|svg|jpg|gif)$/i,
        use: ["file-loader"]
      },
      {
        enforce: "pre",
        test: /\.js$/,
        loader: "source-map-loader"
      }
    ]
  }
};

ESLint, Prettier and TypeScript

For that install and configuration we can use How to setup a React.JS Project with typcript, ESLint and Prettier

The .eslintrc.json, .prettierrc, tsconfig.json, custom.d.ts are:

.eslintrc.json

{
  "env": {
    "browser": true,
    "es6": true
  },
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly"
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "plugins": ["react", "@typescript-eslint", "prettier"],
  "extends": [
    "plugin:react/recommended",
    "airbnb",
    "plugin:prettier/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "react/prop-types": "off",
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never"
      }
    ],
    "import/prefer-default-export": "off",
    "prettier/prettier": "error",
    "@typescript-eslint/explicit-function-return-type": "off",
    "@typescript-eslint/no-unused-vars": "off",
    "@typescript-eslint/no-var-requires": "off",
    "react/jsx-filename-extension": [
      1,
      { "extensions": [".js", ".jsx", ".ts", ".tsx"] }
    ]
  },
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  }
}
.prettierrc

{
  "singleQuote": true,
  "trailingComma": "es5"
}
tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "rootDir": "src",
    "outDir": "public",
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src", "custom.d.ts"]
}
custom.d.ts;

declare module "*.svg" {
  import React = require("react");
  export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
  const src: string;
  export default src;
}

declare module "*.png" {
  const src: string;
  export default src;
}

The finally packages to install are:

yarn add react react-dom

The project structure is:

To complete we need create:

  • public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <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>ReactJS</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="./bundle.js"></script>
  </body>
</html>
  • src/index.tsx
import React from "react";
import { render } from "react-dom";

import Index from "./pages";

render(<Index />, document.getElementById("root"));
  • src/pages/index.tsx
import React from "react";

export default function src() {
  return (
    <div className="container">
      <h1>Hello World!</h1>
    </div>
  );
}

Now add in package.json:

"scripts": {
    "build": "webpack --mode production",
    "dev": "webpack-dev-server --mode development"
  }

And at root folder run:

yarn dev

source code

Top comments (4)

Collapse
 
erikgmatos profile image
Erik Garces Matos • Edited

Bom dia Renato, ótimo post parabéns, só não consegui fazer funcionar o plugin babel-plugin-root-import, sabe se ele funciona com typescript? eu fiz as configs no arquivo babelrc e eslintrc e ele acha as pastas porem quandodo coloco o nome da imagem(image.svg ou image.png) ele fica dando erro...
module "*.png"
Unable to resolve path to module '~/assets/png/1.icone.png'

se eu coloco o caminho relativo comum('../assets/png/1.icone.png') funciona....sabe o q pode ser?

Collapse
 
renatobentorocha profile image
Renato Rocha

Hi Erik, tanks by comments!

To that with React.JS we need use: customize-cra and react-app-rewired. I already did it, but I not wrote a post about it. So I found this article that could help you whit it.

This is my repo with this config.

In TypeScript I believe we config the tsconfig.json with:

   "baseUrl": "./src",
    "paths": {
      "~/*": ["*"] // resolve any `~/foo/bar` to `<baseUrl>/foo/bar`
    }

Obs: My repo and the article not use TypeScript.

Best regard

Collapse
 
jerryasher profile image
Jerry Asher

I believe

Put in the babel.config.js file the content:

should be

Put in the webpack.config.js file the content:

Collapse
 
renatobentorocha profile image
Renato Rocha

Hi Jerry, thanks for watching. I fixed that.