Geek Culture
Published in

Geek Culture

Create a React project from scratch, with TypeScript and Webpack

A step by step guide on how to create a React project from scratch, with TypeScript and Webpack.

You can find the full source code here: https://github.com/alexadam/project-templates/tree/master/projects/react-app

Setup

Prerequisites:

  • node
  • yarn

Create the project’s folder:

mkdir react-app 
cd react-app

Generate a default package.json file with yarn:

yarn init -y

Install React, TypeScript and Webpack:

yarn add react react-dom

yarn add --dev @types/react \
@types/react-dom \
awesome-typescript-loader \
css-loader \
html-webpack-plugin \
node-sass \
sass-loader \
style-loader \
typescript \
webpack \
webpack-cli \
webpack-dev-server

Add build, dev & clean scripts in the package.json file:

....
},
"scripts": {
"clean": "rm -rf dist/*",
"build": "webpack",
"dev": "webpack serve"
}

Configure TypeScript by creating the file tsconfig.json with:

{
"compilerOptions": {
"incremental": true,
"target": "es5",
"module": "commonjs",
"lib": ["dom", "dom.iterable", "es6"],
"allowJs": true,
"jsx": "react",
"sourceMap": true,
"outDir": "./dist/",
"rootDir": ".",
"removeComments": true,
"strict": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true
},
"include": [
"client"
],
"exclude": [
"node_modules",
"build",
"dist"
]
}

To configure Webpack, make a file webpack.config.js and paste:

const path = require("path");

const app_dir = __dirname + '/client';

const HtmlWebpackPlugin = require('html-webpack-plugin');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: app_dir + '/index.html',
filename: 'index.html',
inject: 'body'
});

const config = {
mode: 'development',
entry: app_dir + '/app.tsx',
output: {
path: __dirname + '/dist',
filename: 'app.js',
publicPath: '/'
},
module: {
rules: [{
test: /\.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}, {
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
exclude: /(node_modules|bower_components)/
},
{
test: /\.(woff|woff2|ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
exclude: [/node_modules/],
loader: "file-loader"
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
exclude: [/node_modules/],
loader: "file-loader"
},
{
test: /\.(pdf)$/i,
exclude: [/node_modules/],
loader: "file-loader",
options: {
name: '[name].[ext]',
},
},
]
},
plugins: [HTMLWebpackPluginConfig],
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"]
},
optimization: {
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false,
},
devServer: {
port: 8080,
// open: true,
hot: true,
inline: true,
historyApiFallback: true,
},
};
module.exports = config;

Example App

Create a folder named client (in the project’s folder):

mkdir client
cd client

Make a simple React component, in the file numbers.tsx:

import React, {useState} from 'react';

interface INumberProps {
initValue: number
}

const Numbers = (props: INumberProps) => {
const [value, setValue] = useState(props.initValue)

const onIncrement = () => {
setValue(value + 1)
}

const onDecrement = () => {
setValue(value - 1)
}

return (
<div>
Number is {value}
<div>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
</div>
)
}
export default Numbers

Create the main React component (the entry point), in the file app.tsx:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Numbers from './numbers';
ReactDOM.render(
<Numbers initValue={42} />,
document.getElementById('app') as HTMLElement
);

Next, add the index.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React TypeScript</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

Then, run yarn dev and open http://localhost:8080/ in a browser.

Use this project as a template

You can save the Setup steps as a shell script:

#!/bin/sh

rm -rf node_modules
rm package.json

yarn init --yes

yarn add react react-dom

yarn add --dev @types/react \
@types/react-dom \
awesome-typescript-loader \
css-loader \
html-webpack-plugin \
node-sass \
sass-loader \
style-loader \
typescript \
webpack \
webpack-cli \
webpack-dev-server

# Remove the last line
sed -i.bak '$ d' package.json && rm package.json.bak

# append the scripts commads
cat <<EOT >> package.json
,"scripts": {
"clean": "rm -rf dist/*",
"build": "webpack",
"dev": "webpack serve"
}
}

Delete the node-modules folder and, when you want to start a new project, you can copy the contents of react-app to the new location:

mkdir new-project
cd new-project

# copy the react-app folder content to the new project
rsync -rtv /path/to/../react-app/ .

./init.sh

Originally published at https://alexadam.dev.

--

--

--

A new tech publication by Start it up (https://medium.com/swlh).

Recommended from Medium

Integrate CATF Time with Lighthouse Audit

Image source: Walmart.com The first screen a user visits on a website is called “Content Above The Fold”. The content that a user sees after scrolling down the page is referred to as “Content Below the Fold”.

How to build the static blog with Content layer, markdown, and nextjs?

Create a static blog with a Content layer, markdown, and next.

React’s TicTacToe tutorial, in Kotlin/JavaFX

Testing NodeJS code with Jest

Clean Architecture — Mapping and Displaying Server-Side Errors With Formik in React Client App

Why React Native?

7 Mistakes That Keep You Behind

Reference VS. Primitive Values

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
alex adam

alex adam

https://alexadam.dev/

More from Medium

[Nextjs Tip] How to resize image URL dynamically with next/image component

All About Rendering: Client and Server

Creating a Textarea with dynamic height using React and Typescript

Next.js Passwordless Email Authentication with NextAuth & MongoDB