背景

使用 CRA 脚手架创建的项目,如果想要修改编译配置,通常可能会选择 npm run eject 弹出配置后魔改。但是,eject 是不可逆操作,弹出配置后,你将无法跟随官方的脚步去升级项目的 react-script 版本。

如果想要无 eject 重写 CRA 配置,目前成熟的是下面这几种方式

  1. 通过 CRA 官方支持的 --scripts-version 参数,创建项目时使用自己重写过的 react-scripts 包
  2. 使用 react-app-rewired + customize-cra 组合覆盖配置
  3. 使用 craco 覆盖配置

第二种方式相对第三种略复杂一些,我自己很有体会并且我们注意到最新的AntDesign4 官方也开始推荐 craco 了,那我们还等什么还不快行动起来,今天主要在这里详细讨论一下 craco 的使用,也方便大家给出更好的建议。

配置步骤

  1. 首先,使用 create-react-app 创建一个项目,这里我们命名为 my-project
npx create-react-app my-project

  1. 进入项目目录,安装基本依赖
yarn add antd @craco/craco craco-less @babel/plugin-proposal-decorators babel-plugin-import -D

3、修改 package.json 中的 scripts

{"scripts":{"start": "set PORT=5000 && craco start FAST_REFRESH=true","build": "set GENERATE_SOURCEMAP=false && craco build","analyzer": "env NODE_ENV=production BUILD_ANALYZER=true yarn start","test": "craco test"}
}

4、项目根目录创建 craco.config.js 文件

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

上面用到了几个环境变量: PORT 启动端口 GENERATE_SOURCEMAP 打包时是否生成 sourceMap BUILD_ANALYZER 文件方式输出编译分析

基础的配置到此完成了,接下来是处理各种配置的覆盖,完整的 craco.config.js 配置文件结构,可以在 craco 官方的文档中详细查询:Configuration Overview 。

扩展 babel 配置

虽然可以在 configure 中定义 babel 配置,但 craco 也提供了快捷的方式单独去书写,添加 @babel/preset-env 配置示例如下:

/* craco.config.js */module.exports = {babel: {presets: [['@babel/preset-env',{modules: false, // 对ES6的模块文件不做转化,以便使用tree shaking、sideEffects等useBuiltIns: 'entry', // browserslist环境不支持的所有垫片都导入// https://babeljs.io/docs/en/babel-preset-env#usebuiltins// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.mdcorejs: {version: 3, // 使用core-js@3proposals: true,},},],],plugins: [// 配置 babel-plugin-import['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }, 'antd'],// 配置解析器["@babel/plugin-proposal-decorators", { "legacy": true }],["@babel/plugin-proposal-class-properties", { "loose": true }],["babel-plugin-styled-components", { "displayName": true }]],loaderOptions: {},loaderOptions: (babelLoaderOptions, { env, paths }) => { return babelLoaderOptions; }},
}

检测模块编译情况

new WebpackBar({ profile: true }),
new CircularDependencyPlugin({exclude: /node_modules/,include: /src/,failOnError: true,allowAsyncCycles: false,cwd: process.cwd()
})

观察打包进度

const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin')
module export = {webpack: {plugins: [// 查看打包的进度new SimpleProgressWebpackPlugin()]}
}

修改打包输出目录

module.exports = {webpack: {configure: (webpackConfig, {env, paths}) => {// paths.appPath='public'paths.appBuild = 'dist'webpackConfig.output = {...webpackConfig.output,// ...{//   filename: whenDev(() => 'static/js/bundle.js', 'static/js/[name].js'),//   chunkFilename: 'static/js/[name].js'// },path: path.resolve(__dirname, 'dist'), // 修改输出文件目录publicPath: '/'}return webpackConfig}}
}

如果觉得繁琐也可以直接使用webpack进行configure覆盖、webpackConfig的信息大概有这么多:

热更新Hot-loader扩展

启动热更新如何避免频繁刷新 常用的热更新方案 react-hot-loader、craco也帮我们提供了两种craco-plugin-react-hot-reloadcraco-fast-refresh

react-hot-loader配置如下(传送门)

step1:webpack.config.js中引入别名配置解除相关警告
yarn add @hot-loader/react-dom
module.exports = {// ...resolve: {alias: {'react-dom': '@hot-loader/react-dom',},},
};
step2:注入引用App.js
import { hot } from 'react-hot-loader/root'
function App {return (<div>ceshi</div>)
}
export default hot(App)

craco-plugin-react-hot-reload配置如下(传送门)

/* craco.config.js */
const reactHotReloadPlugin = require('craco-plugin-react-hot-reload')
const reactHotReloadPlugin = require('craco-plugin-react-hot-reload')
module.exports = {plugins: [{plugin: reactHotReloadPlugin}]
}

craco-fast-refresh 配置如下(传送门)

这是最近发现的新 craco plugin,相对于 react-hot-loader好用得多,零配置,不需要修改项目代码,据说性能也更好。

step1:增加插件
/* craco.config.js */
const FastRefreshCracoPlugin = require('craco-fast-refresh')
module.exports = () => {return {plugins: [{plugin: FastRefreshCracoPlugin}],};
};
step2: 注入引用App.js
import React from 'react'
import { hot } from 'react-hot-loader'
const App = () => <div>Hello World!</div>export default hot(module)(App)

Antd自定义主题配置

配置antd主题颜色可随意对以下方案就行选取

结合lessOptions

step1:运行 yarn add craco-less
step2:引入 const CracoLessPlugin = require('craco-less')
step3:配置
{plugin: CracoLessPlugin,options: {lessLoaderOptions: {lessOptions: {modifyVars: {'@primary-color': '#1DA57A'},javascriptEnabled: true}}}
}

同时craco 也提供了专门的 plugin 来处理 antd 的集成(传送门)配置方式有区别

Craco自定义支持

craco-antd includes: - Less (provided by craco-less) - babel-plugin-import to only import the required CSS, instead of everything - An easy way to customize the theme. Set your custom variables in ./antd.customize.less

step1: yarn add craco-antd
step2: const CracoAntDesignPlugin = require('craco-antd')
step3
{plugin: CracoAntDesignPlugin,options: {customizeTheme: {'@primary-color': '#FF061C'}}
}

针对customizeTheme 如果想单独抽离可采取如下方案

step1: 新建antd.customize.less文件
---------
@primary-color: #FF061C;
---------
step2:读取模式
{plugin: CracoAntDesignPlugin,options: {customizeThemeLessPath: path.join(__dirname,"antd.customize.less")}}

相对来讲使用会更简洁一些,推荐使用。

总结

确实能够在不 eject 弹出配置的情况下,能够自定义所有的 cra 构建配置,之前进行了详细的说明,有这方面的需求可以去看看(传送门)。因此在后续的编码中,我们可以随便使用这两种方式构建自己的webpack配置。 注意:_configure配置和_craco配置会互斥谨慎使用

以下,是我整理完整的 craco.config.js 配置,相应的demo方便参照 craco 还提供一些其他 plugin具体根据实际情况自行加入(传送门)

/* craco.config.js */
/*** TODO: 区分环境 —— NODE_ENV* - whenDev ☞ process.env.NODE_ENV === 'development'* - whenTest ☞ process.env.NODE_ENV === 'test'* - whenProd ☞ process.env.NODE_ENV === 'production'*/
const {when, whenDev, whenProd, whenTest, ESLINT_MODES, POSTCSS_MODES
} = require('@craco/craco')
const webpack = require('webpack')
const CracoLessPlugin = require('craco-less')
const CracoAntDesignPlugin = require('craco-antd')
const CracoVtkPlugin = require('craco-vtk')
const WebpackBar = require('webpackbar')
const CircularDependencyPlugin = require('circular-dependency-plugin')
const FastRefreshCracoPlugin = require('craco-fast-refresh')
const TerserPlugin = require('terser-webpack-plugin')
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin')
const {BundleAnalyzerPlugin
} = require('webpack-bundle-analyzer')
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const DashboardPlugin = require('webpack-dashboard/plugin')
const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin')const path = require('path')// 判断编译环境是否为生产
const isBuildAnalyzer = process.env.BUILD_ANALYZER === 'true'const pathResolve = pathUrl => path.join(__dirname, pathUrl)module.exports = {webpack: {// 别名配置alias: {'@': pathResolve('.'),src: 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')// 此处是一个示例,实际可根据各自需求配置},plugins: [// webpack构建进度条new WebpackBar({profile: true}),new webpack.IgnorePlugin(/^./locale$/, /moment$/),// 查看打包的进度new SimpleProgressWebpackPlugin(),// 时间转换工具采取day替换momentnew AntdDayjsWebpackPlugin(),// // 新增模块循环依赖检测插件...whenDev(() => [new CircularDependencyPlugin({exclude: /node_modules/,include: /src/,failOnError: true,allowAsyncCycles: false,cwd: process.cwd()}),// webpack-dev-server 强化插件new DashboardPlugin(),new webpack.HotModuleReplacementPlugin()], []),/*** 编译产物分析*  - https://www.npmjs.com/package/webpack-bundle-analyzer* 新增打包产物分析插件*/...when(isBuildAnalyzer, () => [new BundleAnalyzerPlugin({analyzerMode: 'static', // html 文件方式输出编译分析openAnalyzer: false,reportFilename: path.resolve(__dirname, `analyzer/index.html`)})], []),...whenProd(() => [// new TerserPlugin({//   // sourceMap: true, // Must be set to true if using source-maps in production//   terserOptions: {//     ecma: undefined,//     parse: {},//     compress: {//       warnings: false,//       drop_console: true, // 生产环境下移除控制台所有的内容//       drop_debugger: true, // 移除断点//       pure_funcs: ['console.log'] // 生产环境下移除console//     }//   }// }),// 打压缩包new CompressionWebpackPlugin({algorithm: 'gzip',test: new RegExp('.(' + ['js', 'css'].join('|') + ')$'),threshold: 1024,minRatio: 0.8})], [])],//抽离公用模块optimization: {splitChunks: {cacheGroups: {commons: {chunks: 'initial',minChunks: 2,maxInitialRequests: 5,minSize: 0},vendor: {test: /node_modules/,chunks: 'initial',name: 'vendor',priority: 10,enforce: true}}}},/*** 重写 webpack 任意配置*  - configure 能够重写 webpack 相关的所有配置,但是,仍然推荐你优先阅读 craco 提供的快捷配置,把解决不了的配置放到 configure 里解决;*  - 这里选择配置为函数,与直接定义 configure 对象方式互斥;*/configure: (webpackConfig, {env, paths}) => {// paths.appPath='public'paths.appBuild = 'dist' // 配合输出打包修改文件目录// webpackConfig中可以解构出你想要的参数比如mode、devtool、entry等等,更多信息请查看webpackConfig.json文件/*** 修改 output*/webpackConfig.output = {...webpackConfig.output,// ...{//   filename: whenDev(() => 'static/js/bundle.js', 'static/js/[name].js'),//   chunkFilename: 'static/js/[name].js'// },path: path.resolve(__dirname, 'dist'), // 修改输出文件目录publicPath: '/'}/*** webpack split chunks*/// webpackConfig.optimization.splitChunks = {//   ...webpackConfig.optimization.splitChunks,//   ...{//     chunks: 'all',//     name: true//   }// }// 返回重写后的新配置return webpackConfig}},babel: {presets: [],plugins: [// AntDesign 按需加载['import', {libraryName: 'antd',libraryDirectory: 'es',style: true}, 'antd'],['@babel/plugin-proposal-decorators', {legacy: true}] // 用来支持装饰器],loaderOptions: {},loaderOptions: (babelLoaderOptions, {env, paths}) => {return babelLoaderOptions}},/*** 新增 craco 提供的 plugin*/plugins: [// 热更新...whenDev(() => [{plugin: FastRefreshCracoPlugin}, {plugin: CracoVtkPlugin()}, {plugin: new AntdDayjsWebpackPlugin()}], []),// 方案1、配置Antd主题less// {//   plugin: CracoLessPlugin,//   options: {//     lessLoaderOptions: {//       lessOptions: {//         modifyVars: { '@primary-color': '#1DA57A' },//         javascriptEnabled: true//       }//     }//   }// },// 方案2、配置Antd主题// {//   plugin: CracoAntDesignPlugin,//   options: {//     customizeTheme: {//       '@primary-color': '#FF061C'//     }//   }// },// 方案3、配置Antd主题{plugin: CracoAntDesignPlugin,options: {customizeThemeLessPath: path.join(__dirname,"antd.customize.less"),},},],devServer: {port: 9000,proxy: {'/api': {target: 'https://placeholder.com/',changeOrigin: true,secure: false,xfwd: false,}}}
}

同时我们也可以看一下官方给我们暴露了哪些Api

const { when, whenDev, whenProd, whenTest, ESLINT_MODES, POSTCSS_MODES } = require("@craco/craco");module.exports = {reactScriptsVersion: "react-scripts" /* (default value) */,style: {modules: {localIdentName: ""},css: {loaderOptions: { /* Any css-loader configuration options: https://github.com/webpack-contrib/css-loader. */ },loaderOptions: (cssLoaderOptions, { env, paths }) => { return cssLoaderOptions; }},sass: {loaderOptions: { /* Any sass-loader configuration options: https://github.com/webpack-contrib/sass-loader. */ },loaderOptions: (sassLoaderOptions, { env, paths }) => { return sassLoaderOptions; }},postcss: {mode: "extends" /* (default value) */ || "file",plugins: [],env: {autoprefixer: { /* Any autoprefixer options: https://github.com/postcss/autoprefixer#options */ },stage: 3, /* Any valid stages: https://cssdb.org/#staging-process. */features: { /* Any CSS features: https://preset-env.cssdb.org/features. */ }},loaderOptions: { /* Any postcss-loader configuration options: https://github.com/postcss/postcss-loader. */ },loaderOptions: (postcssLoaderOptions, { env, paths }) => { return postcssLoaderOptions; }}},eslint: {enable: true /* (default value) */,mode: "extends" /* (default value) */ || "file",configure: { /* Any eslint configuration options: https://eslint.org/docs/user-guide/configuring */ },configure: (eslintConfig, { env, paths }) => { return eslintConfig; },loaderOptions: { /* Any eslint-loader configuration options: https://github.com/webpack-contrib/eslint-loader. */ },loaderOptions: (eslintOptions, { env, paths }) => { return eslintOptions; }},babel: {presets: [],plugins: [],loaderOptions: { /* Any babel-loader configuration options: https://github.com/babel/babel-loader. */ },loaderOptions: (babelLoaderOptions, { env, paths }) => { return babelLoaderOptions; }},typescript: {enableTypeChecking: true /* (default value)  */},webpack: {alias: {},plugins: [],configure: { /* Any webpack configuration options: https://webpack.js.org/configuration */ },configure: (webpackConfig, { env, paths }) => { return webpackConfig; }},jest: {babel: {addPresets: true, /* (default value) */addPlugins: true  /* (default value) */},configure: { /* Any Jest configuration options: https://jestjs.io/docs/en/configuration. */ },configure: (jestConfig, { env, paths, resolve, rootDir }) => { return jestConfig; }},devServer: { /* Any devServer configuration options: https://webpack.js.org/configuration/dev-server/#devserver. */ },devServer: (devServerConfig, { env, paths, proxy, allowedHost }) => { return devServerConfig; },plugins: [{plugin: {overrideCracoConfig: ({ cracoConfig, pluginOptions, context: { env, paths } }) => { return cracoConfig; },overrideWebpackConfig: ({ webpackConfig, cracoConfig, pluginOptions, context: { env, paths } }) => { return webpackConfig; },overrideDevServerConfig: ({ devServerConfig, cracoConfig, pluginOptions, context: { env, paths, proxy, allowedHost } }) => { return devServerConfig; },overrideJestConfig: ({ jestConfig, cracoConfig, pluginOptions, context: { env, paths, resolve, rootDir } }) => { return jestConfig },},options: {}}]
};

这么多的信息使用起来是不是很爽,想探索的赶快行动起来共同进步啦

参考

  • craco 配置
  • less-loader 官方文档
  • ant design 官方文档
  • craco实践

antd + react model自定义footer_更骚的create-react-app开发环境配置craco相关推荐

  1. antd + react model自定义footer_使用ESLint+Prettier规范React+Typescript项目

    项目开发过程中,大多数时候我们使用别人搭建好的脚手架编写代码,是项目的参与者.对于一些细节往往被忽略了.其中代码检测本身是一类非常简单的配置,但涉及不同框架和语言组合使用的时候,可能比想象中要困难,本 ...

  2. React + Typescript + Webpack 开发环境配置

    对于复杂或多人开发的 React 项目来说,管理和使用每个组件的 props . state 或许会成为一件让人头痛的事情,而为每一个组件写文档,成本也会比较大,对项目的开发效率也不是最理想的. Ty ...

  3. React Native开发环境配置检测

    安装依赖: 必须安装的依赖有:Node.Yarn, JDK 和 Android Studio. 安装过程中,请务必保持一颗良好的心态 1. 基础环境搭建 : Node: 安装参考连接:https:// ...

  4. antd走马灯组件自定义前进后退按钮

    antd走马灯组件自定义前进后退按钮[ts + react] antd的Carousel没有提供前进后退按钮需要自己根据文档 实现此功能 官方提供了next 和prev两个方法 next() 切换到下 ...

  5. uni-app简介、条件编译、App端Nvue开发、HTML5+、开发环境搭建、自定义组件、配置平台环境、uniCloud云开发平台

    uni-app简介 : 概述:uni-app是一个前端跨平台框架:会uni-app就可以用一套代码(类似vue语法)打包出安卓.ios.及各种小程序(微信.qq.支付宝等)端跨平台发布. 生态:完整的 ...

  6. php开发环境搭建套件,PHP开发环境套件与自定义安装方法介绍

    本文涉及的安装包下载地址,在文章最后附上. 1.在Window下搭建 (apache(iis)+ php + mysql+phpmyadmin) => wamp 2.在Linux linux + ...

  7. webpack搭建php服务器,webpack搭建react开发环境步骤详解

    这次给大家带来webpack搭建react开发环境步骤详解,webpack搭建react开发环境的注意事项有哪些,下面就是实战案例,一起来看一下.mkdir react-redux && ...

  8. 基于webpack3.x从0开始搭建React开发环境

    在开发react单页面的时候无可避免的要使用到webpack打包,今天就从零开始搭建一个react的开发环境. 需要实现的功能有: 使用Babel编译ES6 编译.jsx文件 实现热更新 编译CSS预 ...

  9. 一个更适合Java初学者的轻量级开发工具:BlueJ

    Java是世界上最流行的编程语言之一,它被广泛用于从Web开发到移动应用的各种应用程序.大部分Java工程师主要是用IDEA.Eclipse为主,这两个开发工具由于有强大的能力,所以复杂度上就更高一些 ...

最新文章

  1. 探究C/C++可变参数
  2. 说实话,Hibernate 和 MyBatis 哪个更好用?
  3. VTK:模型之MarchingSquares
  4. find函数matlab_Matlab 数值数据
  5. CSS中的Position属性
  6. mySQL教程 第1章 数据库设计
  7. 判断sem信号量为零_Linux线程同步(互斥量、信号量、条件变量、生产消费者模型)...
  8. 下行文格式图片_帮你填平论文投稿格式修改这个大坑,一文了解三大出版社投稿要求...
  9. 第2章 Python与数据分析
  10. P3978 [TJOI2015]概率论(生成函数)
  11. C# - Environment类,获取桌面的路径
  12. iOS多线程编程的知识梳理
  13. EFM (Explicit Factor Models)显因子模型
  14. FLUENT_V6.1.22 3CD (正式商业版)
  15. 用来进行虚拟仿真实验的软件有哪些?这3款简单易懂的软件值得你拥有
  16. 可视化任务编排拖拉拽的数据集成工具
  17. Web2.0 网站介绍(3) - Flickr.com
  18. 制作MMORPG游戏需要储备哪些技术鲨鱼辣椒
  19. 运维工作发展的几个阶段
  20. 设置Ajax为同步请求

热门文章

  1. Java线程的状态转换
  2. DS1819 对应版本的FFMPEG_Qt音视频开发33-ffmpeg安卓版
  3. java安装了为什么运行不了_安装jdk后运行javac可以运行,为什么不能运行java?...
  4. 国内程序员最容易发音错误的单词集合
  5. 【struts2+hibernate+spring项目实战】Spring计时器任务 Spring整合JavaMail(邮件发送)(ssh)
  6. struts2常见错误及解决总结
  7. php 二叉树判断节点的位置,PHP实现判断二叉树是否对称的方法
  8. Java-Web Response响应和Request请求
  9. 蓝桥杯 历届试题 分糖果(模拟)
  10. linux日志队列长度,Linux 消息队列长度处理