Webpack5 Manually builds the React TS project

1. Introduction

React has been used for a long time. Either crA or ANTDPro is used to set up projects for you. All you need to do is write business code. Therefore, IN my spare time, I plan to manually build a React Ts project based on WebPack5 step by step from 0, so I have the following practice. Since I am a little white, I welcome you to correct me if I have done something wrong.

2. Initialize the project

Find an empty directory and execute the following code:

mkdir webpack5-react-ts-tempalte
cd webpack5-react-ts-tempalte
npm init -y
Copy the code

3. Initialize typeScript configuration

npm install --save-dev typescript ts-loader
Copy the code

Create a new tsconfig.json file. I’m using the tsconfig configuration from the WebPack website.

{
  "compilerOptions": {
    "outDir": "./dist/"."noImplicitAny": true."module": "es6"."target": "es5"."jsx": "react"."allowJs": true."moduleResolution": "node"."allowSyntheticDefaultImports": true}}Copy the code

4. Configure webPack

npm i webpack webpack-cli webpack-merge html-webpack-plugin clean-webpack-plugin --dev
Copy the code

Since our project is basically divided into development environment and production environment, for the webPack configuration, I created three new files to store different configurations.

Create a config file to store the webpack configuration file:

  • webpack.config.base.jsStore the basic configuration of WebPack
  • webpack.config.dev.jsThe development environment configuration that holds WebPack
  • webpack.config.prod.jsProduction environment configuration to store WebPack
// config/webpack.config.base.js
const path = require('path
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') /** * @type {import('webpack').Configuration} */ module.exports = { entry: { app: './src/index.tsx', }, output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[hash].js', }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }, plugins: [ new HtmlWebpackPlugin({ title: 'Management background', template: path.resolve(__dirname, '../index.html'), filename: 'index.html', }), new CleanWebpackPlugin(), ], }Copy the code

Merge configuration items

Since we are configuring WebPack separately, there will be an operation to merge configuration items. The webPack-Merge plug-in installed above is the one that does this.

// config/webpack.config.dev.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
const path = require('path')

/ * * *@type {import('webpack').WebpackOptionsNormalized}* /
const devServer = {
  port: 3000.host: 'localhost'.contentBase: path.join(__dirname, '.. /publich'),
  watchContentBase: true.publicPath: '/'.compress: true.historyApiFallback: true.hot: true.clientLogLevel: 'error'.// open: true,
  watchOptions: {
    ignored: /node_modules/,}}const devConfig = {
  mode: 'development'.devServer: devServer,
}

module.exports = webpackMerge.merge(baseConfig, devConfig)

// config/webpack.config.prod.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
/ * * *@type {import('webpack').WebpackOptionsNormalized}* /
const prodConfig = {
  mode: 'production',}module.exports = webpackMerge.merge(baseConfig, prodConfig)
Copy the code

5. Configuration Babel

Install dependencies

npm i babel-loader babel-plugin-import @babel/cli @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript --dev
Copy the code

Create a new. Babelrc file in the root directory

{
  "presets": [
    "@babel/preset-env"."@babel/preset-react"]}Copy the code

Add the mode configuration to webpack.config.base.js

module.exports = {
    ...
    module: {
        rules: [{test: /\.(js|jsx)$/, loader: 'babel-loader'.exclude: /node_modules/ },
              { test: /\.(ts|tsx)$/, loader: 'ts-loader'.exclude: /node_modules/},],}};Copy the code

6. To configure the React

Install dependencies

npm i react react-dom react-router-dom
npm i @types/react @types/react-dom @types/react-router-dom --dev
Copy the code

New HTML file

Create index. HTML in the root directory

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

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

</html>
Copy the code

Create project entry file

Create app.tsx index.tsx in the SRC directory

// App.tsx

import React from 'react'

const App = () = > {
  return <div>1234</div>
}

export default App

// index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />.document.getElementById('root'))
Copy the code

7. Functional configuration

Style file parsing

npm i style-loader sass-loader sass css-loader postcss-loader postcss-normalize autoprefixer postcss-preset-env -D
Copy the code

Since we will not only use SCSS in development, but also use SCSS Module, we will configure and install dependencies at the same time

npm i react-dev-utils resolve-url-loader -D
Copy the code

Add mode configuration to webpack.config.base.js


const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent')

module.exports = {
    ...
    module: {
        rules: [{...test: /\.(css|scss)$/,
            exclude: /\.module\.scss$/,
            use: ['style-loader'.'css-loader'.'postcss-loader'.'sass-loader'],}, {test: /\.module\.scss$/,
            use: [
              'style-loader',
              {
                loader: 'css-loader'.options: {
                  modules: {
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
              },
              'postcss-loader'.'sass-loader',],},],},};Copy the code

Add the postcss.config.js file and configure it

const postcssNormalize = require('postcss-normalize')

module.exports = {
  plugins: [['postcss-preset-env',
      {
        autoprefixer: {
          flexbox: 'no-2009',},stage: 3,
      },
    ],
    postcssNormalize(),
    require('autoprefixer') ({overrideBrowserslist: ['last 2 version'.'> 1%'.'ios 7'],}),],}Copy the code

Picture address resolution

Webpack5 has built-in assets. We do not need to install additional plug-ins to parse resource files such as pictures. The configuration is as follows:

{
  test: /\.(jpe? g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i,
  type: "asset/resource",},Copy the code

8. Performance optimization

Webpack 5 has introduced caching to speed up secondary builds, so we just need to add the following code to the WebPack configuration file to enjoy caching

cache: {
  type: 'filesystem'.// Optional
  buildDependencies: {
    config: [__filename], // The cache is invalidated when the contents of the config file that builds the dependency (via the require dependency) change
  },
  name: 'development-cache',},Copy the code

9. Complete the configuration

webpack.config.base.js

// webpack.config.base.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
/ * * *@type {import('webpack').Configuration}* /

module.exports = {
  entry: {
    app: './src/index.tsx',},output: {
    path: path.resolve(__dirname, '.. /dist'),
    filename: '[name].[hash].js',},module: {
    rules: [{test: /\.(js|jsx)$/, loader: 'babel-loader'.exclude: /node_modules/ },
      { test: /\.(ts|tsx)$/, loader: 'ts-loader'.exclude: /node_modules/ },
      {
        test: /\.(css|scss)$/,
        exclude: /\.module\.scss$/,
        use: ['style-loader'.'css-loader'.'postcss-loader'.'sass-loader'],}, {test: /\.module\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader'.options: {
              modules: {
                getLocalIdent: getCSSModuleLocalIdent,
              },
            },
          },
          'postcss-loader'.'sass-loader',]}, {test: /\.(jpe? g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',}]},resolve: {
    extensions: ['.tsx'.'.ts'.'.js'.'.jsx'],},plugins: [
    new HtmlWebpackPlugin({
      title: 'Admin background'.template: path.resolve(__dirname, '.. /index.html'),
      filename: 'index.html',}).new CleanWebpackPlugin(),
  ],
  cache: {
    type: 'filesystem'.// Optional
    buildDependencies: {
      config: [__filename], // The cache is invalidated when the contents of the config file that builds the dependency (via the require dependency) change
    },
    name: 'development-cache',}}Copy the code

webpack.config.dev.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
const path = require('path')

/ * * *@type {import('webpack').WebpackOptionsNormalized}* /
const devServer = {
  port: 3000.host: 'localhost'.contentBase: path.join(__dirname, '.. /publich'),
  watchContentBase: true.publicPath: '/'.compress: true.historyApiFallback: true.hot: true.clientLogLevel: 'error'.// open: true,
  watchOptions: {
    ignored: /node_modules/,}}const devConfig = {
  mode: 'development'.devServer: devServer,
}

module.exports = webpackMerge.merge(baseConfig, devConfig)
Copy the code

webpack.config.prod.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
/ * * *@type {import('webpack').WebpackOptionsNormalized}* /

const prodConfig = {
  mode: 'production',}module.exports = webpackMerge.merge(baseConfig, prodConfig)
Copy the code

10. Extract CSS into a separate package file

The CSS in the above configuration is packaged into JS, so if you want to package the CSS separately, you need to do some configuration and install dependencies

npm install --save-dev mini-css-extract-plugin
Copy the code

Modify the configuration in webpack.config.base.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
	...
  plugins: [new MiniCssExtractPlugin({
              filename: 'css/[name].[hash].css'})],module: {
    rules: [{test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],},],},}Copy the code

11. Configure the development server

Install dependencies

npm i webpack-dev-server --dev
Copy the code

Add startup commands to package.json

"scripts": {
  
    "start": "webpack serve --config ./config/webpack.config.dev.js"."build": "webpack --mode=production --config ./config/webpack.config.prod.js"
  },
Copy the code

12. Problem solving

After completing the above steps, you may receive this error when running.

Cannot find module './index.module.scss' or its corresponding type declarations.
Copy the code

Since it is the project of TS, the declaration file needs to be written at this time.

A new declaration. Which s

declare module '*.scss' {
  const content: Record<string.string>
  export default content
}
Copy the code

13. Get good CSS code tips

A plug-in is required

npm install -D typescript-plugin-css-modules
Copy the code

Configuration tsconfig. Json

{ 
    "compilerOptions": 
	{ 
            "plugins": [{ "name": "typescript-plugin-css-modules"}}}]Copy the code

If you’re using vscode, you can do the same

Root directory to create.vscode folder, and then create Settings. Json

Write to the file

{
	"typescript.tsdk": "node_modules/typescript/lib"."typescript.enablePromptUseWorkspaceTsdk":true
}
Copy the code

Set the TypeScript version from your workspace to read the tsconfig.json file

Then you can get good code hints