craco.config.js 相关配置解析

3,828 阅读5分钟

8b4dc4e3-c8dd-4e3a-99a8-b407d4f74ba1.png

1、前导信息

众所周知,使用create-react-app(官方文档)构建项目时,会把webpack相关配置都隐藏起来了,若需要修改配置可以执行以下命令将配置文件弹出来,但此操作是不可逆

npm run eject

需要注意的是,执行 eject 后,你将不再享受 Create React App 提供的抽象和自动化功能,同时也需要自行处理配置和构建的相关问题。这意味着你对项目的配置和构建有更多的责任和掌控,但也能满足更灵活的定制需求。

为了在不eject的情况下自定义某些配置,使用craco(Create React App Configuration Override)插件就是其中一个比较常用的方案

2、配置详情(craco文档craco.js.org/docs/)

在安装@craco/craco之前我们先观察node_modules文件夹,可以发现有些我们所需要的包已经安装

image.png

这是因为执行 npm init react-app my-app 时自动安装了react-scripts插件,它为了我们集成了webpack\babel\postcss\lodash 等一系列常用的工具和配置,所以再自定义其他相关配置时我们可以安装需要的即可

2.1、安装@craco/craco

npm i @craco/craco -D

2.2、在项目根目录创建一个craco.config.js文件
2.2.1、配置less预处理器(项目中可以使用less文件及语法)

只需安装craco-less即可,查询craco-less的package.json可以发现项目中已经依赖了less,less-loader插件,所有我们只需安装craco-less即可

npm i craco-less -D

// craco.config.js文件
const CracoLessPlugin = require('craco-less')
module.exports = {
  //...
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: { // 配置可以参照webpack的less-loader具体配置
          lessOptions: {
            javascriptEnabled: true // 允许less文件中使用js表达式
          }
        }
      }
    }
  ],
  //...
}
2.2.2、配置移动端自适应postcss-pxtorem

项目初始化时已经安装了postcss postcss-loader,所以此处不需要在安装

npm i lib-flexible postcss-pxtorem -D

  • 入口文件index.tsx中引入lib-flexible

image.png

  • 配置postcss-pxtorem
// craco.config.js文件
const postcssPx2Rem = require('postcss-pxtorem')
module.exports = {
    //...
    style: {
        postcss: {
          mode: 'extends',
          loaderOptions: () => {
            return {
              postcssOptions: {
                ident: 'postcss',
                config: false,
                plugins: [
                  postcssPx2Rem({
                    rootValue: 37.5, // 设计稿尺寸/10
                    propList: ['*'], // 需要转换的样式属性,默认为 ['*'],即匹配所有属性
                    exclude: /node_modules/i // 排除掉node_modules中转换
                  })
                ]
              },
              sourceMap: false
            }
          }
        }
      },
  //...
}

image.png image.png

2.2.3、配置devserver(代理相关)
    // craco.config.js文件
    module.exports = {
        //...
        devServer: {
            port: 8888,
            hot: true,
            client: {
              overlay: false
            },
            // 配置代理解决跨域
            proxy: {
              '/': {
                target: process.env.REACT_APP_URL, // https://xxx.com
                changeOrigin: true,
                pathRewrite: {
                  '^/': ''
                }
              }
            }
        }
    //...
    }
2.2.3、配置webpack相关(别名及打包大小分析)
 // craco.config.js文件
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
  // ...
  webpack: {
    // 配置别名
    alias: {
      // 约定:使用 @ 表示 src 文件所在路径
      '@': path.resolve(__dirname, 'src')
    },
    
    plugins: [
      // 打包分析插件,需要分析时解开注释
      // [new BundleAnalyzerPlugin()]
    ],
   // ...
}
  • 包大小分析结果

image.png

2.2.3、配置webpack相关(拆包、打包路径等)
// craco.config.js文件
module.exports = {
  // ...
  webpack: {
    configure: webpackConfig => {
      // 生产环境配置
      if (isProd) {
        // 去除map文件
        webpackConfig.devtool = false
        // 拆包
        webpackConfig.optimization = {
          splitChunks: {
            chunks: 'async',
            minSize: 40000, // bite
            maxAsyncRequests: 10, // 最大异步请求数
            maxInitialRequests: 10, // 页面初始化最大异步请求数
            automaticNameDelimiter: '~', // 解决命名冲突
            name: false,
            cacheGroups: {
              antd: {
                name: 'chunk-antd',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](@ant-design|antd-mobile)[\\/]/,
                priority: -7
              },
              common: {
                name: 'chunk-common',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](react|react-dom|react-router|react-redux|react-router-dom|redux-persist|react-fastclick)[\\/]/,
                priority: -9
              },
              vendor: {
                name: 'chunk-vendor',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](axios|lodash|core-js|react-copy-to-clipboard|crypto-js|web-vitals)[\\/]/,
                priority: -10
              }
            }
          }
        }
        // 输出output
        webpackConfig.output = {
          ...webpackConfig.output,
          publicPath: './' // 打包资源引入路径--目前使用的是相对路径
        }
      }
      return webpackConfig
    }
  },
  // ...
 }
  • 拆包结果

image.png

  • 打包资源引入路径

image.png

2.2.4、配置生产环境打包后删除console
module.exports = {
     babel: {
        plugins: [
          // 生产环境只留console.error、warn,去除console.log
          [
            'babel-plugin-transform-remove-console',
            { exclude: isProd ? ['error', 'warn'] : ['error', 'warn', 'log'] }
          ]
        ]
      },
}
2.3、修改package.json文件的运行命令
"scripts": {  
    "start": "craco start"   // react-scripts start --> craco start  
    "build": "craco build"  // react-scripts build --> craco build
}

image.png

2.3.1、使用dotenv-cli加载开发、测试、生产不同环境的环境变量

npm i dotenv-cli -D

package.json 文件的配置
{
    "scripts": {
        "dev": "craco start",
        "prod": "dotenv -e .env.production craco start",
        "build:dev": "dotenv -e .env.development craco build",
        "build:test": "dotenv -e .env.test craco build",
        "build:prod": "dotenv -e .env.production craco build",
        "eject": "react-scripts eject",
        "lint": "eslint -c .eslintrc.js src --ext .ts,.tsx,.js,.jsx --fix",
        "clean": "rimraf node_modules"
      },
 }

image.png

  • craco.config.js 的全部配置(拆包模块为本项目所使用的一些包,可自行修改)
/* eslint-disable @typescript-eslint/no-var-requires */
//对webpack配置别名
const path = require('path')
require('react-scripts/config/env')
const url = process.env.REACT_APP_URL
// 移动端rem适配
const CracoLessPlugin = require('craco-less')
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const isProd = process.env.NODE_ENV === 'production'
const postcssPx2Rem = require('postcss-pxtorem')

module.exports = {
  // webpack 配置
  webpack: {
    // 配置别名
    alias: {
      // 约定:使用 @ 表示 src 文件所在路径
      '@': path.resolve(__dirname, 'src')
    },
    plugins: [
      // 打包分析插件,需要分析时解开注释
      // [new BundleAnalyzerPlugin()]
    ],

    configure: webpackConfig => {
      // 生产环境配置
      if (isProd) {
        // 去除map文件
        webpackConfig.devtool = false
        // 拆包
        webpackConfig.optimization = {
          splitChunks: {
            chunks: 'async',
            minSize: 40000, // bite
            maxAsyncRequests: 10, // 最大异步请求数
            maxInitialRequests: 10, // 页面初始化最大异步请求数
            automaticNameDelimiter: '~', // 解决命名冲突
            name: false,
            cacheGroups: {
              antd: {
                name: 'chunk-antd',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](@ant-design|antd-mobile)[\\/]/,
                priority: -7
              },
              common: {
                name: 'chunk-common',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](react|react-dom|react-router|react-redux|react-router-dom|redux-persist|react-fastclick)[\\/]/,
                priority: -9
              },
              vendor: {
                name: 'chunk-vendor',
                chunks: 'all',
                test: /[\\/]node_modules[\\/](axios|lodash|core-js|react-copy-to-clipboard|crypto-js|web-vitals)[\\/]/,
                priority: -10
              }
            }
          }
        }
        // 输出
        webpackConfig.output = {
          ...webpackConfig.output,
          publicPath: './'
        }
      }
      return webpackConfig
    }
  },
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            javascriptEnabled: true // 允许less文件中使用js表达式
          }
        }
      }
    }
  ],
  style: {
    postcss: {
      mode: 'extends',
      loaderOptions: () => {
        return {
          postcssOptions: {
            ident: 'postcss',
            config: false,
            plugins: [
              postcssPx2Rem({
                rootValue: 37.5, // 设计稿尺寸/10
                propList: ['*'], // 需要转换的属性,默认为 ['*']
                exclude: /node_modules/i // 哪些文件不需要转换
              })
            ]
          },
          sourceMap: false
        }
      }
    }
  },
  babel: {
    plugins: [
      // 生产环境只留console.error、warn,去除console.log
      [
        'babel-plugin-transform-remove-console',
        { exclude: isProd ? ['error', 'warn'] : ['error', 'warn', 'log'] }
      ]
    ]
  },

  devServer: {
    port: 8888,
    // open: true,
    hot: true,
    client: {
      overlay: false
    },
    // 配置代理解决跨域
    proxy: {
      '/': {
        target: url,
        changeOrigin: true,
        pathRewrite: {
          '^/': ''
        }
      }
    }
  }
}

以上就是今天的全部内容了,如有错误,欢迎指正!