Table of contents:
- npm setup
- Installing environment with npm
- React app and component files
- Webpack configuration
- Development test
- Production build
There really is a simple way to create a working react app inside your existing project using Webpack.
We will create React app from scratch, without "create-react-app" template. For this task we need Webpack, a popular module bundler which will help to bundle our project files.
Let's make a new project and call it "webpackapp". Create a webpackapp folder:
mkdir webpackapp && cd webpackapp
npm setup
First of all, we need to install modules we want in our project. We will do this with npm. What is npm? It's a CLI (command-line interface) tool for publishing and downloading packages.
Add a file package.json (npm configuration file) in our project folder:
{
"name": "webpackapp",
"description": "A React.js project using Webpack",
"version": "1.0.0",
"author": "techapple.ru",
"scripts": {
"dev": "webpack-dev-server --hot --open",
"build": "webpack",
"build:dev": "webpack --mode=development"
},
"dependencies": {
"css-loader": "^5.0.1",
"file-loader": "^6.2.0",
"react": "^16.14.0",
"react-dom": "^16.5.0",
"style-loader": "^2.0.0"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.0",
"html-webpack-plugin": "^4.5.0",
"node-sass": "^4.14.1",
"sass-loader": "^10.1.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9"
}
}
Dependencies section contains react and react-dom fields. These are modules containing core functions for React.js library, we need them for our app to work.
devDependencies section defines modules we need in our development mode.
- @babel - compiler for jsx and js files
- @babel/core - main compiler module
- babel/loader and @babel/reset-react are used for loading react files into compiler
- @babel/preset-env is used for ES2015+ standard support
- @babel/plugin-proposal-class-properties ??
As we use Webpack, at the end we add webpack module. To simplify development we need another module - webpack-dev-server. It will create dynamic web-server with hot reload (you won't need to hit refresh every time).
Besides that, we defined two commands in the scripts section: dev and build.
Command dev is used for development purposes and it let you generate bundle file on the fly and launch the project in a browser. We pass 2 parameters: --hot --open. Parameter --hot allows to enable Hot Module Replacement, it will re-render on component changes. Second parameter --open will launch default browser with our app (on "localhost" domain).
Command build will generate production bundle (bundle.js).
Full and detailed info about package.json you can find here.
Installing environment with npm
Now we tell npm to install all needed modules we defined in package.json:
npm install
When npm will finish install we can create some React project files.
Note that if you want to install some other module with a command, like for example, npm install bootstrap, npm will add dependencies in package.json itself. You don't need to modify package.json, it's that easy.
React app and component files
Add index.html file to the webpackapp folder:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack && React</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
We do not set script bundle.js, because html-webpack-plugin will do it for us later.
Time to add our app and component files. Create a folder named app, in which we will store our application files.
Create a subfolder components in app folder. Add new file SearchPlugin.jsx:
import React from 'react';
export default class SearchPlugin extends React.Component{
constructor(props){
super(props);
this.onTextChanged = this.onTextChanged.bind(this);
}
onTextChanged(e){
var text = e.target.value.trim(); // удаляем пробелы
this.props.filter(text); // передаем введенный текст в родительский компонент
}
render() {
return <input placeholder="Search" onChange={this.onTextChanged} />;
}
}
And also in catalog "app/components" we add component ItemsList.jsx:
import React from 'react';
import SearchPlugin from './SearchPlugin.jsx';
export default class ItemsList extends React.Component {
constructor(props){
super(props);
this.state = { items: this.props.data.items};
this.filterList = this.filterList.bind(this);
}
filterList(text){
var filteredList = this.props.data.items.filter(function(item){
return item.toLowerCase().search(text.toLowerCase())!== -1;
});
this.setState({items: filteredList});
}
render() {
return(
<div>
<h2>{this.props.data.title}</h2>
<SearchPlugin filter={this.filterList} />
<ul>
{
this.state.items.map(function(item){
return <li key={item}>{item}</li>
})
}
</ul>
</div>);
}
}
In the first line we are importing React module, which contains React.Class. We need it for creating our components.
import React from 'react';
And we need first component - SearchPlugin which is defined in another file, so we import it also.
import SearchPlugin from './SearchPlugin.jsx';
The only difference between these two lines is in that react is installed as external module, so we pass only its name. Our component SearchPlugin is defined by us and we use a relative path (./ path means the file is located in the same folder).
Then in webpackapp folder we create our main project file app.jsx:
import ReactDOM from 'react-dom';
import React from 'react';
import ItemsList from './components/ItemsList.jsx';
const propsValues = {
title: "Phones list",
items: [
"HTC U Ultra",
"iPhone 7",
"Google Pixel",
"Huawei P9",
"Meizu Pro 6",
"Asus Zenfone 3"
]
};
ReactDOM.render(
<ItemsList data={propsValues} />,
document.getElementById("app")
)
This React file will actually load our components on a web page.
Finally, Webpack configuration
Add webpack.config.js to the webpackapp folder:
const HtmlWebPackPlugin = require( 'html-webpack-plugin' );
const path = require( 'path' );
module.exports = {
entry: "./app.jsx", // entry point, our main app file
output:{
path: path.resolve(__dirname, './public'), // path for our output files
filename: "bundle.js" // bundle filename
},
module:{
rules:[ // jsx loader
{
test: /\.(js|jsx)$/, // determine file type
exclude: /(node_modules)/, // exclude node_modules folder
loader: "babel-loader", // determine loader
options:{
presets:["@babel/preset-env", "@babel/preset-react"], // used plugins
plugins: [
[
"@babel/plugin-proposal-class-properties"
]
]
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'] // scss loaders
},
{
test: /\.(png|j?g|svg|gif)?$/,
use: 'file-loader' // static files loader
}
]
},
plugins: [
new HtmlWebPackPlugin({ // html file generating for our setup
template: path.resolve( __dirname, 'index.html' ), // path to the template file
filename: 'index.html' // generated filename
})
]
}
In Entry section "./app/app.jsx" we define the main app file.
Ouput section defines configuration for output file, its folder and name - public/bundle.js. This will be our final bundle file.
Module section defines a set of loaders, which will apply to different files (babel for jsx, file-loader for static files etc).
More about Webpack
Finally, the project structure will look like this:

Development test
Run this command for development build:
npm run dev
As a result the app will launch in a browser:

On this step you can easily debug your app, because React dev js files have a detailed information about errors in your code (of course, if you have some).
Production build
Now we can generate our final bundle.js with this command:
npm run build
It will create 2 files: index.html and bundle.js. You can put index.html directly to your browser and see the result. The final folder structure will be:

So, we built a bundle.js file, that we can use anywhere, include it in existing project for example. But don't forget to use appropriate container id in your template file (for our example app):
<div id="app"></div>
Thats it, in the next article I will explain how to create separate bundles for a project.