使用 @craco/craco 来自定义 React 配置

1,666 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

使用 CRA 脚手架创建的 React 项目,如果想要修改编译配置项,就需要通过npm run eject弹出配置后在官方原本的配置上进行魔改,同时 eject 操作是不可逆的,在配置弹出后,你后续将无法跟随官方的脚本去升级react-script版本。

这种魔改的方式对于不太熟悉webpack的人来说,也很难容易找到对应的配置参数。为了改变这个局面我便出现了以下几种修改配置的方式:

  1. 通过 CRA 官方支持的 --scripts-version 参数,创建项目时使用自己重写过后的reat-scripts包。
  2. 使用 react-app-rewired + customize-cra 组合覆盖配置。
  3. 使用@craco/craco覆盖配置,该方式相较于第二种方式来说,配置更为简单。

配置步骤

  1. 安装@craco/craco

    yarn add @craco/craco -D
    
  2. 修改package.json中的scripts

    {
        "scripts": {
            "start": "craco start",
            "build": "craco build",
            "test": "craco test"
        }
    }
    
  3. 项目根目录下创建craco.config.js文件。

    /*craco.config.js */
    module.export = {
        /* ...... */
    }
    

    image.png

@craco/craco有暴露出几个函数,分别在不同的环境下执行。when的话可以自己指定环境。需要三个参数,而其他的分别为两个,一个为执行的函数,另一个参数是在不满足条件时的值。

const { when, whenDev } = require("@craco/craco");

// 配置在开发环境需要用到的插件
const whenDevPlugin = whenDev(()=> {
    return [new CircularDependencyPlugin()]
},[])

module.exports = {
    eslint: {
        mode: ESLINT_MODES.file,
        configure: {
            formatter: when(process.env.NODE_ENV === "CI", require("eslint-formatter-vso"))
        }
    },
    webpack: {
        plugins: [
            new ConfigWebpackPlugin(),
            ...whenDevPlugin
        ]
    }
};

接下来就是按照自己的需求,来对官方默认的webpack配置进行覆盖。

常用配置

修改打包输出目录

module.exports = {
    webpack: {
        configure:{
            output: {
                publicPath: '/',
                path: path.resolve(__dirname, 'dist'), // 修改输出文件目录
            }
        },
    }
}

路径别名

module.exports = {
    // 路径别名配置
    alias: {
        '@': pathResolve('src'),
        "@assets": pathResolve('src/assets'),
        "@common": pathResolve('src/common'),
        "@components": pathResolve('src/components'),
        "@hooks": pathResolve('src/hooks'),
        "@pages": pathResolve('src/pages'),
        "@store": pathResolve('src/store'),
        "@utils": pathResolve('src/utils')
    },
}

显示编译进度

yarn add webpackbar -D
const WebpackBar = require("webpackbar");  // webpack 编译进度条
module.exports = {
    webpack:{
          plugins: {
              add: [
                  new WebpackBar({
                      name: "webpack开始构建......",
                      color: "#2d56f8",
                      profile: true
                  })
              ]
          }
    }
}

Kapture 2022-10-27 at 15.36.39.gif

循环依赖检查

yarn add circular-dependency-plugin -D
const { whenDev} = require("@craco/craco")
const CircularDependencyPlugin = require('circular-dependency-plugin')
const whenDevPlugin = whenDev(() => ([
    // 循环依赖检查
    new CircularDependencyPlugin({
        exclude: /node_modules/,
        include: /src/,
        failOnError: true,
        allowAsyncCycles: false,
        cwd: process.cwd()
    })
]), [])

显示打包模块报告

yarn add webpack-bundle-analyzer -D
const {whenDev, whenProd} = require("@craco/craco")
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
// 开发环境用到的插件
const whenDevPlugin = whenDev(() => ([
    new CircularDependencyPlugin({
        exclude: /node_modules/,
        include: /src/,
        failOnError: true,
        allowAsyncCycles: false,
        cwd: process.cwd()
    }),
    new webpack.HotModuleReplacementPlugin()
]), [])
// 生产环境需要用到的插件
const whenProdPlugin = whenProd(() => ([
    new BundleAnalyzerPlugin(),
]), [])
const isDev = process.env.NODE_ENV === "development"
module.exports = {
    webpack: {
        plugins: {
            add: [
                // webpack 构建进度条
                new WebpackBar({
                    name: "webpack开始构建......",
                    color: "#2d56f8",
                    profile: true
                }),
                ...isDev ? whenDevPlugin : whenProdPlugin
            ],
        },
    }
}

image.png

开启gizp压缩

项目打包后,一般体积还是比较大的,加载资源稍微有些慢,所以要对此优化。 首先 web 服务器和客户端必须支持gizp,即请求头的Accept-Language包含gzip,返回头的Conten-Encoding 也包含 gzip

如果在服务端开启gizp压缩的话,如果文件比较大,还是比较耗费服务器资源的,整个过程也是比较久的,会导致用户体验不好。

另一种方案就是,在打包的时候生成gizp资源,服务端负责将生成的.gz文件返给客户端。

image.png

const CompressionWebpackPlugin = require("compression-webpack-plugin");
const whenProdPlugin = whenProd(() => ([
    new BundleAnalyzerPlugin(),
    new CompressionWebpackPlugin()
]), [])

UglifyJS Webpack Plugin

UglifyJS Webpack Plugin插件用来缩小(压缩优化)js文件。

module.exports = {
    webpack: {
        configure: {
            optimization: {
                minimizer: [new UglifyJsPlugin({
                    test: /.js(?.*)?$/i,  // 测试匹配文件,
                    cache: false,   // 是否启用文件缓存
                    parallel: true,  // 使用多进程并行运行来提高构建速度
                    uglifyOptions: {
                        warning: false,
                        compress: {
                            drop_debugger: true, // 清除debugger
                            drop_console: false, // 是否清除所有console
                            pure_funcs: ["console.log", "console.info"],    // 需要清除的console
                        },
                    },
                })]
            }
        }
    }
}