webpack + TypeScript + React: Part 2

John Tucker
codeburst
Published in
4 min readFeb 21, 2018

--

Having built our “hello world” TypeScript web application, we introduce third-party libraries (in particular React).

This article is part of a series starting with webpack + TypeScript + React: Part 1. All of the examples are also available for download.

Source Map

As we likely want to be able to use the browser’s development tools to debug our TypeScript, we can include a source map. Starting from the previous example we update:

source-map/tsconfig.json

{
"compilerOptions": {
"noImplicitAny": true,
"sourceMap": true,
"target": "es5"
}
}

source-map/webpack.config.js

...  
devtool: 'source-map',
module: {
rules: [
...

Now running the following will generate a main.bundle.js.map in the dist folder:

./node_modules/.bin/webpack

React

Let us now refactor our previous example into a React application.

npm install react
npm install react-dom
npm install @types/react
npm install @types/react-dom

Observations:

  • First, you can shorten the previous command into a single line as npm can accept multiple package names; broke apart in this article for clarity
  • Installing versioned third-party declaration files is preferable compared to the current state of affairs with Flow; where you have to check-in the third-party library definitions into your repository.
  • Not exactly sure why, but the react-dom declaration package depended on the node one (no big deal, but odd).

Next we need to update:

react/tsconfig.json

{
"compilerOptions": {
"jsx": "react",
"noImplicitAny": true,
"sourceMap": true,
"target": "es5"
}
}

Next we update:

webpack.config.js

const path = require('path');module.exports = {
entry: './src/index.tsx',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
devtool: 'source-map',
resolve: {
extensions: ['.js', '.json', '.ts', '.tsx'],
},

module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: 'awesome-typescript-loader',
},
],
},
};

Observations:

  • The official TypeScript React & webpack tutorial includes source-map-loader; did not use in this example as it was not clear that it was necessary (confirmed that the source maps were properly generated with this configuration).
  • Their tutorial also uses the webpack externals option using the argument of keeping the vendor code out of the main bundle for download and caching performance reasons. Given a proper bundle splitting webpack configuration is is a non issue (this simple example, however, outputs a monolithic bundle).

We add a root div to:

react/public/index.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>webpack TypeScript Patterns</title>
</head>
<body>
<div id="root"></div>
<script src="main.bundle.js"></script>
</body>
</html>

We replace the index.ts file with an index.tsx and include App.tsx:

react/src/index.tsx

import * as React from 'react';
import { render } from 'react-dom';
import App from './components/App';
render(
<App message="World" />,
document.getElementById('root'),
);

react/src/components/App.tsx

import * as React from 'react';interface AppProps {
message: string,
};
export default function({ message }: AppProps ) {
return <h1>Hello {message}</h1>;
};

note: Apparently the use of import * as React from ‘react’; instead of the more common import React from ‘react’; is due to a difference in opinion between TypeScript and Babel on handling CommonJS modules.

As I am using an editor that supports TypeScript out of the box (the no-cost Visual Studio Code), I get some immediate benefits from using TypeScript. As we have included the type declarations for the third-party libraries, we get code completion.

Another interesting pattern with TypeScript is to not use the React component’s propTypes property to enforce proper component usage (at run-time). Instead, we use TypeScript for this purpose (the interface AppProps). The big benefit of this is that we get these as compile-time errors. Say we forget to provide the message property for the App component:

note: With Visual Studio Code we also see this same error while editing the file.

To build and run we, as before, copy of the index.html file an run webpack.

cp public/index.html dist
./node_modules/.bin/webpack

We can then open index.html in a browser to see the resulting web application.

Next Steps

In the next article, webpack + TypeScript + React: Part 3, we explore our linting options.

--

--