# webpack5搭建React开发脚手架

# 1. 初始化npm环境

npm init -y

生成package.json文件

# 2. 本地安装webpack、webpack-cli

npm install webpack webpack-cli -D

webpack@5.64.4

webpack-cli@4.9.1

# 3. 最基本目录结构及配置

npm install webpack-dev-server html-webpack-plugin webpack-merge -D

  • 当前目录结构

  • 配置步骤

    webpack.config.base.js

    配置入口、出口、模板plugin

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: path.resolve(__dirname, '../src/index.js'),
      output: {
        filename: 'boundle.js',
        path: path.resolve(__dirname, '../dist'),
        clean: true,
      },
      plugins: [
        new HtmlWebpackPlugin({
          title: 'webpack5从0到1搭建React开发脚手架'
        })
      ]
    }
    

    webpack.config.dev.js

    配置开发服务器相关参数、source-map

    const path = require('path');
    const { merge } = require('webpack-merge');
    const baseConfig = require('./webpack.config.base');
    
    module.exports = merge(baseConfig, {
      mode: 'development',
      devServer: {
        static: {
          directory: path.resolve(__dirname, '../dist'),
        },
        port: 9000,
        hot: true,
        open: true,
      },
      devtool: 'source-map',
    })
    

    webpack.config.build.js

    const { merge } = require('webpack-merge');
    const baseConfig = require('./webpack.config.base');
    
    module.exports = merge(baseConfig, {
      mode: 'production',
    })
    

    package.json

    "scripts": {
        "start": "webpack serve --config ./build/webpack.config.dev.js",
        "build": "webpack --config ./build/webpack.config.build.js"
     },
    

# 4. babel-loader配置

npm install -D babel-loader @babel/core @babel/preset-env

npm install -D @babel/plugin-transform-runtime @babel/runtime

npm install -S corejs@3

webpack.config.base.js 增加如下配置内容:

module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
                ['@babel/preset-env',
                    {
                      useBuiltIns: 'usage',
                      corejs: 3,
                    }
             	],
            ],
            plugins: ['@babel/plugin-transform-runtime'],
            cacheDirectory: true,
          }
        }
      }
    ]
  },

# 5. 配置支持react语法

npm install -D @babel/preset-react

npm install -S react react-dom

wepack.config.base.js内容修改:

module: {
    rules: [
      {
--        test: /\.jsx?$/,
++        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
           -- plugins: ['@babel/plugin-transform-runtime'],
           ++ presets: [
               	['@babel/preset-env',
                 {
                     useBuiltIns: 'usage',
                     corejs: 3
                 }
             	],
               '@babel/preset-react'
              ],
            plugins: ['@babel/plugin-transform-runtime'],
            cacheDirectory: true,
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      -- title: 'webpack5从0到1搭建React开发脚手架',
      template: path.resolve(__dirname, '../index.html'),
    })
  ]

根目录增加index.html模板

<!DOCTYPE html>
<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>webpack5从0到1搭建React开发脚手架</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

新建src/App.jsx和src/index.js进行React基本测试

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));

App.jsx:

import React from 'react';

export default function App() {
  return <div>
    react jsx!
  </div>
}

# 5.1 解析扩展名

import Counter from './components/counter';能解析到counter下的入口文件。

webpack.config.base.js:

resolve: {

extensions: ['.js', '.jsx'],

},

# 6. 配置Sass-loader及抽取压缩css

npm install -S sass sass-loader css-loader style-loader

npm install -D mini-css-extrat-plugin css-minimizer-webpack-plugin

开发模式下:

不用抽离和压缩css。

webpack.config.dev.js:

module: {
    rules: [
      {
        test: /\.(css|scss|sass)$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      }
    ]
  },

生成模式下:

有必要抽离和压缩css。

webpack.config.build.js:

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

module: {
    rules: [
      {
        test: /\.(css|scss|sass)/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles/[contenthash].css'
    })
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  }

# 6.1 配置postcss

npm install -D postcss-loader postcss postcss-preset-env

修改配置文件:webpack.config.dev/build.js

rules: [
      {
        test: /\.(css|scss|sass)$/,
        use: [
          'style-loader', 'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  ['postcss-preset-env']
                ]
              }
            }
          },
          'sass-loader'
        ]
      }
    ]

# 7. 配置图片资源解析 AssetModules

webpack5新增的4种AssetModules类型,可以用来代替以往的file-loader、url-loader

webpack.config.base.js新增:

      {
        test: /\.(png|jpg|jpeg|gif)$/,
        type: 'asset/resource',
        generator: {
          filename: 'images/[contenthash][ext]'
        }
      },
      {
        test: /\.svg$/,
        type: 'asset',
        generator: {
          filename: 'images/[contenthash][ext]',
        },
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024
          }
        }
      }

# 8. 配置字体图标

以阿里字体图标为例子。https://www.iconfont.cn/下载字体文件。

# 8.1 Symbol方式接入(推荐方式):

第一步:引入项目下面生成的 symbol 代码:

# <script src="./iconfont.js"></script>

React中推荐用模块方式导入:
import './iconfont.js'

第二步:加入通用 CSS 代码(引入一次就行):

<style>
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

第三步:挑选相应图标并获取类名,应用于页面:推荐封装成组件

<svg class="icon" aria-hidden="true">
  <use xlink:href="#icon-xxx"></use>
</svg>

这一步有注意事项:
1. xlink:href要改成camelCase,即:xlinKHref。

# 8.2 font-class引用:

webpack.config.base.js:

{
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name][ext]',
        }
      }

第一步:引入字体图标文件:

# 新建font文件夹,放入iconfont.ttf等字体文件
# 修改iconfont.css字体图标文件路径:
@font-face {
  font-family: "iconfont"; /* Project id  */
  src: url('./font/iconfont.ttf?t=1638679880337') format('truetype');
}

第二步:引入项目下面生成的 fontclass 代码:

<link rel="stylesheet" href="./iconfont.css">

第三步:挑选相应图标并获取类名,应用于页面:

<span class="iconfont icon-xxx"></span>

# 9. 配置编译目标target

package.json: 编译后的文件支持哪些浏览器版本

"browserslist": [
    "last 2 versions",
    "> 1%",
    "IE 10"
  ],

webpack.config.base.js:

target: 'browserslist',

# 10. 配置ESLint

可以安装eslint-loader进行eslint规范提示。

为了能在编写代码的同时查看到Eslint提示,推荐以下配置方式。

第一步:安装Eslint插件。(vscode插件市场安装即可)

第二步:安装eslint包。

npm install -D eslint

第三步:生成eslint配置文件.

npx eslint --init
# 根据提示完成选择即可
# 过程中可能会安装一些lint插件,比如react hooks相关的lint插件。

第四步:修改eslint配置文件如下:

以下是完成react hooks的规则,其他规则可自行在rules下定义。

生成配置文件时可以选择.json.js.yaml几种格式,以下使用的是.json方式

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "plugin:react/recommended",
        "plugin:react-hooks/recommended"
    ],
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "react-hooks/rules-of-hooks": "error",
        "react-hooks/exhaustive-deps": "warn",
        "no-console": "warn"}
}

第五步:忽略不需要进行eslint检查的文件或文件夹

.eslint.json文件同级目录新建.eslintignore文件。

build

# 11. 配置打包压缩

生成环境有可能需要将打包结果进行压缩。

npm install -D filemanager-webpack-plugin

webpack.config.build.js增加:

const FileManagerPlugin = require('filemanager-webpack-plugin');

# plugins增加:
new FileManagerPlugin({
  events: {
    onEnd: {
      copy: [{
        source: path.resolve(__dirname, '../src/text.json'),
        destination: 'dist/text.json'
      }],
      archive: [
        {
          source: path.resolve(__dirname, '../dist'),
          destination: `dist/production_${new Date().getTime()}.tar.gz`,
          format: 'tar',
          options: {
            gzip: true,
            gzipOptions: {
              level: 1,
            },
            globOptions: {
              nomount: true,
            },
          }
        }
      ]
    }
  },
  runTasksInSeries: true,
})

# 12. 一些优化

  1. 输出js路径及名称,。

    webpack.config.base.js:

    output: {
        filename: 'scripts/[name].[contenthash].boundle.js',
        path: path.resolve(__dirname, '../dist'),
        pathinfo: false,
        clean: true,
      },
    
  2. 将src目录定义一个别名,简短模块化导入路径。

    webpack.config.base.js:

    resolve: {
        extensions: ['.js', '.jsx'],
        alias: {
          '@': path.resolve(__dirname, '../src')
        }
      },
    
  3. optimization配置优化。

    webpack.config.build.js:

    optimization: {
        runtimeChunk: true,
        minimizer: [
          new CssMinimizerPlugin()
        ],
        splitChunks: {
          chunks: 'all',
          cacheGroups: {
            commons: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendors',
              chunks: 'all',
            },
          },
        }
      }
    
作者:王龙楷; 标签:原创; 提交时间: 12/26/2021, 12:26:44 PM