In the root of the ASP.NET Core web project, create the following folder structure:
ClientApp/ src/ index.js components/
We use the ClientApp folder and structure to follow common naming conventions.
Open a new command prompt window and navigate to the ClientApp folder.
The package.json file is used in Nodejs projects to store general information about the project (like its name, version, etc) and track what dependencies the project needs (so that anyone can install them all at once).
To create a “default” package.json file, type the “npm init” command with the y option:
npm init -y
The “-y” option uses default options.
Once the npm init
command is done, you should have a package.json
file under your project directory (and nothing else, yet).
The package.json
file can now be used to "document" any dependencies you add to your project. This happens automatically when you npm install
anything.
If the command was successful, it should have created a package.json file with contents similar to this:
{ "name": "demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Since you’ll be writing your code in multiple modules (files) and it will depend on other modules (like React), you need a module bundler to translate all these modules into something that can work in all browsers today. You can use Webpack for that job.
To install the packages you need for Webpack (which is also a “module”), type the following command:
npm i -D webpack webpack-cli
If the command ran successfully, it should have created a new folder named “node_modules” in your project folder and downloaded several modules into this folder (into various folders), of course including the Webpack package as well.
Instead of a run-time dependency, the “ — save-dev” option adds a “dev dependency” to the package.json file. This indicates that the Webpack package is only useful during development. That would make sense, as once we have created the “bundles” as we require, we would use them directly in production. The package.json file should look similar to this:
{
// ...
},
"devDependncies": {
"webpack": "^5.69.1",
"webpack-cli": "^4.9.2"
}
}
Official website: webpack bundle your styles
Babel is a transpiler. The transpiler transforms ES6 code to use ES5 syntax that older browsers can understand. While Babel itself is very feature-rich and can be used independently, for our purposes, we can use the corresponding babel “loaders” to do the job.
Webpack is just a generic module bundler. You need to configure it with loaders to transform code from one state into the other.
Before we can use any loaders, we need first to install them. For our purpose, we will have to install the relevant babel loaders. Use the following command to install the babel loaders and the “presets”.
npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react
If the command ran successfully, these loaders would be installed in the node_modules folder and the package.json would be modified.
A priceless development dependency is ESLint.
ESLint is a code quality tool and if you don’t use it, your code will not be as good as it could be.
Since Babel is part of this stack, you need to configure ESLint to parse through what Babel is going to parse through. You should also use the main recommended ESLint configurations in addition to those recommended for React projects. Here are the packages you need for that:
npm i -D eslint @babel/eslint-parser eslint-plugin-react eslint-plugin-react-hooks
Updating babel-eslint to @babel/eslint-parser for React apps | Tim Addison (tjaddison.com)
The most popular testing library that’s usually used with React is Jest. Install that if you plan to write tests for your React project (and you should!). You’ll also need babel-jest
and a test renderer like react-test-renderer
:
npm i -D jest babel-jest react-test-renderer
The frontend dependencies you need are React and ReactDOM. Install them next:
npm i -D react react-dom
Install the Babel preset to process React JSX code:
npm i -D @babel/preset-react
Install the Terser plugin
terser-webpack-plugin
webpack-contrib/terser-webpack-plugin: Terser Plugin (github.com)
To configure Webpack to bundle your application into a single bundle file, create a webpack.config.js
file under the root of the project and put the following module.exports
object in it:
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, '../wwwroot/js'),
filename: 'snippset.js'
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
}
};
Webpack has certain defaults on which JavaScript file to start with. It looks for asrc/index.js
file. It’ll also output the bundle todist/main.js
by default. If you need to change the locations of yoursrc
anddist
files, you’ll need a few more configuration entries inwebpack.config.js
.
To configure Babel to compile JSX and modern JavaScript code, create a babel.config.js
file under the root of the project and put the following module.exports
object in it:
babel.config.js
module.exports = {
presets: ['@babel/preset-react', '@babel/preset-env'],
};
These presets were already installed above. The env preset is the one Babel uses to transform modern JavaScript (and it’s configurable if you need to target just modern browsers and make the bundle smaller). The react preset is for the mighty JSX extension.
To configure ESLint, you need to add a .eslintrc.js
file in the root of the project. This file will naturally depend on your code style preferences, but definitely start it with the recommended configurations and then customize them as needed:
.eslintrc.js
module.exports = { parser: 'babel-eslint', env: { browser: true, commonjs: true, es6: true, node: true, jest: true, }, parserOptions: { ecmaVersion: 2020, ecmaFeatures: { impliedStrict: true, jsx: true, }, sourceType: 'module', }, plugins: ['react', 'react-hooks'], extends: [ 'eslint:recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', ], settings: { react: { version: 'detect', }, }, rules: { // You can do your customizations here... // For example, if you don't want to use the prop-types package, // you can turn off that recommended rule with: 'react/prop-types': ['off'] }, };
You should make your editor highlight any ESLint issues for you on save! All the major editors today have plugins to do that. You should also make your editor auto-format code for you on save as well using Prettier. Prettier works great with ESLint.
In your package.json
file you should have a scripts
section. If you generated the file with the npm init
defaults you’ll have a placeholder "test" script in there. You should change that to work with Jest.
Add more scripts in there to build the scripts with runner for Webpack.
{
// ...
"scripts": {
"build:dev": "webpack --stats verbose",
"build:prd": "webpack build --config ./webpack.config.prd.js --stats verbose",
"build:watch": "webpack --watch",
"test": "jest"
},
The --mode=development
flag is to make Webpack generate a development-friendly bundle. Run Webpack with --mode=production
in production.
The --watch
flag in the command above is to run Webpack in watch mode
webpack.config.prd.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, '../wwwroot/dist/js'),
filename: 'snippset.min.js'
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: false,
},
},
extractComments: false,
}),
],
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
}
};
Remove Comments
Resources: