likes
comments
collection
share

一篇教你学会如何用Webpack从零搭建一个React脚手架

作者站长头像
站长
· 阅读数 14

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情

前言

前面已经学习了一些webpack的基本配置,然后下面用学过的一些配置来搭建一个React脚手架!

开发模式下webpack配置

// webpack.dev.js
const path = require('path')
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    "style-loader",
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};
module.exports = {
  entry: './src/main.js',
  output: {
    path: undefined, //开发环境不需要指定输出目录
    filename: 'static/js/[name].js', // 输出的文件名
    chunkFilename: 'static/js/[name].chunk.js', // 动态导入的文件打包输出的文件名
    assetModuleFilename: 'static/media/[name][hash:10][ext][query]', // 图片等公共资源打包后的名字
  },
  module: {
    rules: [
      /**
       * 样式资源处理
       */
      {
        test: /\.css$/,
        use: getStyleLoaders()
      },
      {
        test: /\.less$/,
        use: getStyleLoaders("less-loader"),
      },
      {
        test: /\.s[ac]ss$/,
        use: getStyleLoaders("sass-loader"),
      },
      {
        test: /\.styl$/,
        use: getStyleLoaders("stylus-loader"),
      },
      /**
       * 图片资源处理
       */
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
      },
      /**
       * 字体图标处理
       */
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource", // 原封不动输出
      },
      /**
       * js资源处理
       */
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: 'babel-loader',
        options: {
          cacheDirectory: true, // 开启babel编译缓存
          cacheCompression: false, // 缓存文件不要压缩
          plugins: [
            'react-refresh/babel' // js热替换HMR
          ]
        }
      }
    ]
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),// 要处理的文件范围
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"), // 缓存目录
    }),
    // 处理html资源
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new ReactRefreshWebpackPlugin()
  ],
  optimization: {
    splitChunks: {
      chunks: "all", // 代码分割
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}`,
    },
  },
  mode: "development",
  devtool: "cheap-module-source-map",
  // webpack解析模块加载选项
  resolve: {
    // 自动补全扩展名
    extensions: [".jsx", ".js", ".json"]
  },
  // 自动化配置
  devServer: {
    open: true, // 是否自动打开浏览器
    host: "localhost",
    port: 4000,
    hot: true, // 热模块替换
    historyApiFallback: true, // 解决react-router刷新404问题
  },
}
// package.json
{
  "name": "react-deom",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "npm run dev",
    "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.20.5",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
    "babel-loader": "^9.1.0",
    "babel-preset-react-app": "^10.0.1",
    "cross-env": "^7.0.3",
    "css-loader": "^6.7.2",
    "eslint": "^8.29.0",
    "eslint-config-react-app": "^7.0.1",
    "eslint-webpack-plugin": "^3.2.0",
    "html-webpack-plugin": "^5.5.0",
    "less": "^4.1.3",
    "less-loader": "^7.3.0",
    "postcss-loader": "^7.0.2",
    "postcss-preset-env": "^7.8.3",
    "react-refresh": "^0.14.0",
    "sass": "^1.56.1",
    "sass-loader": "^4.1.1",
    "style-loader": "^3.3.1",
    "stylus-loader": "^7.1.0",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-cli": "^0.3.1",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.4.4"
  }
}
// eslintrc.js
module.exports = {
  extends: ["react-app"], // 继承 react 官方规则
  parserOptions: {
    babelOptions: {
      presets: [
        // 解决页面报错问题
        ["babel-preset-react-app", false],
        "babel-preset-react-app/prod",
      ],
    },
  },
};
// babel.config.js
module.exports = {
  // 用来编译ES6的语法
  presets: ["react-app"],
}

开发模式配置的一些问题

热替换(HMR)

webpack从入门到原理(高级二)——HMR和oneOf(提高打包构建速度)写了当css已经通过style-loader实现了热替换,但是js是通过module.hot.accept("");来实现的,在实际开发中会使用其他的loader来解决这个问题,所以我们需要配置React热更新插件

安装:

npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
// 配置

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
......
rules: [
    test: /\.jsx?$/,
    loader: 'babel-loader',
    options: {
        cacheDirectory: true, // 开启babel编译缓存
        cacheCompression: false, // 缓存文件不要压缩
        plugins: [
        'react-refresh/babel' // js热替换HMR
        ]
    }
]
......
plugins:[
    new ReactRefreshWebpackPlugin()
]
devServer: {
    hot: true, // 热模块替换
    ......
},

配置完成之后就可以进行js的热更新替换了,效果如下图:

一篇教你学会如何用Webpack从零搭建一个React脚手架

前端路由刷新404

参考官方文档 当使用HTML5 History API时,如果页面返回404,启用devServer。historyApiFallback设置为true,就会页面404时返回index.html页面。

// 配置
......
devServer: {
    historyApiFallback: true, // 解决react-router刷新404问题
}

生产模式下webpack配置

生产模式在开发模式基础上进行修改了如下配置:

  • 打包输出目录
  • 增加了contenthash来更好地做文件缓存
  • 设置了clean打包时清空上一次打包的文件
  • 提取样式成单独文件
  • 压缩了css和js文件
  • 压缩图片
  • 更改mode模式和devtool
  • 删除devServer配置
  • 删除HMR热替换功能
  • 增加了copy插件
  • 配置了打包指令
// webpack.prod.js
/*
 * @Author: fdhou
 * @Date: 2022-12-06 14:50:19
 * @LastEditors: fdhou
 * @LastEditTime: 2022-12-07 15:46:08
 * @Description: 开发环境webpack配置
 */
const path = require('path')
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'static/js/[name].[hash:10].js', // 输出的文件名
    chunkFilename: 'static/js/[name].chunk.js', // 动态导入的文件打包输出的文件名
    assetModuleFilename: 'static/media/[name][hash:10][ext][query]', // 图片等公共资源打包后的名字
    clean: true,
  },
  module: {
    rules: [
      /**
       * 样式资源处理
       */
      {
        test: /\.css$/,
        use: getStyleLoaders()
      },
      {
        test: /\.less$/,
        use: getStyleLoaders("less-loader"),
      },
      {
        test: /\.s[ac]ss$/,
        use: getStyleLoaders("sass-loader"),
      },
      {
        test: /\.styl$/,
        use: getStyleLoaders("stylus-loader"),
      },
      /**
       * 图片资源处理
       */
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
      },
      /**
       * 字体图标处理
       */
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource", // 原封不动输出
      },
      /**
       * js资源处理
       */
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: 'babel-loader',
        options: {
          cacheDirectory: true, // 开启babel编译缓存
          cacheCompression: false, // 缓存文件不要压缩
        }
      }
    ]
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),// 要处理的文件范围
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"), // 缓存目录
    }),
    // 处理html资源
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[hash:10].css",
      chunkFilename: "static/css/[name].[hash:10].chunk.css",
    }),
    new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../public'),
          to: path.resolve(__dirname, '../dist'),
          globOptions: {
            ignore: ["**/index.html"], // 忽略这个文件
          },
        },
      ],
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: "all", // 代码分割
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}`,
    },
    minimizer: [
      new CssMinimizerWebpackPlugin(),
      new TerserWebpackPlugin(),
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ]
  },
  mode: "production",
  devtool: "source-map",
  // webpack解析模块加载选项
  resolve: {
    // 自动补全扩展名
    extensions: [".jsx", ".js", ".json"]
  }
}
// package.json
{
  "name": "react-deom",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "npm run dev",
    "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.20.5",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
    "babel-loader": "^9.1.0",
    "babel-preset-react-app": "^10.0.1",
    "copy-webpack-plugin": "^11.0.0",
    "cross-env": "^7.0.3",
    "css-loader": "^6.7.2",
    "css-minimizer-webpack-plugin": "^4.2.2",
    "eslint": "^8.29.0",
    "eslint-config-react-app": "^7.0.1",
    "eslint-webpack-plugin": "^3.2.0",
    "html-webpack-plugin": "^5.5.0",
    "image-minimizer-webpack-plugin": "^3.8.1",
    "imagemin": "^8.0.1",
    "less": "^4.1.3",
    "less-loader": "^7.3.0",
    "mini-css-extract-plugin": "^2.7.2",
    "postcss-loader": "^7.0.2",
    "postcss-preset-env": "^7.8.3",
    "react-refresh": "^0.14.0",
    "sass": "^1.56.1",
    "sass-loader": "^4.1.1",
    "style-loader": "^3.3.1",
    "stylus-loader": "^7.1.0",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-cli": "^0.3.1",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.4.4"
  }
}

生产模式下的一些问题

public目录下一些资源的打包

在我们打包的时候HTML资源是原封不动的进行打包的,并不会进行解析,如果在index.html中引入了一些图标、公共样式等文件,这样他们在打包的时候并不会被打打包进去!所以我们需要安装一个插件将public目录下的内容原封不动复制一份到dist目录下。copy-webpack-plugin

安装

npm i copy-webpack-plugin
// 配置 webpack.prod.js
const CopyPlugin = require("copy-webpack-plugin");
plugins:[
new CopyPlugin({
  patterns: [
    {
      from: path.resolve(__dirname, '../public'),
      to: path.resolve(__dirname, '../dist'),
      globOptions: {
        ignore: ["**/index.html"], // 忽略这个文件
      },
    },
  ],
})

配置完成之后重新进行打包,public目录下的公共资源就会被复制到dist目录下完成打包!注意要忽略掉index.html,避免重复打包报错!

前端路由刷新404

(手动狗头!)生产模式下因为没有用到webpack的devServer配置,所以不能够在页面404时显示index.html,需要在代码上线打包部署的时候会有专门的配置来解决这个问题,我还不会(哈哈哈哈哈哈哈),等我学会了再写!

开发模式生产模式配置合并

通过上面开发模式和生产模式的配置,发现有很多配置是一样的,这样就导致了很多的重复,所以为了增强代码的复用性同时减小代码的体积,那么就需要进行代码合并!

主要就是通过process.env.NODE_ENV去获取环境变量,来判断是生产环境运行还是开发环境运行!
// 合并后 webpack.config.js
/*
 * @Author: fdhou
 * @Date: 2022-12-06 14:50:19
 * @LastEditors: fdhou
 * @LastEditTime: 2022-12-08 10:43:06
 * @Description: 开发环境webpack配置
 */
const path = require('path')
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === 'production'
// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    isProduction ? MiniCssExtractPlugin.loader : "style-loader",
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    preProcessor && {
      loader: preProcessor,
      options:
        preProcessor === "less-loader" ?
          {
            lessOptions: {
              modifyVars: { '@primary-color': '#1DA57A' },
              javascriptEnabled: true,
            },
          } : {},
    },
  ].filter(Boolean);
};
module.exports = {
  entry: './src/main.js',
  output: {
    path: isProduction ? path.resolve(__dirname, '../dist') : undefined,
    filename: isProduction ? 'static/js/[name].[hash:10].js' : 'static/js/[name].js', // 输出的文件名
    chunkFilename: isProduction ? 'static/js/[name].[hash:10].chunk.js' : 'static/js/[name].chunk.js', // 动态导入的文件打包输出的文件名
    assetModuleFilename: 'static/media/[name][hash:10][ext][query]', // 图片等公共资源打包后的名字
    clean: isProduction ? true : false,
  },
  module: {
    rules: [
      /**
       * 样式资源处理
       */
      {
        test: /\.css$/,
        use: getStyleLoaders()
      },
      {
        test: /\.less$/,
        use: getStyleLoaders("less-loader"),
      },
      {
        test: /\.s[ac]ss$/,
        use: getStyleLoaders("sass-loader"),
      },
      {
        test: /\.styl$/,
        use: getStyleLoaders("stylus-loader"),
      },
      /**
       * 图片资源处理
       */
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
      },
      /**
       * 字体图标处理
       */
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource", // 原封不动输出
      },
      /**
       * js资源处理
       */
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: 'babel-loader',
        options: {
          cacheDirectory: true, // 开启babel编译缓存
          cacheCompression: false, // 缓存文件不要压缩
          plugins: [
            !isProduction && 'react-refresh/babel' // js热替换HMR
          ].filter(Boolean)
        }
      }
    ]
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),// 要处理的文件范围
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"), // 缓存目录
    }),
    // 处理html资源
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    isProduction && new MiniCssExtractPlugin({
      filename: "static/css/[name].[hash:10].css",
      chunkFilename: "static/css/[name].[hash:10].chunk.css",
    }),
    isProduction && new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../public'),
          to: path.resolve(__dirname, '../dist'),
          globOptions: {
            ignore: ["**/index.html"], // 忽略这个文件
          },
        },
      ],
    }),
    !isProduction && new ReactRefreshWebpackPlugin()
  ].filter(Boolean),
  optimization: {
    splitChunks: {
      chunks: "all", // 代码分割
      cacheGroups: {
        // react react-dom react-router-dom 一起打包成单独文件
        react: {
          test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
          name: "chunk_react", // 包名、
          priority: 40, // 权重需要比node_moduels,否则会直接打包到ode_moduels里面了
        },
        // antd打包成单独文件
        antd: {
          test: /[\\/]node_modules[\\/]antd(.*)?[\\/]/,
          name: "chunk_antd", // 包名、
          priority: 30, // 权重需要比node_moduels,否则会直接打包到ode_moduels里面了
        },
        // 剩下node_modules的在单独打包成一个文件
        lib: {
          test: /[\\/]node_modules[\\/]/,
          name: "chunk_libs", // 包名、
          priority: 20,
        }

      }
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}`,
    },
    // 是否需要进行压缩
    minimize: isProduction,
    minimizer: [
      new CssMinimizerWebpackPlugin(),
      new TerserWebpackPlugin(),
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ]
  },
  mode: isProduction ? "production" : 'development',
  devtool: isProduction ? "source-map" : "cheap-module-source-map",
  // webpack解析模块加载选项
  resolve: {
    // 自动补全扩展名
    extensions: [".jsx", ".js", ".json"]
  },
  // 自动化配置
  devServer: {
    open: true, // 是否自动打开浏览器
    host: "localhost",
    port: 4000,
    hot: true, // 热模块替换
    historyApiFallback: true, // 解决react-router刷新404问题
  },
  performance: false, // 关闭性能分析,提示速度
}

完成以上更改之后可以分别运行npm startnpm run build进行测试:

一篇教你学会如何用Webpack从零搭建一个React脚手架

一篇教你学会如何用Webpack从零搭建一个React脚手架

优化配置

自定义主题配置

在开发的时候我们会用到一些库,比如Antd,So下面介绍一下对Antd的一些配置。

安装

npm i antd

安装完成之后在main.js中进行引入import 'antd/dist/antd',然后就可以开始使用了

一篇教你学会如何用Webpack从零搭建一个React脚手架

一篇教你学会如何用Webpack从零搭建一个React脚手架 在Antd中默认主题色是蓝色,假如我们需要改变主题色,那么就需要在webpack的配置中做一些更改,可以参考Antd官网,因为我是自己写的脚手架所以配置会有一点不同,配置如下,因为Antd的样式都是用less写的,所以需要修改less-loader的options选项,修改之后主题色就会全部发生变化,其他的主题颜色修改可以参考定制主题

// webpack.config.js
const getStyleLoaders = (preProcessor) => {
  return [
    isProduction ? MiniCssExtractPlugin.loader : "style-loader",
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    preProcessor && {
      loader: preProcessor,
      options:
        preProcessor === "less-loader" ?
          {
            lessOptions: {
              modifyVars: { '@primary-color': '#1DA57A' },
              javascriptEnabled: true,
            },
          } : {},
    },
  ].filter(Boolean);
};

注意: 在main.js中引入的时候需要修改引入为less:import 'antd/dist/antd.less'否则样式是不会生效的。

再次打包运行会发现主题色就更改成了绿色。

一篇教你学会如何用Webpack从零搭建一个React脚手架

代码体积优化

在运行npm run build将代码打包后,提示打包后文件体积太大,会导致加载文件的速度比较慢,影响页面加载性能,那么我们可以将代码进行分割,这样就可以减小每个文件的体积,也能更好的去做按需加载! 一篇教你学会如何用Webpack从零搭建一个React脚手架

一篇教你学会如何用Webpack从零搭建一个React脚手架

配置如下,我们可以在splitChunks中配置cacheGroups手动配置将代码进行拆分!

// webpack.config.js
......
splitChunks: {
  chunks: "all", // 代码分割
  cacheGroups: {
    // react react-dom react-router-dom 一起打包成单独文件
    react: {
      test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
      name: "chunk_react", // 包名
      priority: 40, // 权重需要比node_moduels,否则会直接打包到ode_moduels里面了
    },
    // antd打包成单独文件
    antd: {
      test: /[\\/]node_modules[\\/]antd(.*)?[\\/]/,
      name: "chunk_antd", // 包名
      priority: 30, // 权重需要比node_moduels,否则会直接打包到ode_moduels里面了
    },
    // 剩下node_modules的在单独打包成一个文件
    lib: {
      test: /[\\/]node_modules[\\/]/,
      name: "chunk_libs", // 包名
      priority: 20,
    }

  }
}

配置完成之后重新打包如下图文件已经被拆分:

一篇教你学会如何用Webpack从零搭建一个React脚手架

一篇教你学会如何用Webpack从零搭建一个React脚手架

tips

通过上面代码分割的方法已经将代码分割成小块,但是发现控终端还是在报warnings,看着有点烦(手动狗头!),那么下面就把它关掉,只需如下一行代码,终端立马successfully!

// webpack.config.js

performance: false, // 关闭性能分析,提示速度

小结

github链接如果下载安装依赖之后npm run build报如下错误只需要参照webpack从入门到原理(高级五)——减少打包代码体积重新安装一下压缩图片的插件即可!

一篇教你学会如何用Webpack从零搭建一个React脚手架

通过以上配置最终就完成了何用Webpack从零搭建一个React脚手架的过程,上面的大段代码都是配置完优化以及解决了遇到的问题的代码,可以直接使用!今天是更文的第19天,加油,我想要个暖脚宝(哈哈哈哈哈!)