Create React App 的Webpack4配置高级进阶

本文介绍了如何在Create React App (CRA) 中进行Webpack4的高级配置,包括添加antd支持,配置less以及解决跨域问题。通过eject操作暴露webpack配置,然后详细说明了如何配置antd的less以及按需加载,同时讲解了如何使用webpack-dev-server设置代理以实现跨域访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

React 框架搭建

Creact React App(CRA)是创建React应用的一个构建脚本,并不处理后端逻辑及数据库,它与其他构建脚本不同的一点就是,它使用了 Babel 和 Webpack 这样的构建工具,使开发者不用单独去配置这些工具,从而降低了开发人员的学习难度。
但对于一些高阶的开发人员,想要对Webpack做一些修改,包括对less、跨域访问的支持以及antd的配置等,下面就是我的具体做法。
注意当前webpack的版本"webpack": "4.19.1",时基于此给出的解决方案,webpack至少是4以上版本。
按照React 官网创建你的React项目,这里就不在讲解。
使用CRA创建好项目之后,打开package.json文件:

  {
  ...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  ...
}

执行yarn eject将封装到CRA中的全部配置反编译到当前项目,由此webpack的配置全部暴露给了开发者。

// eject 后项目根目录下会出现 config 文件夹,里面就包含了 webpack 配置
config
├── env.js
├── jest
│   ├── cssTransform.js
│   └── fileTransform.js
├── paths.js
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.prod.js // 生产环境配置
└── webpackDevServer.config.js
// eject 后项目根目录下会出现 scripts 文件夹,里面就包含了 项目启动文件
├── build.js //生产环境
├── start.js // 开发环境
├── test.js // 测试环境

CRA和其他构建脚本不同的是,它可以通过升级react-scripts来升级CRA特性,但是如果使用eject命令后,就无法使用了,因为react-scripts已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。

Webpack配置

这时,一个简单的项目已经可以运行成功了并且webpack配置暴露了出来,下面安装antd,配置antd

1. antd

yarn add antd安装后,你可以使用antd的组件,官网提供了两种配置方案,我们这里只介绍eject配置。

  • 配置less,antd 的样式使用了 Less 作为开发语言,安装yarn add lessyarn add less-loader
  • 按需加载,yarn babel-plugin-import 是一个用于按需加载组件代码和样式的 babel 插件
  • 自定义主题
    打开webpack.config.dev.js,作出相应的修改:
...
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
//--------------------注意:这里需要增加less的相关配置--------------------
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
 ...
 // --------------------注意,在此处修改了判断语句的代码,增加对less的支持--------------------
 if (preProcessor) {
     if (preProcessor === 'less-loader') {
         loaders.push({
             loader:require.resolve(preProcessor),
             options: {
                 modules: false,
                 modifyVars: {
                     "@primary-color": "#1890ff" // 这里配置antd的自定义主题色
                 },
                 javascriptEnabled: true
             }
         })
     } else {
         loaders.push(require.resolve(preProcessor));
     }
 }
 return loaders;
 };
 // This is the development configuration.
 // It is focused on developer experience and fast rebuilds.
 // The production configuration is different and lives in a separate file.
 module.exports = {
 ...
 module: {
 strictExportPresence: true,
 rules: [
   ...
   {
     // "oneOf" will traverse all following loaders until one will
     // match the requirements. When no loader matches it will fall
     // back to the "file" loader at the end of the loader list.
     oneOf: [
       ...
       // Process application JS with Babel.
       // The preset includes JSX, Flow, and some ESnext features.
       {
         test: /\.(js|mjs|jsx|ts|tsx)$/,
         include: paths.appSrc,
         loader: require.resolve('babel-loader'),
         options: {
           customize: require.resolve(
             'babel-preset-react-app/webpack-overrides'
           ),
           
           plugins: [
             [
               require.resolve('babel-plugin-named-asset-import'),
               {
                 loaderMap: {
                   svg: {
                     ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
                   },
                 },
               },
             ],
             // --------------------注意此处增加:实现按需加载--------------------: 
               ['import', { libraryName: 'antd', style: true }],  // import less
           ],
           // This is a feature of `babel-loader` for webpack (not Babel itself).
           // It enables caching results in ./node_modules/.cache/babel-loader/
           // directory for faster rebuilds.
           cacheDirectory: true,
           // Don't waste time on Gzipping the cache
           cacheCompression: false,
         },
       },
       ...
       // --------------------注意此处在cssRegex配置之上增加--------------------
         // "postcss" loader applies autoprefixer to our CSS.
         // "css" loader resolves paths in CSS and adds assets as dependencies.
         // "style" loader turns CSS into JS modules that inject <style> tags.
         // In production, we use a plugin to extract that CSS to a file, but
         // in development "style" loader enables hot editing of CSS.
         // By default we support CSS Modules with the extension .module.css
         {
             test: lessRegex,
             exclude: lessModuleRegex,
             use: getStyleLoaders({
                 importLoaders: 2,
             }, 'less-loader'),
         },
         // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
         // using the extension .module.css
         {
             test: lessModuleRegex,
             use: getStyleLoaders({
                 importLoaders: 2,
                 modules: true,
                 getLocalIdent: getCSSModuleLocalIdent,
             },  'less-loader'),
         },
       // "postcss" loader applies autoprefixer to our CSS.
       // "css" loader resolves paths in CSS and adds assets as dependencies.
       // "style" loader turns CSS into JS modules that inject <style> tags.
       // In production, we use a plugin to extract that CSS to a file, but
       // in development "style" loader enables hot editing of CSS.
       // By default we support CSS Modules with the extension .module.css
       {
         test: cssRegex,
         exclude: cssModuleRegex,
         use: getStyleLoaders({
           importLoaders: 1,
         }),
       },
       // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
       // using the extension .module.css
       {
         test: cssModuleRegex,
         use: getStyleLoaders({
           importLoaders: 1,
           modules: true,
           getLocalIdent: getCSSModuleLocalIdent,
         }),
       },
       ...
     ],
   },
   ...
   // ** STOP ** Are you adding a new loader?
   // Make sure to add the new loader(s) before the "file" loader.
 ],
 },
 ...
 };

同样,对webpack.config.prod.js做相同的调整。
至此,antd配置结束。

2. 跨域-- webpack-dev-server

webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。
在eject之后暴露出来的scripts/start.js, 找到

...
const paths = require('../config/paths');
...
// We require that you explictly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
  .then(() => {
    // We attempt to use the default port but if it is busy, we offer the user to
    // run on a different port. `choosePort()` Promise resolves to the next free port.
    // 获取端口号
    return choosePort(HOST, DEFAULT_PORT);
  })
  .then(port => {
    if (port == null) {
      // We have not found a port.
      return;
    }
    // 获取协议类型
    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
    // 获取名称
    const appName = require(paths.appPackageJson).name;
    // 获取url
    const urls = prepareUrls(protocol, HOST, port);
    // 根据惯用的信息创建一个webpack编译器
    const compiler = createCompiler(webpack, config, appName, urls, useYarn);
    // **加载代理**-----------
    const proxySetting = require(paths.appPackageJson).proxy;
    const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
    // 创建WebpackDevServer服务器
    const serverConfig = createDevServerConfig(
      proxyConfig,
      urls.lanUrlForConfig
    );
    const devServer = new WebpackDevServer(compiler, serverConfig);
    // 启动WebpackDevServer服务器
    devServer.listen(port, HOST, err => {
      if (err) {
        return console.log(err);
      }
      if (isInteractive) {
        clearConsole();
      }
      console.log(chalk.cyan('Starting the development server...\n'));
      openBrowser(urls.localUrlForBrowser);
    });

    ['SIGINT', 'SIGTERM'].forEach(function(sig) {
      process.on(sig, function() {
        devServer.close();
        process.exit();
      });
    });
  })
  .catch(err => {
    if (err && err.message) {
      console.log(err.message);
    }
    process.exit(1);
  });

注意 加载代理配置项proxySetting,它是由paths.appPackageJson加载来的,我们向上找到const paths = require('../config/paths');

...
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
// -------加载代理配置栏------
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};
...

查找当前src文件夹

src
├── App.css
├── App.js
├── App.test.js
├── index.css
├──index.js
├── logo.svg
└── serviceWorker.js

并没有setupProxy.js文件,我们创建src/setupProxy.js,并安装yarn add http-proxy-middleware,设置相应的代理

// src/setupProxy.js 配置代理
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
    app.use(proxy('/api/',
        {
            target: 'https://api.dev.com',// 后端服务器地址
            changeOrigin: true,
            secure: false
        }
    ));
}

更多devServer的配置,详见开发中 Server(devServer),这里不在详细介绍。

至此,若后续有修改,将继续更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值