深入React源码01——使用 create-react-app 构建React工程化项目

186 阅读3分钟

前言:这是根据2023年最新珠峰React全家桶【react基础-进阶-项目-源码-淘系-面试题】-哔哩哔哩网课做的笔记,其大体结构由免费资料打底,但官方资料并没有完整的记录知识点,故我按照自己的文风简单修改,并把实战中的一些踩坑记录于此,希望能帮到你。

  • 这个课是我网上找到的最细致深入的课,安利一波。💕
  • webpack也有笔记,目前是以注释的形式写在源码里,可以访问我的github:zo-no/webpack: webpack学习库 (github.com)
  • 最后,我更新文章的第一手地方是blog,所以欢迎来访问我的blog,与我交朋友,里面有我的联系方式😊。

使用 create-react-app 构建React工程化项目

1.create-react-app概述

  • create-react-app:基于webpack搭建一套脚手架
  • 脚手架:默认把webpack打包规则处理好了,基础项目结构也创建好了
  • 后面命令都是yarn,故可以了解一下yarn
    • 下载
    • 初始化yarn init

1.1 react的版本

16:用的多

17:应该是底层升级

18:新版本、机制语法都升级了(默认安装)

1.2 初识create-react-app

1.2.1 安装create-react-app

全局安装

$ npm i create-react-app -g 「mac需要加sudo」

基于脚手架创建项目「项目名称需要符合npm包规范」:使用“数字、小写、_”

$ npx create-react-app xxx`
$ cd my-app`
$ npm start

1.2.2 安装后的文件目录

|- node_modules  包含安装的模块
|- public  页面模板和IconLogo
    |- favicon.ico
    |- index.html
|- src  我们编写的程序
    |- index.jsx  程序入口「jsx后缀名可以让文件支持jsx语法」
|- package.json
|- ...

1.2.3 从package.json认识基本结构

//package.json
{
  ...
  "dependencies": {
    ...
    "react": "^18.2.0",  //核心(语法状态处理)
    "react-dom": "^18.2.0",  //视图渲染核心
    "react-scripts": "5.0.1", //对打包命令的集成,会调用webpack
    "web-vitals": "^2.1.4"  //性能检测工具
  },
  "scripts": {
    "start": "react-scripts start", //开发环境启动web服务进行预览
    "build": "react-scripts build", //生产环境打包部署
    "test": "react-scripts test",   //单元测试
    "eject": "react-scripts eject"  //暴露配置项
  },
  "eslintConfig": {  //对webpack中ESLint词法检测的配置:包括检测词法错误、要求满足指定的规范等内容
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {  //基于browserslist规范,设置浏览器的兼容情况:例如
      					//1、postcss-loader + autoprefixer 给css3设置相关前缀
      					//2、babel-loader 把ES6编译为ES5
    "production": [
      ">0.2%",//忽略使用率小于0.2%的浏览器
      "not dead",//忽略IE
      "not op_mini all"//不考虑欧朋浏览器
    ],
    "development": [//不兼容低版本浏览器
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

2.暴露webpack配置项(非必须)

前置知识,学webpack

这里因为要深入学习故暴露配置项

2.1认识暴露后的文件目录

默认情况下,会把webpack配置项隐藏到node_modules中,如果想修改,则需要暴露配置项$ yarn eject

注意事项

1、一旦暴漏后,无法还原

2、 会提醒你先把代码提交到git区,避免暴露后覆盖原始代码(必须上传代码)

3、这里需要用一个空的git库,建议先创建一个新的库,然后git add .git commit -m(不需要上传到远端)

暴露后多了config文件夹(webpack配置)、scripts文件夹(对应下文scripts中的内容,执行相关命令的入口文件)

/* 暴露后package.json中的变化 */
//可以参考之前webpack的笔记,
//TODO 目前是在github库中,以注释为笔记,以后写入blog
{
  "dependencies":{  //暴露后,把webpack打包需要的所有模块都会安装一次,这里简写了
  	//有例如babel、单元测试、postcss、sass-loader等等
    //一些记录:
    //babel-preset-react-app:是对@babel/preset-env的重写,为了react
     ...
  },
  "scripts": {
    "start": "node scripts/start.js",  
    "build": "node scripts/build.js",
    "test": "node scripts/test.js"
    //不在基于react-scripts处理命令,而是直接基于node去执行对应的文件
    //已经没有eject命令了
  },
   //没变
  "jest": {
    //单元测试配置
  },
  "babel": {  //关于babel-loader的额外配置,类似babel.config.js对bebal-loader的额外配置
    "presets": [
      "react-app"//基于react重写的babel包
    ]
  }
}

/* 新增的内容 */
|- scripts
    |- start.js
    |- build.js
    |- ...
|- config
    |- webpack.config.js
    |- paths.js
    |- ...

2.1.1 QUER一些疑惑:

cra为什么没有区分开发依赖,和生产依赖?

2.2真实项目中常用的一些修改操作

简单演示了如果配置less的流程,并不是目前开发必要的。sass和less按喜好来。当然文章是less。

2.2.1配置less

2.2.1.1 安装命令行:
  $ yarn add less less-loader@8  #安装8版本,为了兼容。(不确定你看的时候兼容了没)
  $ yarn remove sass-loader  #卸载sass
2.2.1.2 配置

vscode折叠代码块(方便看)

折叠所有 Ctrl+K+0(零)

展开所有 Ctrl+K+J

配置对应less的内容,其实就是把sass名改为less

/*config\webpack.config.js*/
// 72~73
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

//507~545
//在module——rules——第二个大括号——oneof——某个大括号中
{
  test: lessRegex,
  exclude: lessModuleRegex,
  use: getStyleLoaders(
    ...
    'less-loader'
  )
},
{
  test: lessModuleRegex,
  use: getStyleLoaders(
    ...
    'less-loader'
  ),
}

注意是改两次,一个lessRegex,一个lessModuleRegex

2.2.1.3写入一个less文件用于测试
//src\index.less
@B:lightblue;

html,
body {
  height: 100%;
  background: @B;
}

然后导入index.jsx

//src\index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.less';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <div>zono 无敌</div>
);

待其他配置完之后测试

2.2.2 配置别名

配置一个别名,这样以后@就能直接访问src目录

//config\webpack.config.js
resolve: {
  ...
  alias: {
    '@': path.appSrc,//设置别名,指向src目录
    ...
  }
}

2.2.3 配置预览域名

可以修改端口号,有两种方式

// scripts/start.js
// 48
const HOST = process.env.HOST || '127.0.0.1';

// 也可以基于 cross-env/ 设置环境变量,先安装cross-env(dotenv也行)
// 安装:yarn add cross-env
// 然后在package.json中修改start:“cross-env POST=8080 node scripts/start.js”
2.2.3.1 QUER一点疑惑

QUER:为什么localhost下使用cross-env设置的POST不生效

这是因为在webpackDevServer.config.js中,会对host进行判断,如果是localhost,就会使用默认的端口(生成的答案待解决)

2.2.4 配置跨域代理

我们可以看见paths.proxySetup中指定了读取跨域文件的位置(在paths.proxySetup中搜索paths.proxySetup),也就是src/setupProxy.js

/*
安装 http-proxy-middleware:用于实现跨域代理,webpack-dev-server也是基于这个
$ yarn add http-proxy-middleware

src/setupProxy.js
*/
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
    app.use(
        createProxyMiddleware("/api", {
            target: "http://127.0.0.1:7100",
            changeOrigin: true,
            ws: true,
            pathRewrite: { "^/api": "" }
        })
    );
};

//测试地址:
//https://www.jianshu.com/asimov/subscriptions/recommended_collections
//测试写法
const createProxyMiddleware = require("http-proxy-middleware");
module.exports = function (app) {
  app.use(
    createProxyMiddleware("/jian", {
      target: "https://www.jianshu.com/asimov/",
      changeOrigin: true,
      pathRewrite: {
        "^/jian": "",
      },
    })
  );
};
//https://news-at.zhihu.com/api/4/news/latest

测试

fetch()

也能配置到package.json中,但因为json的原因,只能配置一个

2.2.4.1 QUER一些疑惑:

别尝试这个了,配置后会有跨域问题,我还不会解决

TODO 学习node中间件

2.2.5配置浏览器兼容(可选)

解决老版本浏览器兼容

修改兼容后对postcss-loader、babel-loader生效,但对ES6内置API不兼容

可以用@babel/polyfill,但脚手架中不需要我们来自己安装,因为有react-app-poly(看package.json)

index.jsx中加入

import 'react-app-polyfill/ie9';
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
//package.json
//https://github.com/browserslist/browserslist
"browserslist": {
  "production": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
  ]
}
/*
回顾知识点

CSS兼容处理:设置前缀
autoprefixer + postcss-loader + browserslist

JS兼容处理:ES6语法转换为ES5语法
babel-loader + babel-preset-react-app(@babel/preset-env) + browserslist

JS兼容处理:内置API
入口配置react-app-polyfill
*/

ps:每次配置都可以yarn start测试一下效果

其余的一些优化配置、响应式布局的配置等,实战中再去处理!!