1. Initialize the
mkdir react-webpack-demo
cd react-webpack-demo
npm init
Copy the code
  1. Install the react
npm i react react-dom
Copy the code

React did not have ReactDOM before V0.14. All functions were included in React. React was split into React and ReactDOM from later versions. Why separate React from ReactDOM? With ReactNative, React only contains the core parts common to both Web and Mobile. The Dom operations are divided into the ReactDOM, and the Mobile operations are included in the ReactNative.

  1. Install webpack and WebPack-CLI
npm i -D webpack webpack-cli
Copy the code
  1. Create the wbpack.config.js file and the entry file index.tsx
type nul>webpack.config.js
mkdir src
cd src
type nul>index.tsx
Copy the code

webpack.js

module.exports = {
  entry: "./src/index.tsx"};Copy the code
  1. Package. json adds script command
 "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
Copy the code

If you run the NPM run dev test without specifying mode, Webpack will issue a warning and use production by default. This mode can also be configured in weback.config. Packaging succeeded. The entry file is currently empty.

  1. Add content to entry file index. TSX
import React from "react";
import ReactDOM from "react-dom";
const App = <div>hello</div>;

ReactDOM.render(App, document.querySelector("#app"));
Copy the code

NPM run dev error: You may need an appropriate loader to handle this file type because JSX syntax is found in the file

  1. Added loader parsing JSX
npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react

Copy the code

Webpack.confg.js adds loader configuration

module.exports = {
  entry: "./src/index.tsx".module: {
    rules: [{test: /\.(js|mjs|jsx|ts|tsx)$/,
        exclude: /node-modules/,
        loader: "babel-loader",},],},};Copy the code

Create a new Babel configuration file in the root directory

type nul>.babelrc
Copy the code
{
  "presets": ["@babel/react","@babel/env"]
}
Copy the code

Note: If the JSX syntax is used in the file, the file suffix must be. JSX or. TSX before it can be parsed by loader.

Dist /mian. Js file. This is a compiled JS file that can be directly parsed by the browser and referenced by other HTML files. Next, add an HTML template file and, with the help of the Webpack Plugin, inject the compiled file into the HTML.

  1. Add an HTML template file. In the root directory, create a public directory, public/index.html file
mkdir public
cd public
type nul>index.html
Copy the code

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta http-equiv="X-UA-Compatible" content="IE=11" />
  <meta http-equiv="Expires" content="0">
  <meta http-equiv="Pragma" content="no-cache">
  <meta http-equiv="Cache-control" content="no-cache">
  <meta http-equiv="Cache" content="no-cache">
  <meta name="format-detection" content="telephone=no">
  <title>react-webpack-demo</title>
</head>

<body>
  <div id="app"></div>
</body>

</html>HTML - webpack - the plugin installationCopy the code

npm i -D html-webpack-plugin

Copy the code

Webpack configuration file added

const HtmlWebpackPlugin = require("html-webpack-plugin");
/ /... Middle part omitted
plugins: [
  new HtmlWebpackPlugin({
    template: "./public/index.html",})];Copy the code

The dist directory has an index. HTML file that can be opened directly in the browser.

  1. Added devServer for easy local development real-time preview of WebPack configuration files added
  devServer: {
    port: 8090.// Specify a port
    open: true.// Automatically open the browser
  },
Copy the code

Package. json scripts dev Adds the serve command

"dev": "webpack serve --mode development",
Copy the code

Error: Install webpack-dev-server

 npm i -D webpack-dev-server
Copy the code
  1. Webpack adds the output configuration
  output: {
    path: path.resolve(__dirname, "dist"), // The webpack output directory defaults to dist
    filename: "[name].[hash].js".clean: true.// Empty dist before packing
  },
Copy the code
  1. Webpack configures extensions and aliases for import. Aliases also need to be configured for paths in tsconfig.json. You must restart vscode,tsconfg. Json is in the project root directory), and configure alias in both places to be linked to correctly
 resolve: {
    extensions: [".js".".jsx".".ts".".tsx"].alias: {
      "@": path.resolve(__dirname, "./src"),
      "@v": path.resolve(__dirname, "./src/views"),// View page
      "@t": path.resolve(__dirname, "./src/types"),// Unified management of TS types
      "@c": path.resolve(__dirname, "./src/components"),// Global components}},Copy the code

Tsconfg. json(complete), configure alias, just add paths

{
  "compilerOptions": {
    "target": "es5"."module": "esnext"."baseUrl": ". /"."types": ["webpack-env"]."paths": {
      "@ / *": ["src/*"]."@v/*": ["src/views/*"]."@c/*": ["src/components/*"]."@t/*": ["src/types/*"]},"lib": ["dom"."dom.iterable"."esnext"]."sourceMap": true."allowJs": true."checkJs": true."esModuleInterop": true."allowSyntheticDefaultImports": true."strict": true."skipLibCheck": true."noImplicitReturns": true."noUnusedLocals": false."noUnusedParameters": true."forceConsistentCasingInFileNames": true."moduleResolution": "node"."resolveJsonModule": true."jsx": "react"
  },
  "include": ["src"]."exclude": ["node_modules"."src/assets/*"]}Copy the code

After this configuration, you need to restart vscode for the link to take effect.

  1. Tsconfig. json, entry file index. TSX, editor type not found
 npm i -D @babel/preset-typescript typescript @types/react @types/react-dom
Copy the code
  1. Add CSS precompiled LESS
 npm i -D less less-loader css-loader
Copy the code

Added under Webpack configuration file Rules

  {
    test: /\.less$/,
    use: [
      {
        loader: "css-loader".// Process CSS files
      },
      {
        loader: "less-loader".// Process less files as CSS files},],},Copy the code

Add file styles/global.less under SRC

.color-red {
  color: red;
}
Copy the code

The index. TSX file is modified as follows

import React from "react";
import ReactDOM from "react-dom";
import "./assets/styles/global.less";

const App = <div className="color-red">hello32</div>;

ReactDOM.render(App, document.querySelector("#app"));
Copy the code

Run NPM Dun dev and find that CSS file is not loaded and styles are not in effect? Webpack adds style-loader to inject CSS files into HTML files

 npm i -D style-loader
Copy the code

Webpack rules less

  {
    test: /\.less$/,
    use: [
      {
        loader: "style-loader".// Inject the file into the HTML head
      },
      {
        loader: "css-loader"}, {loader: "less-loader",}]},Copy the code

Run the command again and it takes effect

  1. If you don’t want to inject style into an HTML file and use a separate file, you can use the Webpack plugin mini-CSs-extract-plugin.
npm i -D mini-css-extract-plugin
Copy the code

Webpack introduces definitions

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
Copy the code

Delete style-loader and package.json devDependencies from webpack rules less


{
  test: /\.less$/,
  use: [
    MiniCssExtractPlugin.loader,
    / / {
    // loader: "style-loader", // inject the file into the HTML head
    // },
    {
      loader: "css-loader"}, {loader: "less-loader",}]},Copy the code

Added CSS -loader to handle CSS files and extract CSS files to separate files under Rules added CSS parsing

 {
    // Extract the CSS to a separate file
    test: /\.css$/,
    use: [MiniCssExtractPlugin.loader, "css-loader"],},Copy the code

Add MiniCssExtractPlugin to Webpack Plugins

 plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",}).new MiniCssExtractPlugin(),
  ],
Copy the code

As you can see, a CSS file is pulled out of the package

  1. Use style-resources-loader to add global less variables that can be referenced by other LESS files
npm i -D style-resources-loader
Copy the code

New file/SRC/assets/styles/variable. The less

// font
@default-font: 12px;
//color
@primary-text-color: #333;
// height
Copy the code

Webpack Rules less added


{
  test: /\.less$/,
  use: [
    MiniCssExtractPlugin.loader,
    / / {
    // loader: "style-loader", // inject the file into the HTML head
    // },
    {
      loader: "css-loader"}, {loader: "less-loader"}, {loader: "style-resources-loader".options: {
        patterns: path.resolve(
          __dirname,
          "./src/assets/styles/variable.less"),},},],},Copy the code

In the test, modify global.less

.color-red {
  color: @primary-text-color;
}
Copy the code

Rerun, NPM run dev

  1. CSS properties multi-browser prefix processing
npm i -D postcss-loader autoprefixer
Copy the code

Add the postcss.config.js file to the root directory

module.exports = {
  plugins: [
    require("autoprefixer"), // References the Autoprefixer module]};Copy the code

Add browserslist to package.json

 "browserslist": [
    "1%" >."last 2 versions"."not ie <= 8"."since 2013"."Firefox ESR"."Firefox > 20"."cover 99.5%"."unreleased versions"."defaults"
  ]
Copy the code

In rules, less is modified as follows

{
  test: /\.less$/,
  use: [
    MiniCssExtractPlugin.loader,
    / / {
    // loader: "style-loader", // inject the file into the HTML head
    // },
    {
      loader: "css-loader"
    },
    {
      // Prefixes the CSS
      loader: "postcss-loader"}, {loader: "less-loader"}, {loader: "style-resources-loader".options: {
        patterns: path.resolve(
          __dirname,
          "./src/assets/styles/variable.less"),},},],},Copy the code
  1. Style processing in React uses a combination of CSS-Module + Styled components
npm i -D styled-components
Copy the code

Index.tsx is modified as follows

import React from "react";
import ReactDOM from "react-dom";
import "./assets/styles/global.less";
import styled from "styled-components";

const AppCon = styled.div` font-size: 18px; `;
const App = <AppCon className="color-red">hello32</AppCon>;

ReactDOM.render(App, document.querySelector("#app"));
Copy the code

Css-module makes less modular, similar to vue’s scope creating SRC /index.module.less files

.bg {
  background: gray;
}
Copy the code

Index.tsx is modified as follows

import React from "react";
import ReactDOM from "react-dom";
import "./assets/styles/global.less";
import styled from "styled-components";
import styles from "./index.module.less";

const AppCon = styled.div` font-size: 18px; `;
const App = <AppCon className={`color-redThe ${styles.bg} `} >hello32</AppCon>;

ReactDOM.render(App, document.querySelector("#app"));
Copy the code

Change webpack rules less CSS-loader to the following

{
  loader: "css-loader".options: {
    sourceMap: true.modules: {
      mode: (resourcePath) = > {
        if (/global.less$/i.test(resourcePath)) { // Filter out global styles
          return "global";
        }
        return "local";
      },
      localIdentName: "[name]-[local]-[hash:5]".// localIdentName User-defined generated class name format}},},Copy the code

Error: index.module.less generates ts type error. SRC /types adds index.d.ts

// Type declarations for all ts in the project

declare module "*.jpg";
declare module "*.png";
declare module "*.jpeg";
declare module "*.gif";

declare module "*.module.less" {
  const content: any;
  export default content;
}
Copy the code
  1. CSS compression WebPack configuration file added
  const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
  optimization: {
    minimizer: [new CssMinimizerPlugin()],
    minimize: true.// Use CSS optimizations in development environments
  },
Copy the code
npm i -D css-minimizer-webpack-plugin
Copy the code
  1. Other file types loader Added Add loader for handling other file types under WebPack Rules
npm i -D html-loader file-loader url-loader
Copy the code
{
  // url-loader: processing image resources. Problem: img images in HTML cannot be processed by default
  test: /\.(jpg|png|gif|jpeg)$/.// Download url-loader file-loader
  loader: "url-loader".options: {
    // If the image size is less than 8KB, it will be processed by Base64. Advantages: reduce the number of requests (reduce server stress), disadvantages: Larger image size (slower file request)
    // Base64 decoding in the local client will reduce the server pressure, if the image is too large and base64 encoding will lead to CPU call rate increase, webpage load time change card
    limit: 8 * 1024.// Rename the image, [hash:10] : take the first 10 bits of the hash of the image, [ext] : take the original extension of the file
    name: "[hash:10].[ext]".[object Module] [object Module] [object Module] [object Module] [object Module]
    // Resolve: Disable ES6 modularization of urL-loader and use CommonJS parsing
    esModule: false.outputPath: "imgs",}}, {test: /\.html$/.// Handle the IMG image of the HTML file (responsible for importing img so that it can be processed by urL-loader)
  loader: "html-loader",},// Package other resources (other than HTML /js/ CSS)
{
  / / | | js | CSS rule out HTML less | JPG | PNG | | GIF jpeg files
  exclude: /\.(html|js|mjs|ts|jsx|tsx|css|less|jpg|png|gif|jpeg)/.// file-loader: processes other files
  loader: "file-loader".options: {
    name: "[hash:10].[ext]".outputPath: "assets",}},Copy the code
  1. Package gzip to open webpack file increment
  const CompressionPlugin = require("compression-webpack-plugin");
  new CompressionPlugin({
    filename: "[path][base].gz".test: /\.(js|css|svg)$/.// threshold: 10240, // Only handle resources larger than this value
    // minRatio: 0.8, // Only resources with a compression ratio lower than this value are processed
  }),
Copy the code
npm i -D compression-webpack-plugin
Copy the code
  1. Webapck packaging analysis
npm i -D webpack-bundle-analyzer cross-env
Copy the code

The full packag. Json

{
  "name": "react-webpack-demo"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "dev": "webpack serve --mode development"."build": "webpack --mode production"."report": "cross-env report=true webpack --mode production"."test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": ""."license": "ISC"."dependencies": {
    "react": "^ 17.0.2"."react-dom": "^ 17.0.2"
  },
  "devDependencies": {
    "@babel/core": "^ 7.16.0"."@babel/preset-env": "^ 7.16.0"."@babel/preset-react": "^ 7.16.0"."@babel/preset-typescript": "^ 7.16.0"."@types/react": "^ 17.0.34"."@types/react-dom": "^ 17.0.11"."@types/styled-components": "^ 5.1.15"."autoprefixer": "^ 10.4.0"."babel-loader": "^ 8.2.3"."compression-webpack-plugin": "^ 9.0.0"."cross-env": "^ 7.0.3." "."css-loader": "^ 6.5.1." "."css-minimizer-webpack-plugin": "^ 3.1.1." "."file-loader": "^ 6.2.0"."html-loader": "^ 3.0.1." "."html-webpack-plugin": "^ 5.5.0"."less": "^ 4.1.2." "."less-loader": "^ 10.2.0"."mini-css-extract-plugin": "^ 2.4.3." "."postcss-loader": "^ 6.2.0"."style-loader": "^ 3.3.1"."style-resources-loader": "^ 1.4.1." "."styled-components": "^ 5.3.3." "."typescript": "^ 4.4.4." "."url-loader": "^ 4.4.1"."webpack": "^ 5.61.0"."webpack-bundle-analyzer": "^ 4.5.0." "."webpack-cli": "^ 4.9.1." "."webpack-dev-server": "^ 4.4.0"
  },
  "browserslist": [
    "1%" >."last 2 versions"."not ie <= 8"."since 2013"."Firefox ESR"."Firefox > 20"."cover 99.5%"."unreleased versions"."defaults"]}Copy the code

The full webpack. Config. Js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // Inject the package file into the HTML file
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

const isReport = process.env.report; // Whether to enable package analysis

const webpackConfig = {
  entry: "./src/index.tsx".devServer: {
    port: 8090.// Specify a port
  },
  output: {
    path: path.resolve(__dirname, "dist"), // The webpack output directory defaults to dist
    filename: "[name].[hash].js".clean: true.// Empty dist before packing
  },
  module: {
    rules: [{test: /\.(js|mjs|jsx|ts|tsx)$/,
        exclude: /node-modules/,
        loader: "babel-loader"}, {test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"."postcss-loader"],}, {test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          / / {
          // loader: "style-loader", // inject the file into the HTML head
          // },
          {
            loader: "css-loader".options: {
              sourceMap: true.modules: {
                mode: (resourcePath) = > {
                  if (/global.less$/i.test(resourcePath)) {
                    return "global";
                  }
                  return "local";
                },
                localIdentName: "[name]-[local]-[hash:5]".// localIdentName User-defined generated class name format}},}, {// Prefixes the CSS
            loader: "postcss-loader"}, {loader: "less-loader"}, {loader: "style-resources-loader".options: {
              patterns: path.resolve(
                __dirname,
                "./src/assets/styles/variable.less"),},},],}, {// url-loader: processing image resources. Problem: img images in HTML cannot be processed by default
        test: /\.(jpg|png|gif|jpeg)$/.// Download url-loader file-loader
        loader: "url-loader".options: {
          // If the image size is less than 8KB, it will be processed by Base64. Advantages: reduce the number of requests (reduce server stress), disadvantages: Larger image size (slower file request)
          // Base64 decoding in the local client will reduce the server pressure, if the image is too large and base64 encoding will lead to CPU call rate increase, webpage load time change card
          limit: 8 * 1024.// Rename the image, [hash:10] : take the first 10 bits of the hash of the image, [ext] : take the original extension of the file
          name: "[hash:10].[ext]".[object Module] [object Module] [object Module] [object Module] [object Module]
          // Resolve: Disable ES6 modularization of urL-loader and use CommonJS parsing
          esModule: false.outputPath: "imgs",}}, {test: /\.html$/.// Handle the IMG image of the HTML file (responsible for importing img so that it can be processed by urL-loader)
        loader: "html-loader",},// // Package other resources (resources other than HTML/JS/CSS resources)
      {
        / / | | js | CSS rule out HTML less | JPG | PNG | | GIF jpeg files
        exclude: /\.(html|js|mjs|ts|jsx|tsx|css|less|jpg|png|gif|jpeg)/.// file-loader: processes other files
        loader: "file-loader".options: {
          name: "[hash:10].[ext]".outputPath: "media",},},],},plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",}).new MiniCssExtractPlugin(),
    new CompressionPlugin({
      filename: "[path][base].gz".test: /\.(js|css|svg)$/.// threshold: 10240, // Only handle resources larger than this value
      // minRatio: 0.8, // Only resources with a compression ratio lower than this value are processed}),].optimization: {
    minimizer: [new CssMinimizerPlugin()],
    minimize: true.// Use CSS optimizations in development environments}};if (isReport) {
  webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}

module.exports = webpackConfig;
Copy the code