基于webpack开发react-cli

这篇具有很好参考价值的文章主要介绍了基于webpack开发react-cli。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在前面的章节中我们学习了webpack的基础配置(五大核心属性),以及一些高级优化配置(source map、Tree Shaking、 HMR、Code Split等),并且分别开发了webpack.dev.js(开发环境配置),和webpack.prod.js(生产环境配置)。

这一章节我们将两个配置合并为一个整体配置,内部差异通过process.env.NODE_ENV环境变量区分,并再结合一下react的插件,自己实现一个react-cli脚手架

一、react-cli开发步骤

1. webpack.dev.js和webpack.prod.js的配置
  • 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");

// 返回处理样式loader函数
const getStyleLoaders = (pre) => {
  return [
    "style-loader",
    "css-loader",
    {
      // 处理css兼容性问题
      // 配合package.json中browserslist来指定兼容性
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    pre,
  ].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/[hash:10][ext][query]",
  },
  module: {
    rules: [
      // 处理css
      {
        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: /\.(jpe?g|png|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      // 处理其他资源
      {
        test: /\.(woff2?|ttf)$/,
        type: "asset/resource",
      },
      // 处理js
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: "babel-loader",
        options: {
          cacheDirectory: true,
          cacheCompression: false,
          plugins: [
            "react-refresh/babel", // 激活js的HMR
          ],
        },
      },
    ],
  },
  // 处理html
  plugins: [
    new EslintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new ReactRefreshWebpackPlugin(), // 激活js的HMR
  ],
  mode: "development",
  devtool: "cheap-module-source-map",
  optimization: {
    splitChunks: {
      chunks: "all",
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}.js`,
    },
  },
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: [".jsx", ".js", ".json"],
  },
  devServer: {
    host: "localhost",
    port: 3000,
    open: true,
    hot: true, // 开启HMR
    historyApiFallback: true, // 解决前端路由刷新404问题
  },
};

  • webpack.prod.js
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");

// 返回处理样式loader函数
const getStyleLoaders = (pre) => {
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      // 处理css兼容性问题
      // 配合package.json中browserslist来指定兼容性
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    pre,
  ].filter(Boolean);
};

module.exports = {
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "../dist"),
    filename: "static/js/[name].[contenthash:10].js",
    chunkFilename: "static/js/[name].[contenthash:10].chunk.js",
    assetModuleFilename: "static/media/[hash:10][ext][query]",
    clean: true,
  },
  module: {
    rules: [
      // 处理css
      {
        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: /\.(jpe?g|png|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      // 处理其他资源
      {
        test: /\.(woff2?|ttf)$/,
        type: "asset/resource",
      },
      // 处理js
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: "babel-loader",
        options: {
          cacheDirectory: true,
          cacheCompression: false,
        },
      },
    ],
  },
  // 处理html
  plugins: [
    new EslintWebpackPlugin({
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[contenthash:10].css",
      chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
    }),
    new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, "../public"),
          to: path.resolve(__dirname, "../dist"),
          globOptions: {
            // 忽略index.html文件
            ignore: ["**/index.html"],
          },
        },
      ],
    }),
  ],
  mode: "production",
  devtool: "source-map",
  optimization: {
    splitChunks: {
      chunks: "all",
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}.js`,
    },
    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",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
  },
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: [".jsx", ".js", ".json"],
  },
};

2. 下载cross-env 获取环境变量,配置打包命令

npm i cross-env -D

更改package.json中的打包方式

  • package.json
"scripts": {
    "start": "npm run dev",
    "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
    "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
  },
3. 合并生产和开发配置为webpack.config.js

完整代码如下:

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";

// 返回处理样式loader函数
const getStyleLoaders = (pre) => {
  return [
    isProduction ? MiniCssExtractPlugin.loader : "style-loader",
    "css-loader",
    {
      // 处理css兼容性问题
      // 配合package.json中browserslist来指定兼容性
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: ["postcss-preset-env"],
        },
      },
    },
    pre && {
      loader: pre,
      options:
        pre === "less-loader"
          ? {
              // antd自定义主题配置
              // 主题色文档:https://ant.design/docs/react/customize-theme-cn#Ant-Design-%E7%9A%84%E6%A0%B7%E5%BC%8F%E5%8F%98%E9%87%8F
              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].[contenthash:10].js" : "static/js/[name].js", // 生产环境使用contenthash,开发环境使用hash
    chunkFilename: isProduction ? "static/js/[name].[contenthash:10].chunk.js" : "static/js/[name].chunk.js", 
    assetModuleFilename: "static/media/[hash:10][ext][query]", // 配置图片资源输出的文件名
    clean: true, // 每次打包前清除dist目录
  },
  module: {
    rules: [
      // 处理css
      {
        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: /\.(jpe?g|png|gif|webp|svg)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      // 处理其他资源
      {
        test: /\.(woff2?|ttf)$/,
        type: "asset/resource",
      },
      // 处理js
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: "babel-loader",
        options: {
          cacheDirectory: true,
          cacheCompression: false,
          plugins: [
            !isProduction && "react-refresh/babel", // 激活js的HMR
          ].filter(Boolean),
        },
      },
    ],
  },
  // 处理html
  plugins: [
    new EslintWebpackPlugin({ // eslint检查
      context: path.resolve(__dirname, "../src"), // 指定检查的目录
      exclude: "node_modules", // 指定排除的目录
      cache: true, // 开启缓存,提升eslint检查速度
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache"), // 指定缓存文件存放位置
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"), // 指定html模板
    }),
    isProduction &&
      new MiniCssExtractPlugin({ // 提取css为单独文件
        filename: "static/css/[name].[contenthash:10].css", // 提取的css文件名
        chunkFilename: "static/css/[name].[contenthash:10].chunk.css", // 提取的css chunk文件名
      }),
    isProduction &&
      new CopyPlugin({ // 将public目录下的文件拷贝到dist目录下
        patterns: [
          {
            from: path.resolve(__dirname, "../public"),
            to: path.resolve(__dirname, "../dist"),
            globOptions: {
              // 忽略index.html文件
              ignore: ["**/index.html"],
            },
          },
        ],
      }),
    !isProduction && new ReactRefreshWebpackPlugin(), // 开发环境开启HMR
  ].filter(Boolean),
  mode: isProduction ? "production" : "development",
  devtool: isProduction ? "source-map" : "cheap-module-source-map", // 配置source-map映射, 生产环境使用source-map,开发环境使用cheap-module-source-map
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        // react react-dom react-router-dom 一起打包成一个js文件
        react: {
          test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
          name: "chunk-react",
          priority: 40,
        },
        // antd 单独打包
        antd: {
          test: /[\\/]node_modules[\\/]antd[\\/]/,
          name: "chunk-antd",
          priority: 30,
        },
        // 剩下node_modules单独打包
        libs: {
          test: /[\\/]node_modules[\\/]/,
          name: "chunk-libs",
          priority: 20,
        },
      },
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}.js`, // 为每个入口添加一个runtime文件
    },
    // 是否需要进行压缩
    minimize: isProduction, // 生产环境压缩
    minimizer: [
      new CssMinimizerWebpackPlugin(), // 压缩css
      new TerserWebpackPlugin(), // 压缩js
      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",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
  },
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: [".jsx", ".js", ".json"],
  },
  devServer: {
    host: "localhost",
    port: 3000,
    open: true,
    hot: true, // 开启HMR
    historyApiFallback: true, // 解决前端路由刷新404问题
  },
  performance: false, // 关闭性能分析,提升打包速度
};

二、react-cli新增配置介绍

1. 定义生产环境变量
// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === "production";
2. 借助CopyPlugin ,将public目录下的文件拷贝到dist目录下
    const CopyPlugin = require("copy-webpack-plugin");
    plugins: [
     new CopyPlugin({ // 将public目录下的文件拷贝到dist目录下
        patterns: [
          {
            from: path.resolve(__dirname, "../public"),
            to: path.resolve(__dirname, "../dist"),
            globOptions: {
              // 忽略index.html文件
              ignore: ["**/index.html"],
            },
          },
        ],
      }),
    ]
   
3. 借助ReactRefreshWebpackPlugin 开启开发环境HMR
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
module:{
	rules:[
		// 处理js
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, "../src"),
        loader: "babel-loader",
        options: {
          cacheDirectory: true,
          cacheCompression: false,
          plugins: [
            !isProduction && "react-refresh/babel", // 激活js的HMR
          ].filter(Boolean),
        },
      },
	]
},
plugins: [
	!isProduction && new ReactRefreshWebpackPlugin(), // 开发环境开启HMR
]

4. 解析模块,自动补全扩展名
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: [".jsx", ".js", ".json"],
  },
5. 配置 historyApiFallback: true, 解决前端路由刷新404问题
  devServer: {
    host: "localhost",
    port: 3000,
    open: true,
    hot: true, // 开启HMR
    historyApiFallback: true, // 解决前端路由刷新404问题
  },
6. 关闭性能分析,提升打包速度
performance: false, // 关闭性能分析,提升打包速度
7. 通过cssloader自定义antd主题
pre && {
      loader: pre,
      options:
        pre === "less-loader"
          ? {
              // antd自定义主题配置
              lessOptions: {
                modifyVars: { "@primary-color": "#1DA57A" },
                javascriptEnabled: true,
              },
            }
          : {},
    },
8. 关闭多进程打包

在项目没有达到一定规模之前,开启多进程反而会减慢打包速度文章来源地址https://www.toymoban.com/news/detail-492761.html

9. 模块分离打包
cacheGroups: {
        // react react-dom react-router-dom 一起打包成一个js文件
        react: {
          test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
          name: "chunk-react",
          priority: 40,
        },
        // antd 单独打包
        antd: {
          test: /[\\/]node_modules[\\/]antd[\\/]/,
          name: "chunk-antd",
          priority: 30,
        },
        // 剩下node_modules单独打包
        libs: {
          test: /[\\/]node_modules[\\/]/,
          name: "chunk-libs",
          priority: 20,
        },
      }, 

到了这里,关于基于webpack开发react-cli的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 06 基于Vue+Vue-cli+webpack搭建渐进式高可维护性前端实战项目

         本文是专栏《 Vue + SpringBoot前后端分离项目实战 》的实战第一篇,将从Vue脚手架安装开始,逐步带你搭建起一套管理系统所需的架构。当然,在默认安装完成之后,会对文件目录进行初步的细化拆分,以便后续 功能迭代和维护 所用。 为兼顾大多数计算机毕设的需求,

    2024年02月16日
    浏览(36)
  • chrome插件:一个基于webpack + react的chrome 插件项目模板

    项目结构 主要的文件 manifest.json package.json 完整项目结构 完整代码:https://github.com/mouday/good-dev/

    2024年02月09日
    浏览(28)
  • Vue、Vue CLI、Webpack 和 Webpack CLI 的版本兼容对照表

    这些指南只是一些常见的版本兼容性指南。在实际项目中,取决于具体的应用场景和使用的组件库,不同版本之间可能还存在其它的兼容性问题。因此,我们建议使用最新版本的 Vue、Vue CLI、Webpack 和 Webpack CLI 来获得最佳的性能、安全性以及最新的功能和改进。同时,在使用

    2024年02月11日
    浏览(29)
  • webpack和webpack-cli安装和卸载

    安装: 1、全局安装:运行 npm i webpack -g 全局安装webpack,这样就能在全局使用webpack的命令 或者 npm install --global webpack   2、本地安装:在项目根目录中运行 npm i webpack --save-dev 安装到项目依赖中 3、webpack4.0以后版本,需要安装命令工具 npm install webpack-cli -g 或者 npm install --glo

    2024年02月09日
    浏览(33)
  • Vue CLI webpack 相关

    调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象: 该对象将会被 webpack-merge 合并入最终的 webpack 配置。 警告 有些 webpack 选项是基于 vue.config.js 中的值设置的,所以不能直接修改。例如你应该修改 vue.config.js 中的 outputDir 选项而不

    2023年04月23日
    浏览(23)
  • webpack -v报错:Cannot find module ‘webpack-cli/package.json‘

    -D安装了webpack和webpack-cli,-g安装了webpack和webpack-cli,但是webpack -v的时候仍然提示需要安装webpack-cli,并且安装之后会报错:  看提示应该是webpack-cli/package.json的位置获取不到正确的,但是并不知道为什么获取不到,查了一圈,最后看了这篇文章得到了启发:WebPack 安装出现

    2023年04月24日
    浏览(49)
  • 章节 1:入门React.js -《React.js手把手教程:从初学者到实战高手》- 第一部分:React.js基础

    《React.js手把手教程:从初学者到实战高手》 第一部分:React.js基础 在我们开始探索 React.js 的奇妙世界之前,让我们先来认识一下这个“ 人人都在谈论 ”的家伙。你可以把 React.js 想象成是一个全栈工程师的一大碗甜品,不仅好吃,还可以让你的应用更美味!那么,究竟什么

    2024年02月11日
    浏览(33)
  • webpack/vue-cli构建速度和打包体积优化

    webpack-bundle-analyzer 可以生成代码分析报告,可以直观地分析打包出的文件有哪些,及它们的大小、占比情况、各文件 Gzipped 后的大小、模块包含关系、依赖项等 npm i -D webpackbar webpack-bundle-analyzer javascript 复制代码 const { BundleAnalyzerPlugin } = require(\\\'webpack-bundle-analyzer\\\'); ​ module.e

    2024年01月19日
    浏览(37)
  • 【[TOC]([webpack-cli] Invalid configuration object. Webpack has been initialized using a configurati】

    翻译过来的意思: configuration.devtool配置应该符合 “^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$” 自 webpack 5 以来的重大更改:devtool 选项更加严格。 就是要把webpack devtool配置换成规定的 可以参考官方文档:https://webpack.js.org/configuration/devtool/ 我是在学习阶段,是用于

    2024年02月15日
    浏览(35)
  • Webstorm+Nodejs+webpack+vue-cli+Git搭建vue环境

    此笔记归纳整理webstorm搭建vue项目,仅作记录使用。   因为版权问题,就不再细说了。   选择nvm的安装路径:   选择node的安装路径:    Win键+R键 ,输入cmd,然后回车,打开命令行界面   进入命令提示符窗口,输入以下命令,显示版本号,则安装成功。   在

    2024年02月15日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包