• react create-react-app v5 从零搭建项目


    前言:

    好久没用 create-react-app做项目了,这次为了个h5项目,就几个页面,决定自己搭建一个(ps:mmp 好久没用,搭建的时候遇到一堆问题)。

    我之前都是使用 umi 。后台管理系统的项目 使用 antd-pro框架。实际上antd-pro 是基于umi搭建集成的框架。里面封装好了各种东西,开箱即用。

    读本篇文章建议 打开 csdn的目录功能,可以让你更快捷的找到你需要的配置:
    目录

    我的环境如下:
    create-react-app v5

        "axios": "^1.5.0",
        "http-proxy-middleware": "^2.0.6",
        "react": "^18.2.0",
        "react-dom": "^18.2.0",
        "react-router": "^6.16.0",
        "react-router-dom": "^6.16.0",
        "customize-cra": "^1.0.0",
        "react-app-rewired": "^2.2.1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    v5版本 好多问题,有很多 问题,有些插件 里的办法也不适配了(坑很多,很多 time:2023-09-27)。
    我说的坑多,是我不想暴露 webpack配置的情况下 使用 react-app-rewired 和 customize-cra 这个来配置一些东西遇到的。本身并不是 create-reacr-app的问题。

    所以你如果不想这么麻烦,那你可以直接 npm run eject然后用传统的webpack配置。
    如果你不想用第三方插件重写webpack的话,可以看我这篇:react create-react-app v5 从零搭建(使用 npm run eject)

    v5刚出来没多久,v4的话问题就很少,基本稳定了!如果你不想用v5 可以安装指定版本的 create-react-app 。

    搭建过程:

    一、创建项目:
    安装Node 和 npm: Node >= 14.0.0 和 npm >= 5.6

    npx install -g create-react-app
    
    
    • 1
    • 2
    npx create-react-app my-app
    
    • 1

    在这里插入图片描述
    npx 不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。

    react 官网文档

    二、配置各种必备的东西

    npm start 运行 看到下图就说明项目创建成功了!
    项目运行成功效果图

    配置路由:

    1.下载 react-router-dom

    npm install react-router-dom
    
    • 1

    1.首先 npm react-router-dom
    2.App.js 里 写上如下代码:

    import React from "react";
    import { BrowserRouter, Routes, Route } from "react-router-dom";
    import routes from './routes';
    const App = () => {
      console.log(routes)
      return (
        <BrowserRouter>
          <Routes>
            {routes.map((route) => (
              <Route key={route.path} path={route.path} element={route.component} />
            ))}
            {/* } />  */}
          </Routes>
        </BrowserRouter>
      );
    };
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    App.js 代码截图
    3.index.js里写上:

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <App />
       </React.StrictMode> 
    );
    
    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    index.js代码截图

    4.在src下新建一个 routes.js文件 写上:

    // 导入你的页面组件  
    import Home from './pages'; 
    //可以用 path:"*" 写个 404页面,我暂时不需要
    const routes = [
      { path: "/", component: <Home/>}
    ];
    
    export default routes;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    routes.js代码截图
    运行看到 Home组件里的东西就说明成功了。之后可以在 scr/router.js里导入其他组件 写上 path和routers就行了。

    注意:react-router-dom v6 和v5 api不太一样,比如 v5 把 Route 上是 component v6是element。具体写法 建议参考 你所用的版本 文档!

    如果遇到了Uncaught TypeError: Cannot read properties of null (reading ‘useRef‘) 报错,可以看react create-react-app v5 配置路由(报错及注意事项)

    配置less:

    可以参考:
    react create-react-app 配置less

    配置Proxy代理:

    使用 http-proxy-middleware
    1.安装http-proxy-middleware

    npm install http-proxy-middleware --save
    
    • 1

    2.src目录新建一个setupProxy.js
    代码大致如下:
    然后 请求接口时以/api/xx就会自动走代理。

    const { createProxyMiddleware } = require('http-proxy-middleware');
    
    module.exports = function(app) {
        app.use(
          '/api',
          createProxyMiddleware({
            target: 'http://localhost:8000',
            changeOrigin: true,
            // pathRewrite: {  
            //     '^/api': '/',  
            //   },  
          })
        );
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    具体配置可以参考:React create-react-app 里配置代理(解决跨域)

    配置axios:

    1.安装 axios

    cnpm install axios --save
    
    • 1

    2.src/utils 新建一个 request.js文件(没有utils就新建一个目录然后再建一个request.js)
    3.request代码如下:
    这个是最简单的配置了,你可以根据自己的需求配置 请求拦截里的东西。

    import axios from 'axios'
    
     // axios的配置文件, 可以在这里去区分开发环境和生产环境等全局一些配置
     const devBaseUrl = 'http://api.k780.com/'
     const proBaseUrl = 'http://xxxxx.com/'
     
     // process.env返回的是一个包含用户的环境信息,它可以去区分是开发环境还是生产环境
     export const BASE_URL =  process.env.NODE_ENV === 'development' ? devBaseUrl : proBaseUrl
     export const TIMEOUT = 5000
    
    var request = axios.create({
        baseURL:BASE_URL,//基准地址
        timeout:TIMEOUT
    })
    //拦截请求
    request.interceptors.request.use((config)=>{
        return config
    })
    //拦截响应
    request.interceptors.response.use((response)=>{
        return response
    },function (error){
        //对响应的错误做点什么
        return Promise.reject(error);
    }
    )
     
    export default request;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    使用时就是:

    import request from "@/utils/request";
     request.get("/api/fund_home/select_by_fund?fund=1001").then(res=>{
          console.log(res);
        })
    
    • 1
    • 2
    • 3
    • 4

    当然 你也可以不叫 request 你可以叫 $axios 全看自己。
    上面我给的配置说最简单的,一般来说 需要在 请求拦截里加上一些判断比如 错误提示,根据code值提示一下。可以借用 ui库的message组件 message.error(xxx)。还有 如果你需要加上token 还得统一加上token。

    比如:我就在响应拦截里做了统一处理,status =200 并且 respnse.data.code=000000时才代表数据成功返回(这个需要根据你自己的接口规范来定)。否则 就需要 提示错误信息。Toast是antd-mobile里的,你可以根据自己需求变。

    //拦截响应
    request.interceptors.response.use(
      (response) => {
        console.log(response, "res");
        if (response && response.status == "200") {
          if (response.data && response.data.code == "000000") {
            //接口成功才返回数据
            return Promise.resolve(response.data);
          } else {
            Toast.show({
              content: response.data&&response.data.message,
              duration:2000,
              position: "top",
            });
          }
        }else{
            return Promise.reject(response.message)
        }
      },
      function (error) {
        //对响应的错误做点什么
        Toast.show({
            content: '网络异常',
            duration: 0,
            position: 'top',
          })
        return Promise.reject(error);
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    还需呀注意的时使用 axios的时候一定要用catch捕获一下错误,要不然接口出错一定会导致页面直接有个遮罩层显示错误信息。
    比如:
    接口超时了,页面直接显示错误信息,但其实应该是显示页面才对,这样太影响用户体验了。
    错误截图
    可以用的时候then后面加个catch,就不会直接显示在页面上了。

    request
          .get("/api/fund_home/select_by_fund", {
            params: {
              fund: "混合",
            },
          })
          .then((res) => {
            console.log(res);
          })
          // .catch((error) => {
          //   console.log(error);
          // });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    抽出到servers(模块化):
    不过一般 项目里都会抽出来一个server模块(umi、antd-pro都是这样的),这样更加简洁。

    1.在 src目录新建一个servers目录。
    2.在 src/servers新建一个文件。
    这个文件名 对应的就是模块名,比如:我现在写的是home页,那我就新建 home.js 。 后面写 其他模块就新建对应的js就行。
    3.在 home.js里引入 封装好的 request,写上axios请求。
    大致如下:你需要根据你自己的实际需求来写(@代表src,这个需要配置一下,如过你没配置就用相对路径引入就行)。

    import request from "@/utils/request";
    
    export function getList(params) {
        return request({
            url: "/api/fund_home/select_by_fund",
            method: "get",
            params
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    servers/home.js截图

    然后就可以在 home页里使用了。

    import {getList} from "@/servers/home";
     getList({fund:"混合"}).then((res) => {
            console.log(res);
          })
          .catch((error) => {
            console.log(error);
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    react axios配置

    静态资源图片之类的可以在src下新建assets目录:

    在 src新建文件夹assets。然后新建img可以存放图片。 新建 js,css可以存放静态的js和css。

    其实放public里也可以:
    在create-react-app中,assets目录和public目录都可以用来存放静态资源,但它们之间有一些区别。
    assets目录是我们自己创建的,通常放置一些与组件紧密相关的静态资源,如图片、样式文件等。这些资源在Webpack打包时会被处理和压缩,并与代码一起打包到最终的构建文件中。在组件中引用这些资源时,需要使用import关键字进行导入。

    public目录是在创建React应用时默认生成的,用于放置一些通用的静态资源,如HTML文件、favicon.ico文件等。这些资源在Webpack打包时不会被处理和压缩,并且会被直接复制到最终的构建文件中。在组件中引用这些资源时,需要使用相对路径进行引用。
    总的来说,assets目录和public目录都可以用来存放静态资源,但它们在处理和使用静态资源时有所不同。因此,我们需要根据实际情况选择合适的目录来存放静态资源。

    大白话就是 ,public里的文件打包会直接被复制到 dist里,assets则不会。

    打包部署到非根目录:

    create-react-app v5 打包配置(部署到非根目录)

    使用环境变量

    [react 使用环境变量的方法和步骤(dotenv-cli 实现使用环境变量步骤)]

    打包去掉 map文件

    create-react-app 打包去掉 map文件

    注意严格模式(StrictMode)会导致开发环境接口请求两次

    React中StrictMode严格模式,导致开发环境,接口会请求两次或多次( useEffect 请求多次)

    不暴露 eject 配置自己的webpack:

    1. 下载react-app-rewired 和 customize-cra-5
    npm install react-app-rewired customize-cra-5 --save-dev
    
    • 1

    修改package.json 里scripts配置:

     "start": "react-app-rewired start",
      "build": "react-app-rewired build",
      "test": "react-app-rewired test",
      "eject": "react-scripts eject"
    
    • 1
    • 2
    • 3
    • 4

    2.在项目根目录创建一个config-overrides.js 文件

    比如配置 less 建议具体参考 上面的配置 less:

    const { override, addLessLoader, addPostcssPlugins } = require("customize-cra-5");
    
    module.exports = override(
      addLessLoader({  
        lessOptions:{
          javascriptEnabled: true,  
          modifyVars: { '@primary-color': '#1DA57A' }, // 你的主题色  
        },
      }) 
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    比如:按需加载 antd(按需加载 )

    按需加载ui库时因为ui库是less写的样式,所以配置时,需要先配置 less,上文中有步骤,ui库按需加载建议看官网文档,都会有方法和步骤及注意事项,其实现在 很多 ui库都支持 Tree Shaking ,v5也支持所以只要是ui库支持,那么就不用配置按需加载!!!

    Create React App v5 默认支持 Tree Shaking。Tree Shaking 是一项优化技术,用于在打包过程中只包含实际使用的代码,减少最终打包文件的体积。
    在 Create React App v5 的构建配置中,通过使用 Babel 和 webpack 的相关插件和配置,可以自动启用 Tree Shaking 功能。
    具体来说,Create React App v5 使用了以下插件和配置来支持 Tree Shaking:

    Babel 默认配置:Create React App v5 的默认 Babel 配置中使用了 @babel/preset-env,它会根据目标浏览器的兼容性要求,自动转译代码并进行 Tree Shaking。

    webpack 配置:Create React App v5 配置了优化选项 sideEffects: false,在 production 环境中默认启用了 Tree Shaking。这使得 webpack 在打包时可以识别出未使用的代码并进行排除。
    总结来说,Create React App v5 默认启用了 Tree Shaking,以帮助优化打包文件的体积。你无需额外进行配置即可享受 Tree Shaking 的好处。

    注意:antd-mobile无需配置手动按需加载
    antd-mobile 按需加载
    antd-mobile 按需加载官网截图
    其实 antd 高版本也自带按需加载 可以不用配置(下面的代码只是个 演示,你如果有其他 ui库 或者 插件需要按需加载可以按照下面的步骤来):
    在这里插入图片描述
    antd 官方链接 按需加载

    react-vant 也是:
    react-vant官网
    react-vant
    如果你有其他插件需要配置可以参考这个步骤来:
    这几种方式都需要 babel-plugin-import 支持,所以没有的话需要先安装!!!
    需要 cnpm install babel-plugin-import
    后再配置

    const {
      override,
      addLessLoader,
      addPostcssPlugins,
      fixBabelImports,
    } = require("customize-cra-5");
    
    module.exports = override(
      // addPostcssPlugins([require("autoprefixer")]), //自动给样式加浏览器前缀 不过 cra自带了所以可以不用这个
      // addLessLoader({
      //   lessOptions:{
      //     javascriptEnabled: true,
      //     modifyVars: { '@primary-color': '#1DA57A' }, // 你的主题色
      //   },
    
      // })
    
      // 针对antd-mobile 实现按需打包:根据import来打包 (使用babel-plugin-import)
        fixBabelImports("import", {
        libraryName: "antd",
        libraryDirectory: "es",
        style: true, //自动打包相关的样式 默认为 style:'css'
      }),
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    package.json里babel配置

    1.在 package.json 文件中找到 “babel” 字段,如果没有请自行添加该字段。

    2.在 “babel” 字段中添加 “plugins” 字段,并将 “plugins” 字段的值设置为一个数组,用于配置 babel 插件。

    3.在 “plugins” 数组中添加 “import” 插件,并将其配置为按需加载。具体配置如下:
    只添加 plugins就行,如果默认有其他配置,在后面加上就行。

    {
      "babel": {
        "plugins": [
          [
            "import",
            {
              "libraryName": "react-vant",
              "style": true
            }
          ]
        ]
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    比如:路径别名 src 写成@/xxx

      const {
      override,
      addLessLoader,
      addPostcssPlugins,
      fixBabelImports,
      addWebpackAlias
    } = require("customize-cra-5");
    const path = require('path')
      addWebpackAlias({
        '@': path.resolve('src')
      }),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    然后 就可以使用 @来引入src下的文件了。

    比如 引入 px2rem(虽然官方这么写 但是 我并不起作用):

    目前我找了 issues 里没有解决方案(2023-09-28,以后或许有,因为我项目着急,我必须使用 px转换rem的操作,为了适配移动端 h5,所以我选择了暴露eject的方法,后续可能会有方法,如果有新方法可以评论区告诉我,我也会关注 github issues )
    在这里插入图片描述

      addPostcssPlugins([require("postcss-px2rem")({ remUnit: 37.5 })])
    
    • 1

    2023-10-09补充:
    后来国庆过后有人回复我了,我修改了一下代码,发现可以生效了!
    react create-react-app v5配置 px2rem (不暴露 eject方式)
    部分内容参考于 React移动端适配解决方案
    customize-cra-5 的api可以去看github上的文档
    api部分 截图

    customize-cra api doc

  • 相关阅读:
    217页企业大数据能力平台建设技术方案
    【AI视野·今日Robot 机器人论文速览 第六十二期】Wed, 25 Oct 2023
    【扩散模型 李宏毅B站教学以及基础代码运用】
    hive的语言元素
    Pytorch(二) —— 激活函数、损失函数及其梯度
    Solidworks 发生一个或多个重建错误却不显示出来
    代码随想录算法训练营第59天|● 503.下一个更大元素II ● 42. 接雨水
    brew 下载 nvm 之后,nvm command not found
    8086,8088CPU管脚,奇偶地址体, ready信号,reset复位信号。规则字和非规则字
    凯美瑞 vs 太空船:Web3 游戏生长的两条路径
  • 原文地址:https://blog.csdn.net/weixin_44058725/article/details/133314417