React (or ReactJS, developed by Facebook) has become one of the top popular Javascript frameworks in the world of today. A lot of boilerplate projects and startup kits have been created to make setting up a React development environment easier, including Create React App (CRA for short, see https://create-react-app.dev/), Facebook’s official starter kit. A search on the web for “React starter kit” or “React boilerplates” returns quite some results. Some will set up a whole toolchain and project layout for you, others are only for specific goals or features.
There’s quite some articles around about this topic but almost all start out with CRA and they don’t go much further than setting up the most basic environment. One big disadvantage of a starter kit like CRA is it will include a lot of dependencies and packages you may not need on a specific project, causing bloat. Also on a professional project we often need more control over and customization on our environment. In case of CRA you will end up ejecting CRA (which has its own issues), having to figure out and tweak manually all the options and configurations.
So let’s set up a ReactJS development environment WITHOUT using a starter kit or boilerplate, but even if you start out with one I hope this article can be helpful and provide more insight. Also I will follow the “12 factor app” principles (https://12factor.net/) for modern DevOps and SaaS development. I use a Windows 10 Professional machine to work on, VS Code as editor, Chrome as browser and Powershell 5.1 as command line (CLI).
Getting started
I assume you have at least some understanding of how ReactJS, Javascript and other web technology work. A lot of the tools involved need node.js so we have to install that if we don’t have it already on our machine. From experience I know on a development machine you will use different node versions on different projects quite often. I recommend to install the node version manager (nvm) first, so you can easily manage and switch between node.js versions on one machine. You need to uninstall any node.js already installed first.
To install nvm using Powershell you can first install Chocolatey, a package manager for Windows that works from command prompts similar to RPM on Linux. Instructions on installing Chocolatey are on https://chocolatey.org/install.
After installing Chocolatey, close all Powershell windows and reopen one with elevated permissions. Now to install nvm:
choco install -y nvm
The -y flag automatically confirms any prompts for confirmation. Then to install a node.js version:
nvm install xx.xx.xx
with xx.xx.xx being the version, or
nvm install latest
to get the latest version of node.js. With node.js also the node.js package manager npm will be installed. After installation you need to tell your system to use a specific version:
nvm use xx.xx.xx
(NOTE: if you plan to deploy to Azure you need to match your node.js version with one supported since Azure does not support all node.js versions. To check, go to the app service in Azure you want to deploy to, then under “Development tools” choose “Advanced tools”, en click on the “Go” link. This will open Kudu in a new window, showing the environment for the App Service. Under “Rest API” click “Runtime versions” and you will see a JSON output giving the available versions for various runtimes, including node.js.)
Next install yarn. Using yarn or npm is also a matter of personal preference, but yarn has more advanced caching and concurrency and therefore is faster in most cases, which is a thing to consider in professional build environments. You can install yarn using npm but the yarn team advises to use a OS-native package manager, so we use Chocolatey again:
choco install -y yarn
You may need to close and reopen Powershell again before yarn works. Presuming you have your code editor already installed (VS Code in my case), we’re now ready to start our ReactJS project.
Creating the project
Create a root folder for our new ReactJS project, go to VS Code and open this folder. Then do “Save workspace as…” and give it a name to create a new VS Code workspace for our project. Now all we do in our project folder will be picked up by the VS Code workspace.
Next we’re going to Powershell again. From now on, unless said otherwise all Powershell commands we use will be in the project root folder we just created. So go there in Powershell and do:
yarn init -y
This will create a package.json with default values in the folder. You can always change things manually later. For now add the following line:
"engines" : { "node" : "xx.xx.xx" }
With xx.xx.xx being the used node.js version (note: for all DTAP environments it should be the same; “12-factor-app” again). You can give a range to cover for some different versions but keep that range as small as possible to avoid compatibility issues. See https://docs.npmjs.com/files/package.json#dependencies for possible options.
Now, in or project root folder, create the following folder structure:
|-build
|-public
|-src
|-components
|-images
The public
folder will be for assets that need to be copied to our app root without any processing. Everything in src
will be source code and assets. build
will be the output folder for our builds.
We can also set up Git to have a code repository. First in the root folder create a .gitignore
file, and put in here at least the /node_modules
and /build
folders, yarn.error.log
and any other folders or files that need to be ignored. Then in Powershell do:
git init
and we now have a local git repository. You can do this later at any time, just don’t forget to add existing files you need versioned. Of course you can connect your local repository to a remote. There is enough information on the web about that. Following the “12-factor app” principles all developers should work from one code base in a central repository.
We are going to build a ReactJS app so logically we need to install the ReactJS libraries. In Powershell:
yarn add react react-dom
This will install the latest version of the basic ReactJS libraries in our project. If you use an npm version older than 5.0.0 you need to add the –save flag as well to indicate the dependency of your project output on these libraries.
Creating the plumbing
We will create a single HTML page index.html
for our ReactJS app to run. Usually static items like a favicon.ico
icon and robots.txt
go in the public folder, but the index.html
goes into the /src
folder because we will use it as template for a plugin to inject the necessary references. Therefore it will be processed and not just copied as the assets in /public
. Fill out the basic HTML outline. If you have the “HTML-Boilerplate” or a similar extension installed in VS Code this is done very quickly (https://marketplace.visualstudio.com/items?itemName=sidthesloth.html5-boilerplate).
Within the HTML <body> write:
<div id="root"></div>
This will be the main placeholder where our app goes. Add any meta tags, icon references and other stuff you need in your HTML header, or if you plan to use server-side rendering (SSR) you can use React Helmet (https://github.com/nfl/react-helmet).
Next we will create the top level component for our app. We want our project organized logically when it grows. In the /src/components
folder create a folder App
. In that folder create a file App.jsx
containing the following code:
import React, { Component} from "react";
class App extends Component{
render(){
return(
<div className="App">
<h1> Hello, React World! </h1>
</div>
);
}
}
export default App;
We still need to bind our app root component to the <div> element in index.html. In the src
folder itself create a file index.jsx
containing the following:
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App/App";
ReactDOM.render(<App />, document.getElementById("root"));
As you can see all this file does is render the component App in the <div> we created in our index.html
. For some tools we need to tell this is our starting point, so in package.json change the “main” attribute to:
"main": "src/index.jsx
“
We now have our basic project outline and plumbing. The one thing to do is add references to the build result (our actual app) in index.html
. You can add hardcoded <script> and <link> tags for that but we will use a Webpack plugin later on to do this dynamically for us. You can also add a <noscript> tag with a text to notify any users that have a browser without Javascript (although I don’t think you can do anything with a browser nowadays if you have no Javascript enabled).
Note there is not one recommended or best structure for ReactJS projects, so you can keep a different structure as long as you make all references match up.
Provisioning and the toolchain
Now let’s set up our tooling. But first we will do something called provisioning: we will set up the environment for our tools so they have a context to run in.
Dotenv
Dotenv is a tool that allows us to define environment variables in a file, which will then be passed by node.js to our tools as properties on process.env. In Powershell:
yarn add dotenv
Then create a file .env
in the root folder of our project. In here you can define any environment variable you may need in your project. Following the “12-factor-app principles” again configuration concerning the environment should be in environment variables. So we put in our .env
now:
PUBLIC_URL=http://localhost/
PORT=3000
We will now be able to access environment variables in our build scripts code as properties on process.env
. Since environment variables are context for and not part of the application build process, you should add the .env
file to .gitignore
. Also it is strongly recommended not to use .env
in a production environment for security reasons.
Babel
To use React’s Javascript Extensions (JSX) we need transpiling of JSX into Javascript during the build process. Also modern Javascript frameworks like ReactJS may use specifications of Javascript not available in older browser versions. For all this we will use Babel. This is an extensible transpiler using plugins that can transform JSX and modern Javascript (or more precise modern ECMAScript) and other extension expressions into Javascript that even older browsers can run.
To install Babel and the necessary transformers we go to Powershell again:
yarn add -D @babel/core @babel/cli @babel/preset-env @babel/preset-react
Note the -D flag since we only need Babel during the development build process. It is not a dependency for the runtime version of our app.
Babel needs some configuration. For our project, in the root folder create a file .babelrc
containing the following:
{
"presets": ["@babel/env", "@babel/preset-react"]
}
Despite the lack of a json file extension this is a json file. Note there’s no difference if you use “preset-env” instead of “env”, the “preset-“ part is optional.
Babel has a few different ways to be configured (one is including a key in the package.json
instead of a configuration file) but we use the .babelrc
one here. See the Babel documentation about configuration for more details.
WebPack
So far we set up our project outline and our first tool, but we need a way to run tools in order and create output without a lot of repetitive manual tasks. This is where WebPack comes into play. WebPack has arguably become the most popular Javascript development tool, being a module bundler and extensible task runner in one. In order to install WebPack we go to PowerShell again and do:
yarn add -D webpack webpack-cli webpack-merge babel-loader
As you see we also install the command line interface for WebPack so we can call it from Powershell. Note the -D flag again; WebPack is not a runtime dependency. We also install a loader so webpack can use Babel. See https://webpack.js.org/loaders/ for details and an overview of loaders in WebPack.
In a configuration script we tell webpack how and when to use loaders and plugins. By default this is a file named webpack.config.js.
However configuration for development quite often differs from test or production. To avoid having to put conditionals and checks everywhere we will use separate configuration files per environment type and merge it with a common configuration file. That’s why we also installed webpack-merge with the above. In our project root we create three files:
webpack.common.js
webpack.dev.js
webpack.prod.js
In webpack.common.js
put the following code:
const path = require("path");
const webpack = require("webpack");
const envLoadResult = require('dotenv').config();
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
output: {
path: path.resolve(__dirname, "build"),
publicPath: "/",
filename: "scripts/[name]_[hash].js"
},
plugins: [new webpack.HotModuleReplacementPlugin()]
}
In webpack.dev.js
:
const path = require("path");
const webpack = require("webpack");
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const envLoadResult = require('dotenv').config();
let devConfig = {
entry: "./src/index.jsx",
mode: "development",
devtool: "inline-source-map"
}
module.exports = (env, argv) => {
if(envLoadResult.error) {
throw "Error loading environment variables from .env file.";
}
return merge(commonConfig, devConfig);
}
And in webpack.prod.js
:
const path = require("path");
const webpack = require("webpack");
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const envLoadResult = require('dotenv').config();
let prodConfig = {
entry: "./src/index.jsx",
mode: "production"
}
module.exports = (env, argv) => {
return merge(commonConfig, prodConfig);
}
You can find easily on the web what the various parts of the config files do. Note the mode
setting in the specific configuration files: this property tells webpack to do optimizations like minification for production builds. It also lets Webpack set the process.env.NODE_ENV
environment variable to either production or development.
I assigned the configurations to variables, then export it through a function instead of directly export as an object, as often shown in examples. This allows us to set configuration properties based on passed command line arguments and environment variables. The env
parameter will have the environment variables from the .env
file as properties, while argv
will have any passed commandline parameters as properties.
We add 2 build command to our package.json
, one for a dev build and one for a production build:
"scripts": {
"dev:build": " webpack --config webpack.dev.js",
"prod:build": "webpack --config webpack.prod.js"
}
Now when we type yarn dev:build
(or npm run dev:build
) it will create a development output in the /build
folder. Similar goes for the production build. However it will bundle everything in one big script file, and it cannot handle things like images. We will fix that later.
Inject build result references into index.html
As said before we don’t use hard references in our index.html
but we will use a webpack plugin. This way if we change or add anything it will be handled automatically by WebPack. Install the plugin with:
yarn add -D html-webpack-plugin
Now near the top of our webpack.common.js
put:
const HtmlWebpackPlugin = require('html-webpack-plugin');
And to the plugins, add as first plugin of the array:
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
filename: path.resolve(__dirname, 'build/index.html')
})
Clear /build folder on build
Clearing the /build
folder for every build is important since we will change output filenames using hashes when they change, using Webpack’s [hash] tag. This is so updated versions of code files and assets are loaded correctly instead of old versions from caches. There’s a simple webpack plugin to clean the output folder on every build:
yarn add -D clean-webpack-plugin
Add to webpack.common.js
the following:
- near the top:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
- to the plugins array:
new CleanWebpackPlugin()
Now the /build
folder should be cleaned up on every build.
Hot Module Replacement (HMR) for ReactJS
HMR enables you to see changes to your code on the fly appear in the browser. React Hot Loader (RHL) does this without fully reloading the page every time and with keeping state in React. At the moment of writing the React-Hot-Loader page mentions it will be replaced by React Fast Refresh once that’s stable. See https://github.com/gaearon/react-hot-loader.
Part we already set up in our webpack.common.js
: the HotModuleReplacementPlugin. But to make it work we need to do some more work.
First install the React Hot Loader plugin. Note the -D flag is optional since the plugin will disable itself in a non-development environment, but to minimize unnecessary dependencies in production builds we pass the flag anyway. Powershell from our project root again:
yarn add -D react-hot-loader
To our Babel configuration .babelrc
add the following attribute:
"plugins": ["react-hot-loader/babel"]
Then add to App.jsx
:
import {hot} from "react-hot-loader";
and change the export line to:
export default hot(module)(App);
Note only the root App module needs to be wrapped by the hot returned function, other module exports are normal.
Setting up a (development) server
So far we set up some tooling for building a ReactJS app, but we need a way to run our app on our dev server so we can see some results. Easiest is to install the Webpack dev server, but it’s only a simple static file server and doesn’t support features like server side rendering (SSR) or middleware. So for our environment we will use the Express framework (https://expressjs.com/).
First we have to install Express and the necessary middleware:
yarn add express webpack-hot-middleware webpack-dev-middleware
Then in webpack.dev.js,
replace the entry
property with the following:
entry: [
'react-hot-loader/patch',
'webpack-hot-middleware/client',
'./src/index.jsx'
]
In the project root folder, create a file server.js
, with the following code:
const express = require('express');
const webpack = require('webpack');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require ('./webpack.dev.js');
const compiler = webpack(config());
const xpf = express();
const port = process.env.PORT;
const url=process.env.PUBLIC_URL;
xpf.use(
webpackDevMiddleware(compiler, { /* webpack middleware options */ })
).use(
webpackHotMiddleware(compiler)
).listen(port, () => {
console.log('Listening at '+ url + ':' + port + '/');
});
Quite often a variable app
is used to assign the express
object but I prefer to name it something different (xpf
in this case) since app is already used elsewhere.
Note the webpack configuration config()
is written as a function and not an object due to the way we exported the webpack.dev.config
! Don’t forget the parentheses here or the build will fail. What options you can put in for the middleware you can find on https://github.com/webpack/webpack-dev-middleware.
Now all we need is a command to start our dev server and open a browser window. We install a handy option for our scripts in package.json named Concurrently:
yarn add concurrently
This enables us to run multiple commands simultaneously with a script command. To scripts in package.json
add:
"start": "concurrently \"node server.js\" \"start http://localhost:3000\""
Make sure the port matches with the PORT environment variable; since package.json
is a static json file we cannot import environment variables in it. Also note the escaped quotes, they are necessary for Concurrently to work.
Now with a yarn start
(or npm start
) our app will build, be served by Express and shown in a browser window. Do note we didn’t actually implement server side rendering (SSR) here, we merely have Express serve our app similar as webpack-dev-server would do, but with more control and configuration options and the possibility to add SSR.
Check in Chrome devtools console the hot replacement (RHL) is working. You can check this also by verifying that while running, if you change anything in App.jsx
it should show immediately in the browser without reloading the page. With newer ReactJS versions there’s one thing to fix. If you opened the Devtools console you may have seen the warning “react-🔥-dom patch is not detected” and some newer features may not work. For that we need to add an entry to the rules array in our webpack.common.js
:
{
test: /\.(js|jsx)$/,
use: 'react-hot-loader/webpack',
include: /node_modules/
}
At this point you should have a basic React app working, but so far we can’t handle styling or images yet. We need to do more for that.
SCSS
Modern UI framework development needs more than plain CSS for styling to work with. We will set up SCSS as it works well with ReactJS but any alternative will do. Also the normal “style-loader” WebPack will bundle everything in one package, but we want our resulting stylesheets to be separate from script code. Therefore we use the MiniCssExtractPlugin for WebPack. In Powershell do:
yarn add -D mini-css-extract-plugin styles-loader css-loader sass-loader node-sass
In webpack.common.js
, add near the top:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
add to plugins:
new MiniCssExtractPlugin({filename : './styles/[name]_[hash].css'}
)
and add the following to the rules
array:
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}
Make sure the loaders in use:
are listed in the above order. Note we also installed styles-loader even though we don’t reference it here, but without it any import directives for css in your jsx files will fail.
In our project structure, make SCSS files per component in the component’s folder, so for the root component App create an App.scss
file in the App
folder in components and put any styling you want for App in there. Notice we don’t need to add any stylesheet references in html. The earlier installed HtmlWebpackPlugin automatically handles the injection for stylesheet references.
Images
Now for images. We need to set up a file loader for it. First, do:
yarn add -D file-loader
And add to the rules in webpack.config.js
:
{
test: /\.(gif|png|jpe?g|svg)$/i,
loader:'file-loader',
options: {
name: 'assets/images/[name]_[hash].[ext]'
}
}
Create and /images
folder in the /src
folder, put some image in there and import/ add it to App.jsx
. The image should display. However there’s no optimizations yet. For that you need to install and configure image-webpack-loader. I’m not going to show that here since it’s covered in detail on https://www.npmjs.com/package/image-webpack-loader.
Static assets
One thing that is not yet happening now is our static assets like favicon and other stuff in the /public
folder being copied to our build output. And maybe we have more static assets in other places. Again, there’s a WebPack plugin to take care of this all:
yarn add -D copy-webpack-plugin
Add to the top of webpack.common.js
:
const CopyPlugin = require('copy-webpack-plugin');
And to the plugins
array:
new CopyPlugin({
patterns: [
{ from: "public", to: "" }
]
})
CopyWebPackPlugin has a lot of options for filtering, locations and even transformations so it is a very handy plugin for handling folders with static assets. See on https://webpack.js.org/plugins/copy-webpack-plugin/. You can also set an option to limit concurrent requests to the file system.
Placeholders in HTML
Sooner or later we may need to inject or replace parts in HTML. As an example let’s say we want an absolute url to our favicon in our index.html
. This is dependent on the environment (defined in .env
on our development machine), so we want to use a placeholder and replace it with the specific url on build. Let’s say we put in our index.html
:
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
The favicon itself will be copied to the root of our app by the previously described CopyWebpackPlugin. Now we need to replace %PUBLIC_URL%
with our actual url that’s defined in .env
. In comes the HtmlReplaceWebpackPlugin:
yarn add -D html-replace-webpack-plugin
Note it is dependent on HtmlWebpackPlugin which we already installed. Now create a file in the project root replacements.js
(or whatever name you want to give), with the following:
require('dotenv').config();
module.exports = [
{
pattern: '%PUBLIC_URL%',
replacement: process.env.PUBLIC_URL + ":" + process.env.PORT
}
]
In webpack.common.js
add:
const HtmlReplaceWebpackPlugin = require('html-replace-webpack-plugin');
const replacements = require ('./replacements.js');
and in the plugins
array:
new HtmlReplaceWebpackPlugin (replacements)
Now in the replacements.js
we can define all replacements any way we want as long as it returns a valid array for the plugin. HtmlWebpackPlugin does support complex replacement patterns so we can have much more advanced scenario’s. See on https://www.npmjs.com/package/html-replace-webpack-plugin.
More tools, libraries and frameworks
We now have a working environment, but for full professional development more tooling is required. With guides and directions found everywhere on the net adding them to our setup shouldn’t be too much of a problem now. Some tools that may be needed or useful I will mention here.
Code splitting
An increasing problem with growing web apps is the amount of script code and assets that are loaded with a page, especially with frameworks like ReactJS and single page apps where basically the whole app is scripted. Bundling is done to prevent a website or app having to make tons of requests over the net for script files and other assets.
On the other hand, putting all scripts and assets in one bundle makes a (first) page load having a lot of overhead on scripts that may not be used on it. Modern browser caching and delivery networks make that heavy loading often a one-time event, but still page load on a first visit from an user may become too slow, and the fast release cycles with DevOps techniques partly undo the long-term caching benefits if all scripts and assets are in one big bundle.
For that we split up script code and other assets in chuncks. Webpack already comes with a plugin for it, the SplitChunksPlugin which is already present when Webpack is installed. Al we need to do is put the following in webpack.common.js
:
optimization: {
splitChunks: {
chunks: 'all'
}
}
The default settings already splits up our own code and the third-party code from /node_modules
in separate chuncks. The references to chuncks are automatically injected in index.html
by the HtmlWebpackPlugin we installed near the beginning.
On https://webpack.js.org/guides/code-splitting/ and https://webpack.js.org/plugins/split-chunks-plugin/ a lot more is explained about code splitting and all the possible options for optimizations in the webpack configuration. An effective code splitting strategy is very much dependent on the app being built and the specific environment, so I don’t go into more detail here.
Typescript
Due to its nature of being a dynamic and weakly typed language Javascript is more prone to runtime errors than some other programming languages. This is one reason why for larger and complex projects Typescript may be preferred. For setting up Typescript with React there is a guide on the Webpack site at https://webpack.js.org/guides/typescript/.
Code analysis
Another help can be the use code analysis by means of a linter. According to several sources the most common used linters are JSLint and ESLint.
Most linters can be configured but be aware of too strict rule settings. I have seen productivity severely impaired on projects because of linting rule errors in automatic builds while the code itself was working perfectly and just a warning would be fine. Remember the four core principles of the Agile manifest. Tools should be there to help the developers, not get in the way of productivity.
Testing
Automatic testing can be used to verify the code does what it is supposed to do and throws no unexpected errors. Since ReactJS is a UI framework testing often involves automating user interaction. For ReactJS the JEST framework is provided by Facebook. Other popular test frameworks and tools are Selenium, MochaJS and Jasmine.
Lodash
Lodash is a popular successor of Underscore, a library with useful functions and utilities.
Redux
When a React app becomes more complex, managing the state of various parts of the app can become complex and inconsistent. Redux is a state management library often used in combination with React.
React Developer tools
This is an extension for the Chrome browser devtools (F12) and can be found in the Chrome web store. With this extra options “Components” and “Profiler” appear with the devtools when running a React app. These make it easier to debug and profile a React app.
User interface design
If you ever built sites with Javascript in the past years you have probably come across Bootstrap at some point, the library to create UI layouts and consistent CSS. Now there’s a version specific for React applications.
Another popular user interface components library is Material-UI (https://material-ui.com/). Setup and use are quite extensive, but I found a clear article about it on https://uxdesign.cc/material-design-with-reactjs-using-material-ui-9f7e81a955f7.
Using certificates
Using plain old http is not acceptable anymore, and an increasing amount of tools and libraries block or throw errors on anything not using https. This may cause problems if we use plain http for our development. You may need to install a (self-signed or even official) certificate and switch to https on your localhost as well. Here is a Powershell script to create a self-signed certificate:
# Creates a self-signed certificate in the My store
# Also copy to trusted publishers through the certificates MMC
# adjust dnsname accordingly in this script
$todaydt = Get-Date
$10years = $todaydt.AddYears(10)
New-SelfSignedCertificate -dnsname localhost -NotAfter $10years -CertStoreLocation cert:\LocalMachine\My
Type “mmc” in Powershell and it will open up the Microsoft Managment Console. Add the MMC certificates plugin for the computer, go to “Personal” and you should see the newly created certificate. From here you can export it to various format of key files or use win-ca (https://www.npmjs.com/package/win-ca) to have node.js read the certificate from the Windows store. See on https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener how you can adjust the code in server.js
to use https.createserver(….)
to create a server using Express and https.
Final note
With the above we have already quite a setup, but the world of frontend development is very volatile. Tools or libraries popular today may be obsolete and replaced with new ones tomorrow. Expect to have to learn about and use new or updated stuff constantly. Every new project should start with some research on which versions of what tools and libraries to use. For professional development only use stable versions and don’t use obscure or rarely used tools and libraries, otherwise it will be very difficult to find support for any problems you may run into.