Getting Started with React TypeScript and Webpack

February 01, 2019

7 minute read

Here’s my take on a starter project using React, TypeScript and Webpack.

Getting Started

This will be a tutorial on getting a very bare-boned project up and running using React, TypeScript and Webpack. Alternatively you can skip directly to the source, available on my GitHub (complete with instructions) on getting the project up and running.

Setting up the project

  • Create a folder for your project.

    mkdir your-folder-name && cd your-folder-name && npm init --yes
  • Install React and React-DOM as dependencies of the project.

    npm install react && npm install react-dom
  • Under our devDependencies we need TypeScript.

    npm install typescript --save-dev
  • Along with the Typings for React and React-DOM.

    npm install @types/react --save-dev && npm install @types/react-dom --save-dev
  • Next we can initialize our TypeScript project. You should see a tsconfig.json file being created.

    tsc --init
  • Open tsconfig.json, adding an include array after compilerOptions. This will tell TypeScript where to look for our code.

    {
        "compilerOptions": {
        },
        "include":[ 
            "./src/**/*"
        ]
    }
  • Now create a src folder, and inside create an App.ts file.

    export class App
    {
        constructor()
        {
            console.log("Hello app!");
        }
    }
  • Test TypeScript is compiling by running tsc in the terminal. If successful, you should see an App.js file output to the src folder. Once it does, go ahead and delete the .js file once it appears.

Getting TypeScript and React working together

Now we have TypeScript compiling we can look at getting it to work with React files too.

  • In our tsconfig.json file, update yours to match the below.

    {
        "compilerOptions": {
            "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
            "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
            "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
            "sourceMap": true, /* Generates corresponding '.map' file. */
            "outDir": "./dist/", /* Redirect output structure to the directory. */
            "removeComments": true, /* Do not emit comments to output. */
            "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
            "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
            "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
            "preserveConstEnums": true
        },
        "include": [
            "./src/**/*"
        ]
    }
  • To test TypeScript will now pick up React files, we’ll add a new file to our src folder called Main.tsx.

        import * as React from 'react';
        import { App } from './App';
    
        export interface IMainProps
        {
            app: App;
        }
    
        export class Main extends React.Component<IMainProps, {}>
        {
            public render(): JSX.Element
            {
                return (
                    <>
                        <h1>Hello main</h1>
                    </>
                );
            }
        }
  • Run tsc in your terminal, and you should now see a dist folder appear with a Main.js file, which means TypeScript is now also picking up React TypeScript files! (.tsx)

Adding Webpack to the mix

We now have TypeScript and React working together. What we need next, is for Webpack to bundle it all up and serve it in our browser.

First, we’re going to install Webpack locally, as recommended by the official Webpack documentation.

  • Run the following in your terminal

    npm install webpack --save-dev && 
    npm install webpack-cli --save-dev && 
    npm install webpack-dev-server --save-dev && 
    npm install awesome-typescript-loader --save-dev && 
    npm install html-webpack-plugin --save-dev
  • We’ve now installed Webpack with four additional devDependencies

  • Let’s go ahead and create our webpack.config.js file in the root of our project.

        const path = require('path');
        const HtmlWebPackPlugin = require('html-webpack-plugin');
    
        module.exports = {
            entry: {
                app: ['./src/App.ts'],
                vendor: ['react', 'react-dom']
            },
            output: {
                path: path.resolve(__dirname, 'dist'),
                filename: 'js/[name].bundle.js'
            },
            devtool: "source-map",
            resolve: {
                extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
            },
            module: {
                rules: [
                    {
                        test: /\.tsx?$/,
                        loader: "awesome-typescript-loader"
                    }
                ]
            },
    
            plugins: [
                new HtmlWebPackPlugin({
                    template: "./src/index.html"
                })
            ]
        };

    Things to note:

    • Our entry object contains a path to App.ts file we made earlier.
    • It also includes a vendor array, React and React-Dom are our only libraries, so we add these here. If you want to add additional libraries, you should add them to this so Webpack knows about it.
    • Our output object tells webpack where to bundle our app, which in this case is our dist folder.
    • Under module we’ve added our awesome-type-script-loader.
    • Under our plugin array, we’ve added our source index.html file using the HtmlWebPackPlugin. A minified html file will get placed in our dist folder along with the reference to our bundled up js files.
  • Next, create a new index.html file and add it to our src folder. Make sure there is <div id="app"></div> in yours. This is where our React app will look to render to.

        <!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>App</title>
        </head>
    
        <body>
            <div id="app"></div>
        </body>
    
        </html>
  • Open App.ts and add to the very bottom of the file new App();

    export class App
    {
        constructor()
        {
            console.log("Hello app!");
        }
    }
    
    new App();
  • Now in the root folder of the project, run in the terminal

    node_modules/.bin/webpack-dev-server  --mode development
  • You should now have a successful build, with a webserver at http://localhost:8080/.
  • Inspecting the dev console (F12 > console), you should also see our log in the console outputting “Hello app!”

Making it more React

Now that we have React, TypeScript and Webpack all playing nicely, let’s actually get some React rendering.

  • Create a Main.tsx file and paste in the below.

        import * as React from 'react';
        import { App } from './App';
    
        export interface IMainProps
        {
            app: App; // Reference to our App.ts class
        }
    
        export class Main extends React.Component<IMainProps, {}>
        {
            constructor(props: IMainProps)
            {
                super(props);
            }
    
            public render(): JSX.Element
            {
                return (
                    <>
                        Main app
                    </>
                );
            }
        }
  • Open App.ts file and paste in the below.

        import * as ReactDOM from 'react-dom';
        import * as React from 'react';
        import { Main } from './Main';
    
        export class App
        {
            constructor()
            {
                this.render();
            }
    
            private render(): void
            {
                ReactDOM.render(React.createElement(Main, { app: this }), document.getElementById("app"));
            }
        }
    
        new App();

    Things to note here:

    • We’re rendering our Main.tsx class as our main React UI.
    • We’re passing in a reference to our App class as a react prop. There might be stuff we want to do or access in our App class at a later date.
    • We’re passing in our app id element we added to our index.html file earlier. This will be where React will render.
  • Now if we go back to our browser, we should see “Main app” on our page. Your browser should have auto-reloaded since we changed some code. React has now landed on our webpage.

Tidying up and publishing

Typing in ./node_modules/.bin/webpack-dev-server --mode development just to run the dev server everytime isn’t great. We can change this into a more friendly node command.

Open up our package.json file and update the scripts object so it looks like below:

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

We can now run our above commands in the terminal:

  • Running npm run dev is now doing what we were typing earlier: ./node_modules/.bin/webpack-dev-server --mode development
  • Running npm run build will tell webpack to compile our app for production. It will essentially minify everything and bundle it into our dist folder, ready to upload to the web.

Source code

And that’s it! You now have TypeScript, React and Webpack playing nice.

As mentioned at the start, you can find the source code on my GitHub. It also includes a very basic look at React components and adding them to our Main.tsx file.

Feel free to give it a star if it’s helped you out.


Grant Bartlett

Front end JavaScript lover, more specifically TypeScript and React. Give us a follow - @grant_bartlett