Setting up React, Babel, Webpack, & TypeScript Without Create-React-App👾
Tags: react, typescript, webpack, babel
Published: 2022-09-11 18:47:58

Today, we will be looking at how to integrate TypeScript into our existing, manually set-up project of React, Babel, and Webpack that has been done without the create-react-app command. 

This article is the second part of a series on how to set up a front-end environment. Of course, this article will have a quick, and brief set-up guide. If you would like a more in-depth guide on how to create a project without create-react-app, visit the previous article [here](https://dev.to/rinconcamilo/setting-up-react-babel-webpack-without-create-react-app-2a1f).

**<u>Versions Being Used:</u>**
- React 18
- Babel 7
- Webpack 5
- TypeScript 4
<br />

# Quick Set-Up
In order to quickly initialize the project, run the following commands:

a. Create package.json file
```powershell
npm init -y
```
b. Install React, Babel, Webpack, and other needed packages
```powershell
npm install --save-dev --save-exact react react-dom @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader file-loader
```
c. Make sure to create a file called `.babelrc` and paste the following code:
 ```json
{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ]
  ]
}
```
d. Finally, at the root of the project, create a webpack.config.js file and write the following:
```javascript
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  mode: "development",
  output: {
    filename: "bundle.[fullhash].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
    }),
  ],
  resolve: {
    modules: [__dirname, "src", "node_modules"],
    extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        exclude: /node_modules/,
        use: ["file-loader"]
      }, 
    ],
  },
};
```
e. Create a folder called "src" with the following files:
- App.js
```javascript
const App = () => (
  <div>
    <h1>Hello, World!</h1>
  </div>
);

export default App;
```
- index.js
```javascript
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const rootElement = document.querySelector('#root');
if (!rootElement) throw new Error('Failed to find the root element');
const root = createRoot(rootElement);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```
- index.html
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
```
f. Creating `start` and `build` scripts
Now, in the package.json file, add these lines to your scripts section:
```powershell
"start": "webpack serve --open",
"build": "webpack --config webpack.config.js --mode production"
```
Now that we have all of the above set-up, this quick set-up should be able to run. If you have any questions or would like to learn more on what is going on above, visit my previous article [here](https://dev.to/rinconcamilo/setting-up-react-babel-webpack-without-create-react-app-2a1f).
<br />

#Implementing TypeScript
###Background Information
Before installing and configuring TypeScript into our application, let us first understand how we plan on integrating and using both TypeScript and Babel together.

**<u>Babel:</u>** We will be utilizing Babel for transpiling our code only. Furthermore, since we are using Babel 7 we do not need to install the `ts-loader` since Babel 7 understands TypeScript with the `babel-loader`; and the additional plugins & preset we will install and set in the `.babelrc` will add the remaining functionality.

**<u>TypeScript:</u>** We will be utilizing TypeScript for type-checking only! 

Having these two technologies focus on one task we are able to clearly define the different roles each will accomplish. Making the configuration side of things more maintainable. This means that we will have to type-check then transpile the code.

###1. Installing TypeScript
In order to install TypeScript, we have to install the following packages:
```powershell
npm install --save-dev --save-exact typescript @types/react @types/react-dom @babel/preset-typescript
```
- [typescript](https://www.npmjs.com/package/typescript)
    - Adds optional types to JavaScript.
- [@types/react](https://www.npmjs.com/package/@types/react)
    - Type definitions for react.
- [@types/react-dom](https://www.npmjs.com/package/@types/react-dom)
    - Type definitions for react-dom.
- [@babel/preset-typescript](https://babeljs.io/docs/en/babel-preset-typescript#with-a-configuration-file-recommended)
    - Allows Babel to understand typescript.
Once we have these packages installed, we need to begin modifying our configurations and file names.
<br />

###2. Modifying Webpack.config.js
We need to make some modifications to the Webpack configuration file. The first modification is pointing the `entry` path to a `.tsx` file like so:
```javascript
entry: "./src/index.js",
```
to
```javascript
entry: "./src/index.tsx",
```
Then, we need change the rule using the `babel-loader` under `module` to:
```javascript
      {
        test: /\.(js|ts)x?$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
```
This change is to help webpack resolve:
- plain JavaScript - `js`
- JavaScript with React enabled - `jsx`
- TypeScript with JavaScript - `ts`
- TypeScript with React enabled - `tsx`

The final `webpack.config.js` should look like the following:
```javascript
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.tsx",
  mode: "development",
  output: {
    filename: "bundle.[fullhash].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
    }),
  ],
  resolve: {
    modules: [__dirname, "src", "node_modules"],
    extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
  },
  module: {
    rules: [
      {
        test: /\.(js|ts)x?$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        exclude: /node_modules/,
        use: ["file-loader"]
      }, 
    ],
  },
};
```

###3. Changing File Names
Time to change all the file extensions from `.js` to `.tsx`. This would be two of the following files:
- App.tsx
- index.tsx

With these file names changed, we can now move on to configure TypeScript.
<br />

###4. Configuring TypeScript
In order to configure TypeScript, we need to create a `tsconfig.json` file at the root of our project.

**<u>Background Information:</u>** Within this file, we can implement different rules to run at compile time. You can learn more about tsconfig.json [here](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

Some of the basic fields are called the "Root Fields":
- [Files](https://www.typescriptlang.org/tsconfig#files)
    - List the files to include in the program. An error will occur if any of the listed files are not found.
- [Extends](https://www.typescriptlang.org/tsconfig#extends)
    - A string that contains a path to another configuration file to inherit.
- [Include](https://www.typescriptlang.org/tsconfig#include)
    - Will specify an array of filenames or patterns that will be included within the program.
- [Exclude](https://www.typescriptlang.org/tsconfig#exclude)
    - Will specify an array of filenames or patterns to exclude from the program.
- [References](https://www.typescriptlang.org/docs/handbook/project-references.html)
    - A way to structure TypeScript programs into smaller pieces. This will help improve the following: build, editor interaction times, enforce logical separation, etc.

**<u>Setting Up tsconfig.json:</u>** Since we are only using TypeScript as a type-checker, we make sure the following configurations are set in order for both Babel to work properly:
```json
{
  "compilerOptions": {
    // Emit Configuration
    "noEmit": true,

    // Modules Configuration
    "module": "ES2022",

    // Language and Environment Configuration
    "target": "ES2022",
    "jsx": "react-jsx",

    // Interop Constraints Configuration
    "esModuleInterop": true,
  }
...
}
```
**<u>Explanation:</u>**
- `noEmit: true`
    - Is set to true because we do not want to emit any files since Babel will be in charge of transpiling our code.
- `module: ES2022` and `target: ES2022` 
    - We are are not transpiling our code using TypeScript. This means that we do not need to worry about browser compatibility in this area of configuration.
- `esModuleInterop: true` 
    - Is set in order to have default import in TypeScript since this is allowed within Babel.
- `jsx: react-jsx`
    - Will allow for React's JSX transform.

Here is my `tsconfig.json` that I use, if you have any suggestions please drop a comment!
```json
{
  "compilerOptions": {
    // Emit Configuration
    "noEmit": true,

    // Type Checking Configuration
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitThis": true,
    "noPropertyAccessFromIndexSignature": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitOverride": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    // Strict Rules - v4.8
    "alwaysStrict": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "useUnknownInCatchVariables": true,
    
    // Modules Configuration
    "baseUrl": "./",
    "module": "ES2022",
    "moduleResolution": "node",
    
    // Language and Environment Configuration
    "target": "ES2022",
    "jsx": "react-jsx",

    // JavaScript Support Configuration
    "allowJs": true,
    "checkJs": true,

    // Interop Constraints Configuration
    "esModuleInterop": true,
    "isolatedModules": true
  },
  "include": ["src/**/**/*"],
  "exclude": ["node_modules"]
}
```
Here are some explanation over a few configurations:
- [compilerOptions](https://www.typescriptlang.org/tsconfig#compilerOptions)
    - Covers how the language should work.
    - If upgrading TypeScript, the `strict` rule will add any additional rules automatically. For personal reasons, I like to keep the "magic" of things happening automatically to a minimum which is why I excluded from using the `strict: true`.
- [outDir](https://www.typescriptlang.org/tsconfig#outDir)
    - Where the compiler will emit compiled JavaScript files.
    - Since we are using TypeScript as just a type-checker we will not emit any files, hence the `noEmit: true`.
- [module](https://www.typescriptlang.org/tsconfig#module)
    - Defines output module resolution system that will be used. This is based on what your JavaScript engine is capable of parsing.
- [target](https://www.typescriptlang.org/tsconfig#target)
    - Changes which JavaScript features are down-leveled and which are left intact.

You can find a complete list of all configurations for tsconfig.json [here](https://www.typescriptlang.org/tsconfig).
<br />

###5. Configuring TypeScript with Babel
In order to configure TypeScript with Babel, we have to go to the `.babelrc` file and make sure it contains the following:
```json
{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ],
    "@babel/preset-typescript"
  ]
}
```
<br />
###6. Run Type Checking
Now in the package.json file, add this line to your scripts section:
```json
"tscheck": "tsc"
```
This will type check all of the files that were selected in the tsconfig.json file.
<br />

View everything together in [Github](https://github.com/RinconCamilo/Setting-React-Webpack-TypeScript).

If you found this helpful or just enjoyed reading the article, consider grabbing me a [cup of coffee](buymeacoffee.com/rinconcami9).