不用 npm run eject,我是这么配置webpack的

前言

Create React App是创建 React 应用的一个常用脚手架,它将一些复杂工具(比如webpack)的配置封装了起来,可以让使用者不关心这些工具的具体配置,因此在使用 create-react-app 生成项目时,不会有 webpack 的配置项。

如果开发者要导出 webpack,必须使用 react-script eject。但这是一个单向操作,eject 后,就无法恢复了。个人觉得这种操作十分不便利,远没有vue 自带vue.config.js 的配置这么方便可行。推荐使用react-app-rewiredcustomize-cra 的插件组合,再通过 config-overrides.js 实现对 webpack 的自由配置。

项目使用 eject

如下所示,执行 create-react-app xx(项目名称) 初始化一个react 项目之后,在package.json中可以看到如下脚本命令。

js 复制代码
{
  ...
  "scripts": {
    "eject": "react-scripts eject"
  },
  ...
}

执行命令:npm run eject后,会将封装在 CRA 中的配置全部反编译到当前项目,这样用户就可以完全取得 webpack 文件的控制权,可以随心所欲修改wabpack配置。如下所示。CRA与其他脚手架不同的地方在于可以通过升级其中的react-scripts包来升级 CRA 的特性。但如果我们使用了eject命令,就再也享受不到 CRA 升级带来的好处了,原因如下:

react-scripts 已经是以文件的形式存在于项目中,而不是以包的形式,所以无法对其升级。

js 复制代码
config
├── env.js
├── jest
│   ├── cssTransform.js
│   └── fileTransform.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.prod.js // 生产环境配置
└── webpackDevServer.config.js

项目使用react-app-rewired

react-app-rewired 是react社区开源的一个修改 CRA 配置的工具。纯 react-app-rewired 的方式自定义配置,可以参考 Extended Configuration Options 文档。这次我们使用customize-cra协助react-app-rewired自定义配置。 customize-cra提供了一些api通常就可以满足大部分的开发需求。

在 CRA 创建的项目中安装了react-app-rewired后,可以通过创建一个config-overrides.js 文件来对 webpack 配置进行扩展。具体操作如下:

  1. 安装 react-app-rewired customize-cra:
js 复制代码
yarn add react-app-rewired customize-cra -D
  1. 修改package.json文件,替换其中的 react-scripts:
js 复制代码
......
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
},
......
  1. 在项目根目录新建config-overrides.js
js 复制代码
const { override } = require('customize-cra');

module.exports = {
  ......
};

1. 常规开发配置(打包路径、gzip压缩、端口配置等)

通过从 customize-cra中引入 override,然后在 override() 中自定义打包配置相关函数,可以实现自定义的 webpack 配置。

js 复制代码
const { override } = require("customize-cra");
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const path = require("path");

// 修改端口号:
process.env.PORT = 8000;

// 常规配置
const addCustomize = () => (config) => {
  if (process.env.NODE_ENV === 'production') {
    // 配置打包后的文件位置(默认为build, 修改为dist)
    const paths = require("react-scripts/config/paths");
    paths.appBuild = path.join(path.dirname(paths.appBuild), "dist");
    config.output.path = path.join(path.dirname(config.output.path), "dist");
    // 添加js打包gzip配置
    config.plugins.push(
      new CompressionWebpackPlugin({
        test: /.js$|.css$/,
        threshold: 1024,
      }),
    )
  }
  if (config.resolve) {
    config.resolve.extensions.push(".jsx");
  }
  return config;
};

module.exports = override(
   addCustomize()
)

2. 通过postcss-pxtorem 插件实现移动端适配

实现移动端自适应布局的最简单方式就是通过 lib-flexiblepostcss-pxtorem插件实现。

  1. 安装插件:
js 复制代码
yarn add lib-flexible postcss-pxtorem
  1. 项目主入口引入 lib-flexible,该插件可以获取当前h5屏幕尺寸来设置跟元素的 font-size大小, 实现响应式的屏幕尺寸适配。
js 复制代码
// 在 index.js 文件中引入
import 'lib-flexible';
  1. 再配置 postcss-pxtorem 插件,该插件的作用是可以把 px 尺寸转成 rem 尺寸,方便我们在写样式的时候,可以直接写 px 就可以了。在当前config-overrides.js 中配置目前发现一个问题。几乎网上全都是通过以下方法来解决适配问题:
js 复制代码
const { override, addPostcssPlugins } = require("customize-cra");

module.exports = override(
   ......
   addPostcssPlugins([require('postcss-pxtorem')({ 
     rootValue: 37.5, 
     propList: ['*'], 
     minPixelValue: 2
   })]),
)

但是本人在配置的时候始终不生效,最后不得已通过执行 npm run eject 后在修改webpack 配置,发现还是不生效,目前网上千篇一律的这种做法,也没有附带解决方案,感受到了极大的困扰。然后发现可以通过在pacakge.json 中的直接添加 postcss 配置实现,算是可以顺利解决这个问题。

js 复制代码
...
"postcss": {
    "plugins": {
      "autoprefixer": {},
      "postcss-pxtorem": {
        "rootValue": 37.5,
        "selectorBlackList": [],
        "propList": [
          "*"
        ]
      }
    }
  },
 ...

3. 引入less 和 antd插件的按需加载

需要支持less 编写样式,需要安装依赖:lessless-loaderbabel-plugin-import; 再通过引入 antd 插件,具体的配置如下:

js 复制代码
const { override, fixBabelImports, addLessLoader } = require("customize-cra");

module.exports = override(
  // 针对antd实现按需打包: 根据import来打包(使用babel-plugin-import)
  fixBabelImports("import", {
    libraryName: "antd",
    libraryDirectory: "es",
    style: true, // 自动打包相关的样式
  }),

  // 使用less-loader对源码中的less的变量进行重新指定
  addLessLoader({
    javascriptEnabled: true,
    modifyVars: { "@primary-color": "#1DA57A" }, // 自定义antd的主题
    lessOptions: {
      javascriptEnabled: true,
      localIdentName: '[local]--[hash:base64:5]',
    },
  })
)

执行代码后发现奇怪的报错:

PostCSS Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'plugins'. These properties are valid:

可以通过再加上如下配置解决:

js 复制代码
adjustStyleLoaders(({ use: [, , postcss] }) => {
    const postcssOptions = postcss.options;
    postcss.options = { postcssOptions };
}),

4. 添加别名

配置别名后,可以在组件路径引入的地方统一通过别名处理, 例如组件引入: import Name from '@/pages/name' , 例如文件路径引入:<img src={require("@/imgs/pa-icon.png")} alt="" />等,采用别名的好处在于清晰文件路径,同时加快webpack构建的速度。

js 复制代码
const { override, addWebpackAlias } = require("customize-cra");

module.exports = override(
  // 配置路径别名
  addWebpackAlias({
    "@": path.resolve(__dirname, "./src")
  }),
)

5. sourceMap控制

js 复制代码
const { override, addWebpackAlias } = require("customize-cra");

const closedMap = () => config => {
  config.devtool = config.mode === 'development' ? 'cheap-module-source-map' : false
  return config
}

module.exports = override(
  // sourceMap控制
  closedMap(),
)

6. 添加 addWebpackExternals 排除打包插件,用来配置cdn地址

通过cdn引入能大大减少打包体积的大小,提升首页加载时间,可以通过以下方式实现:

js 复制代码
const {override, addWebpackExternals} = require('customize-cra')

module.exports = override(
  // 排除打包依赖插件,配置cdn引入
  addWebpackExternals({
    react: 'React',
    'react-dom': 'ReactDOM',
    'react-router-dom': 'ReactRouterDOM',
    'redux': 'Redux',
    'axios': 'axios'
  })
)

同时在public 的index.html 文件中引入cdn地址:

js 复制代码
<!-- react相关 -->
<script crossorigin src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-router-dom/5.3.0/react-router-dom.min.js"></script>
<script src="https://unpkg.com/redux@4.0.1/dist/redux.js"></script>
<!-- axios -->
<script type="text/javascript" src="https://unpkg.com/axios/dist/axios.min.js"></script>

7. addWebpackModuleRule 处理图片

addWebpackModuleRule 相当于webpack里Module的rules,通过规则匹配来处理。如下所示,通过加载插件url-loader 来处理图片,可以将 20kb 以下的图片转成base64, 超出则不处理,将文件输出到目录static/imgs/下。

js 复制代码
const {override, addWebpackModuleRule} = require('customize-cra')

module.exports = override(
  addWebpackModuleRule({
    test: /\.(png|jpg|gif|jpeg|svg)$/i,
    use: [{
      loader: 'url-loader',
      options: {
        limit: 20 * 1024,
        esModule: false,
        outputPath: `static/imgs/`,
      },
    },],
  }),
)
相关推荐
GISer_Jing1 小时前
React核心功能详解(一)
前端·react.js·前端框架
Winston Wood2 小时前
Perfetto学习大全
android·性能优化·perfetto
EterNity_TiMe_2 小时前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
程序猿进阶3 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FØund4043 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
契机再现4 小时前
babel与AST
javascript·webpack·typescript
疯狂的沙粒4 小时前
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
react.js·typescript
鑫宝Code5 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
工业甲酰苯胺11 小时前
Redis性能优化的18招
数据库·redis·性能优化
沉默璇年14 小时前
react中useMemo的使用场景
前端·react.js·前端框架