超详细React项目创建步骤

405 阅读4分钟

一、关于React

英文官网:reactjs.org/ ===》 react.dev/

中文官网:zh-hans.reactjs.org/ ===》zh-hans.react.dev/

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

react在发展过程中,一直跟随原生js的脚步,特别是从v16.0版本开始(用到了class来创建组件)

es6.ruanyifeng.com/

2015年推出了使用react来编写移动端的app ---- react-native www.react-native.cn/ v0.73

重要版本发版时间

序号版本号发版时间重要更新
1162017年9月26引入es6的类组件
216.32018年4月3日生命周期更新
316.42018年5月23日生命周期更新
416.82019年2月6日引入 react hooks
517.02020年10月20日过渡版本
618.02022年3月29日写法改变,严格模式发生改变

React目前版本是 18.2.0,是2022年6月14日

二、脚手架

英文官网:create-react-app.dev/

中文官网:create-react-app.bootcss.com/

yarn npm cnpm pnpm

配置cnpm

npm install -g cnpm --registry=https://registry.npmmirror.com

以后就可以使用 cnpm 代替 npm

补充:react的脚手架并不是只有 create-react-app,还有dva-cli,umi

vite

$ npm init vite@latest
# 或者
$ yarn create vite
# 或者
$ pnpm create vite

vue-cli以及create-react-app底层都是基于nodejswebpack

2.1 create-react-app脚手架的使用

npm install --global smart-npm --registry=https://registry.npm.taobao.org/

第一次通过create-react-app 或者 通过webstorm等编译器创建react项目时,因为要安装很多相关的包,而这些包的安装基本都是在内部通过npm进行安装。 由于npm在访问有些国外的资源会非常卡,有的时候即使开了VPN也一样很卡,因此这个时候创建过程可能会异常缓慢,这里其实我们可以使用国内的数据源。 如果 window 用户安装最新版本不成功的话,可以试试安装 smart-npm@1

npm install --global smart-npm@1 --registry=https://registry.npm.taobao.org/

上面命令并不是必须得执行

Create React App 让你仅通过一行命令,即可构建现代化的 Web 应用。

本文档之后称之为cra

创建项目的方式:

需要保证电脑安装node版本在14以上,系统在win7以上

npx: npm可以看成第三方的资源包,npx可以看成各种基于node的脚手架的工具

# 方式1:使用npx
$ npx create-react-app react-basic
# 等价于
$ npm i create-react-app -g #  npm 使用cnpm 代替 cnpm i create-react-app -g
$ create-react-app react-basic

如果需要使用ts开发项目,创建项目时可以通过--template typescript指定模版

$ npx create-react-app myapp --template typescript

如果出现如下内容,即代表项目创建成功

Success! Created react-model-app at E:\workspace\bj2304\code\react-course\react-model-app
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!
​
We suggest that you begin by typing:
​
  cd react-model-app
  npm start

2.2 项目目录解析

项目创建完毕生成目录结构如下:

react-basic
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js // 做性能测试
    └── setupTests.js // 测试

src/reportWebVitals.js

const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry); // 衡量视觉稳定性。为了提供一个好的用户体验,CLS应该小于0.1
      getFID(onPerfEntry); // 衡量可交互性。为了提供一个好的用户体验,FID应该在100毫秒内。
      getFCP(onPerfEntry); // 首次内容绘制
      getLCP(onPerfEntry); // 衡量加载性能。为了提供一个好的用户体验,LCP应该在2.5秒内
      getTTFB(onPerfEntry); // 到第一个字节的时间
    });
  }
};
export default reportWebVitals;

react官方文档已经给了我们性能提升的方案:zh-hans.legacy.reactjs.org/docs/optimi…

打开package.json,发现可运行命令如下:

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

start指令用于启动开发者服务器

build指令用于打包项目

test指令用于测试

eject指令用于抽离配置文件

cra脚手架基于webpack,默认webpack的配置在 node_modules下的react-scripts 内部,但是一般情况下,传输代码时,不会上传 node_modules,那么在必要情况下就必须得抽离配置文件。

如果项目创建不成功,复制别人的项目(不复制node_modules)

2.3 抽离配置文件

通过npm run eject或者cnpm run eject 或者yarn eject指令抽离配置文件

抽离配置文件过程中注意事项

  • 1.确保项目的git仓库是最新的
  • 2.如果不需要对于webpack进行配置,那么不需要抽离配置文件
  • create-react-app v2 默认支持 ts 以及sass 以及css的模块化,如果使用 sass作为css预处理器,那么不需要抽离配置文件
​
Copying files into E:\workspace\bj2304\code\react-course\react-basic
  Adding \config\env.js to the project
  Adding \config\getHttpsConfig.js to the project
  Adding \config\modules.js to the project
  Adding \config\paths.js to the project
  Adding \config\webpack.config.js to the project
  Adding \config\webpackDevServer.config.js to the project
  Adding \config\jest\babelTransform.js to the project
  Adding \config\jest\cssTransform.js to the project
  Adding \config\jest\fileTransform.js to the project
  Adding \scripts\build.js to the project
  Adding \scripts\start.js to the project
  Adding \scripts\test.js to the project
  Adding \config\webpack\persistentCache\createEnvironmentHash.js to the project
​
Updating the dependencies
  Removing react-scripts from dependencies
  Adding @babel/core to dependencies
  Adding @pmmmwh/react-refresh-webpack-plugin to dependencies
  Adding @svgr/webpack to dependencies
  Adding babel-jest to dependencies
  Adding babel-loader to dependencies
  Adding babel-plugin-named-asset-import to dependencies
  Adding babel-preset-react-app to dependencies
  Adding bfj to dependencies
  Adding browserslist to dependencies
  Adding camelcase to dependencies
  Adding case-sensitive-paths-webpack-plugin to dependencies
  Adding css-loader to dependencies
  Adding css-minimizer-webpack-plugin to dependencies
  Adding dotenv to dependencies
  Adding dotenv-expand to dependencies
  Adding eslint to dependencies
  Adding eslint-config-react-app to dependencies
  Adding eslint-webpack-plugin to dependencies
  Adding file-loader to dependencies
  Adding fs-extra to dependencies
  Adding html-webpack-plugin to dependencies
  Adding identity-obj-proxy to dependencies
  Adding jest to dependencies
  Adding jest-resolve to dependencies
  Adding jest-watch-typeahead to dependencies
  Adding mini-css-extract-plugin to dependencies
  Adding postcss to dependencies
  Adding postcss-flexbugs-fixes to dependencies
  Adding postcss-loader to dependencies
  Adding postcss-normalize to dependencies
  Adding postcss-preset-env to dependencies
  Adding prompts to dependencies
  Adding react-app-polyfill to dependencies
  Adding react-dev-utils to dependencies
  Adding react-refresh to dependencies
  Adding resolve to dependencies
  Adding resolve-url-loader to dependencies
  Adding sass-loader to dependencies
  Adding semver to dependencies
  Adding source-map-loader to dependencies
  Adding style-loader to dependencies
  Adding tailwindcss to dependencies
  Adding terser-webpack-plugin to dependencies
  Adding webpack to dependencies
  Adding webpack-dev-server to dependencies
  Adding webpack-manifest-plugin to dependencies
  Adding workbox-webpack-plugin to dependencies
​
Updating the scripts
  Replacing "react-scripts start" with "node scripts/start.js"
  Replacing "react-scripts build" with "node scripts/build.js"
  Replacing "react-scripts test" with "node scripts/test.js"
​
Configuring package.json
  Adding Jest configuration
  Adding Babel preset
​
Running npm install...
​
up to date in 13s
Ejected successfully!
​
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/env.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/getHttpsConfig.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/jest/babelTransform.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/jest/cssTransform.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/jest/fileTransform.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/modules.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/paths.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/webpack.config.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/webpack/persistentCache/createEnvironmentHash.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/config/webpackDevServer.config.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/scripts/build.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/scripts/start.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in code/react-course/react-basic/scripts/test.js.
The file will have its original line endings in your working directory
Staged ejected files for commit.
​
Please consider sharing why you ejected in this survey:
  http://goo.gl/forms/Bi6CZjk1EqsdelXk1
$ npm start
$ npm build

2.4 webpack二次封装

2.4.1 集成css预处理器

  • 集成less预处理器
$ npm i less less-loader -D
  • 集成sass预处理器

    虽然已经默认支持了sass,但是得需要安装以下模块

$ npm i node-sass -D # cnpm i node-sass -D
  • 集成stylus预处理器
$ cnpm i stylus stylus-loader -D

具体配置如下:

React-basic/config/webpack.config.js

// style files regexes 可以搜索此关键字快速定位
const cssRegex = /.css$/;
const cssModuleRegex = /.module.css$/;
const sassRegex = /.(scss|sass)$/;
const sassModuleRegex = /.module.(scss|sass)$/;
const lessRegex = /.less$/; // +++++++
const lessModuleRegex = /.module.less$/;// +++++++
const stylusRegex = /.(styl|stylus)$/;// +++++++
const stylusModuleRegex = /.module.(styl|stylus)$/;// +++++++// "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 MiniCSSExtractPlugin 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,
        sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
        modules: {
          mode: 'icss',
        },
      }),
        // Don't consider CSS imports dead code even if the
        // containing package claims to have no side effects.
        // Remove this when webpack adds a warning or an error for this.
        // See https://github.com/webpack/webpack/issues/6571
        sideEffects: true,
},
  // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
  // using the extension .module.css
  {
    test: cssModuleRegex,
      use: getStyleLoaders({
        importLoaders: 1,
        sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
        modules: {
          mode: 'local',
          getLocalIdent: getCSSModuleLocalIdent,
        },
      }),
  },
    // Opt-in support for SASS (using .scss or .sass extensions).
    // By default we support SASS Modules with the
    // extensions .module.scss or .module.sass
    {
      test: sassRegex,
        exclude: sassModuleRegex,
          use: getStyleLoaders(
            {
              importLoaders: 3,
              sourceMap: isEnvProduction
              ? shouldUseSourceMap
              : isEnvDevelopment,
              modules: {
                mode: 'icss',
              },
            },
            'sass-loader'
          ),
            // Don't consider CSS imports dead code even if the
            // containing package claims to have no side effects.
            // Remove this when webpack adds a warning or an error for this.
            // See https://github.com/webpack/webpack/issues/6571
            sideEffects: true,
    },
      // Adds support for CSS Modules, but using SASS
      // using the extension .module.scss or .module.sass
      {
        test: sassModuleRegex,
          use: getStyleLoaders(
            {
              importLoaders: 3,
              sourceMap: isEnvProduction
              ? shouldUseSourceMap
              : isEnvDevelopment,
              modules: {
                mode: 'local',
                getLocalIdent: getCSSModuleLocalIdent,
              },
            },
            'sass-loader'
          ),
      },
        {
          test: lessRegex,
            exclude: lessModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                  modules: {
                    mode: 'icss',
                  },
                },
                'less-loader'
              ),
                // Don't consider CSS imports dead code even if the
                // containing package claims to have no side effects.
                // Remove this when webpack adds a warning or an error for this.
                // See https://github.com/webpack/webpack/issues/6571
                sideEffects: true,
        },
          // Adds support for CSS Modules, but using SASS
          // using the extension .module.scss or .module.sass
          {
            test: lessModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                  modules: {
                    mode: 'local',
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
                'less-loader'
              ),
          },
     {
          test: stylusRegex,
            exclude: stylusModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                  modules: {
                    mode: 'icss',
                  },
                },
                'stylus-loader'
              ),
                // Don't consider CSS imports dead code even if the
                // containing package claims to have no side effects.
                // Remove this when webpack adds a warning or an error for this.
                // See https://github.com/webpack/webpack/issues/6571
                sideEffects: true,
        },
          // Adds support for CSS Modules, but using SASS
          // using the extension .module.scss or .module.sass
          {
            test: stylusModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                  modules: {
                    mode: 'local',
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
                'stylus-loader'
              ),
          },

2.4.2 配置@解析别名

vue项目中可以使用@代替src目录,那么react中抽离配置文件之后也可以实现此功能

react-basic/config/webpack.config.js

alias: {
  '@': path.resolve('src'), // +++++++++++++
    // Support React Native Web 搜索此关键词快速定位
    // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
    'react-native': 'react-native-web',
      // Allows for better profiling with ReactDevTools
      ...(isEnvProductionProfile && {
      'react-dom$': 'react-dom/profiling',
      'scheduler/tracing': 'scheduler/tracing-profiling',
    }),
      ...(modules.webpackAliases || {}),
},

src/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();
​

如果控制台报错如下,说明@别名没有配置成功

Failed to compile.
​
Module not found: Error: Can't resolve '@/index.css' in '/Users/wudaxun/Desktop/workspace/code/bk2207A/code/react-course/react-basic/src'
ERROR in ./src/index.js 6:0-21
Module not found: Error: Can't resolve '@/index.css' in '/Users/wudaxun/Desktop/workspace/code/bk2207A/code/react-course/react-basic/src'
​
ERROR in ./src/index.js 7:0-24
Module not found: Error: Can't resolve '@/App' in '/Users/wudaxun/Desktop/workspace/code/bk2207A/code/react-course/react-basic/src'
​
ERROR in ./src/index.js 8:0-48
Module not found: Error: Can't resolve '@/reportWebVitals' in '/Users/wudaxun/Desktop/workspace/code/bk2207A/code/react-course/react-basic/src'
​
webpack compiled with 3 errors

如果没有错误说明配置是成功的。

如果不抽离配置文件,但是也需要配置别名@

$ cnpm i @craco/craco -D

项目根目录中创建 craco 的配置文件:craco.config.js

const path = require('path')
module.exports = {
 webpack: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
 }
}

修改package.json中运行命令

"scripts": {
    "start": "craco start",
    "build": "craco build"
    "test": "craco test"
}

重启服务器即可生效

2.5 setupProxy代理

即使不抽离配置文件,也是在此处配置代理

如果整个项目只有一个服务器且有跨域问题,可以直接在package.json中做如下配置:

"proxy": "http://121.89.205.189:3000/api",

然后在项目中可以如下访问:

// cnpm i axios -S
// src/index.js
fetch('/pro/list').then(res => res.json()).then(res => {
  console.log(res.data)
})

了解:那么如果有多个服务器 并且也需要解决跨域问题 - 本项目不做配置

首先,http-proxy-middleware使用 npm 或 Yarn 安装:

$ cnpm install http-proxy-middleware -S
$ # or
$ yarn add http-proxy-middleware -S

接下来,创建src/setupProxy.js并在其中放置以下内容:

const { createProxyMiddleware } = require('http-proxy-middleware');
​
module.exports = function(app) {
  // ...
};

您现在可以根据需要注册代理了!这是使用上述内容的示例http-proxy-middleware

const { createProxyMiddleware } = require('http-proxy-middleware'); // 此处不使用import语法
​
module.exports = function (app) {
  // http://121.89.205.189:3001/api/pro/list ==> /myapi/pro/list
  app.use('/myapi', createProxyMiddleware({
      target: 'http://121.89.205.189:3001/api',
      changeOrigin: true,
      pathRewrite: {
        '^/myapi': ''
      }
    })
  );
  
}

注意: 您不需要在任何地方导入此文件。当您启动开发服务器时,它会自动注册。

注意: 此文件仅支持 Node 的 JavaScript 语法。确保只使用受支持的语言功能(即不支持 Flow、ES 模块等)。

注意: 将路径传递给代理函数允许您在路径上使用通配符和/或模式匹配,这比快速路由匹配更灵活。