深刻浅出 Create React App

本文差点难产而死。由于总结的过程当中,屡次怀疑本文是对官方文档的直接翻译和简单诺列;同时官方文档很全面,全范围的介绍无疑加深了写做的心智负担。但在最终的梳理中,发现走出了一条不同凡响的路,因而坚持分享出来。javascript

但愿本文除了能带领咱们再次了解 Create React App(后文简称 CRA) 外,还能提供一种不一样的知识组织结构和技术视角,加深咱们对整个 React 技术生态的理解。css

本文多是多篇博客的综合体,整理和写做时间 15h+,仔细阅读时间 30min+,请慢用。

本文面向的读者是:html

  • 前端开发初学者或 React 初学者;
  • 使用过 CRA 搭建 React 项目但想拓展相关知识面的人;
  • 但愿经过一篇文章快速复习 CRA 的人;
  • 英文初学者,想要经过一篇中文技术文章来让本身接下来读英文文档再也不困难的人;
  • 以及就想点进来支持一下的人。

其次,本文在对官方文档进行必定的从新编排下,加上了以下创新点以完善总体的阅读学习体验:前端

  • 添加了实战 1:使用单个 HTML 文件构建 React App;
  • 添加了实战 2:使用 Webpack 手动构建 React App;
  • 添加了实战 3:使用 CRA 一站式构建 React App;
  • 添加了实战 4:使用 Source Map Explorer 分析打包文件;
  • 添加了实战 5:在已有的 React 项目中引入/升级 CRA;
  • 添加了实战 6:使用 React App Rewired 注入新配置;
  • 添加了:对 CRA 将来版本的简单展望;
  • 添加了:一个 Dan 十年回顾文章的导读。

最终,本文不涉及源码的解读,想要阅读源码的同窗能够移步官方源码仓库,总体设计思路并非很难,具体实现原理能够细细品嚼;且本文对与 CRA 不直接相关的技术点会略略而过,欢迎从点到面主动学习更多。如下是官方源码仓库以及官方文档地址:java

初始化 React App 的多种方式

常见的初始化 React App 的方式有:node

  • 不使用构建工具构建 React App;
  • 使用 Webpack 手动构建 React App;
  • 使用 Create React App 一站式构建 React App;
  • 在在线沙箱平台直接构建 React App(通常用于 Demo 预演,本文不涉及)。

下面咱们分别进行介绍与实战练习。react

实战 1:使用单个 HTML 文件构建 React App

React 自己专一于构建用户界面,并不依赖于某个构建工具,所以咱们能够用传统的方式引入 React 并书写第一个“Hello World!” App。这种方式是快速尝试 React 的好方法,但并不适用于正式开发。webpack

如下 HTML 代码段是一种实现方式,使用了可选的 Babel 编译和 JSX 语法,基于非构建工具的更多初始化页面的方法(如不使用 JSX 等)能够自行探索。git

<html>
  <head>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <!-- 不须要用于生产环境 -->
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('root')
      )
    </script>
  </body>
</html>

实战 2:使用 Webpack 手动构建 React App

构建工具备不少种,目前最为主流的构建工具当属 Webpack。如何使用 Webpack 逐步构建 React App?github

果不其然,为了证实 CRA 的便捷性而引出的本节 Webpack 实战,耗费了一小时多的时间进行了亲自踩坑,搜索了较多的博文都因为发布时间性而不能和最新的版本进行融合,最终根据 Github 中 react-webpack-babel 库的 package.json 文件里的相关信息才获得实现。
# 建立一个项目并进入该项目
$ mkdir react-webpack-steper & cd react-webpack-steper
# 使用默认选项直接生成一个初始化的 package.json
$ npm init -y
# 安装 React 基础包
$ sudo npm install --save react react-dom
# 安装 Webpack 相关工具 - 打包、本地启动支持、本地异步请求模拟以及热更新等
$ sudo npm install --save webpack webpack-cli webpack-dev-server
# 安装 Babel 相关工具 - 提供 ES6+ 新功能支持
$ sudo npm install --save-dev @babel/cli @babel-core @babel/preset-env @babel/preset-react
$ sudo npm install --save-dev babel-loader babel-plugin-module-resolver html-webpack-plugin
# 新建打包、编译配置文件并准备编写
$ touch webpack.config.js
$ touch .babelrc
# 新建 React 文件
$ mkdir src
$ touch src/index.js
$ touch src/index.html

其中,webpack.config.js 源码以下:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: path.resolve(__dirname, './src/index.js'),
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
    ]
  },
  resolve: {
    extensions: ['*', '.js', '.jsx']
  },
  output: {
    path: path.resolve(__dirname, './build'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './src/index.html')
    })
  ]
}

.babelrc 源码以下:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    ["module-resolver", {
      "root": ["./src"]
    }]
  ]
}

src/index.html 源码以下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Hello World!</title>
</head>
<body>
  <div id="root">Loading...</div>
</body>
</html>

src/index.js 源码以下:

import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
)

此时,一个基于 Webpack 手动搭建的简易型“Hello World”App 开发完成,能够经过以下命令本地运行。

$ webpack-dev-server --mode development --open --hot

更多自定义内容如添加 devServer 支持、添加多页应用支持...等各类各样新技术栈的支持,也能够引伸实战。

所以,咱们须要 CRA

可见,不使用构建工具编写不切实际,使用构建工具手动搭建 React App 又很繁琐。所以咱们须要一个能初始化一个可直接运行项目的工具,并提供各类简易的插件,Create React App 应运而生。

CRA 适用于中小型 React 项目。

CRA 的设计哲学

  • 一种依赖关系。尽管 CRA 使用了 Webpack,Babel,ESLint 等各类出色的项目,但咱们只须要 CRA 一种依赖;从 CRA 生成项目的 package.json 中也能够看到并无 Webpack、Babel 的痕迹。
  • 无需配置。咱们无需进行任何额外配置即可以直接运行代码,专一业务开发;同时 CRA 还提供了开发和生产版本的合理配置。
  • 非锁定配置。只须要运行一个命令, 全部的配置项和构建依赖项都将直接“弹出”到项目中,交由咱们来修改。

CRA 包含了什么?

CRA 将具备构建现代单页 React 应用所需的一切:

  • React,JSX,ES6,TypeScript 和 Flow 语法支持;
  • ES6+ 标准的支持,例如对象传播运算符;
  • CSS 自动添加前缀的支持,所以咱们不须要 -webkit- 或其余前缀;
  • 快速的交互式单元测试运行程序,内置对覆盖率报告的支持;
  • 实时开发服务器,警告常见错误;
  • 一个构建脚本,用于将 JS,CSS 和图像与哈希和源映射捆绑在一块儿进行生产;
  • 知足全部渐进式 Web 应用程序标准的 ServiceWorkerWeb 应用程序清单 支持 (注意:从react-scripts@2.0.0及更高版本开始支持 ServiceWorker);
  • 单一依赖项便可轻松更新上述工具。

CRA 的使用场景

Create React App 很是适合:

  • 在方便且功能丰富的开发环境中学习 React;
  • 快速启动新的单页 React 应用程序;
  • 快速使用 React 为库和组件建立示例。

若是咱们想在没有数百个传递构建工具依赖的状况下尝试 React,请考虑使用单个 HTML 文件构建或使用在线沙箱平台构建。

  • 若是须要将 React 代码与服务器端模板框架(如 Rails,Django 或 Symfony)集成,或者若是不构建单页应用,请考虑使用更灵活的 nwbNeutrino。特别是对于 Rails,可使用 Rails Webpacker。对于 Symfony,请尝试 Symfony's Webpack Encore
  • 若是须要发布 React 组件,nwb 以及 Neutrino 的 react-components preset 也能够这样作;
  • 若是要使用 React 和 Node.js 进行服务器渲染,请查看 Next.jsRazzle。 Create React App 与后端无关,仅生成静态HTML / JS / CSS包;
  • 若是网站大部分是静态的(例如,投资组合或博客),请考虑改用 Gatsby。与 Create React App 不一样,它在构建时会将网站预先渲染为 HTML;
  • 最后,若是须要更多自定义设置,请查看 Neutrino 及其 React preset

CRA 支持的浏览器

一些支持的浏览器规则以下:

  • 默认状况下,生成的项目支持全部现代浏览器。 对 Internet Explorer 九、10 和 11 的支持须要 polyfill。 对于一组支持旧版浏览器的 polyfill,请使用 react-app-polyfill
  • 默认状况下,生成的项目在 package.json 文件中包含一个 browserslist 配置,以针对基于全球使用状况(> 0.2%)的普遍浏览器(用于生产构建)和用于开发的现代浏览器。 这提供了良好的开发体验,尤为是在使用异步/等待等语言功能时,但仍与生产中的许多浏览器保持高度兼容性;
  • browserslist 配置控制输出的 JavaScript,以使注入的代码与指定的浏览器兼容。 经过运行构建脚原本建立生产构建时,将使用生产列表,而在运行启动脚本时,将使用开发列表。 可使用 https://browserl.ist 查看配置的浏览器列表支持的浏览器;
  • 请注意,这不会自动包括 polyfills,仍然须要根据所支持的浏览器来添加语言功能(见上文);
  • 在编辑 browserslist 配置时,咱们的更改可能不会当即被获取。 这是因为 babel-loader 中的一个未检测到 package.json 中更改的问题。 一种快速的解决方案是删除 node_modules/.cache 文件夹,而后重试。

这里的重点是 BrowsersList,一个“在不一样的前端工具之间共用目标浏览器和 node 版本的配置工具”。简而言之,就是 Babel 等转移工具经过咱们设置的 BrowsersList 中想要支持的浏览器版原本决定哪些语法须要被编译。

CRA 支持的 ES 标准

一些支持的 ES 标准规则以下:

CRA 的两个核心库

Create React App 有两个核心库,以下:

  • create-react-app 是全局命令,用于建立初始化的 React 项目;
  • react-scripts 是所生成的项目中的开发依赖项,包括运行项目、测试项目、打包项目等多种命令。因为 CRA 的一种依赖性原则,react-scripts 便开放了全部内部其它依赖的使用方式。

实战 3:使用 CRA 构建 React App

到这里,咱们终于须要经过命令行来安装和使用 CRA,来构建咱们的第三个“Hello World”App。

全局安装 CRA

为保证每个新项目都能使用到 CRA 最新最全的功能,请确保 CRA 为最新版本。

# 再已安装 CRA 的状况下,能够先卸载 CRA
$ npm uninstall -g create-react-app
# 正式安装 CRA
$ npm install -g create-react-app

初始化 CRA 项目

根据咱们的 npm 版本,选择相应命令来安装最新版的 CRA 并初始化第一个项目。同时检查本身的 node 版本,须要在本地开发计算机上安装 Node 8.16.0 或 Node 10.16.0 或更高版本(但服务器上不须要)。 咱们可使用nvm(macOS / Linux)或 nvm-windows 在不一样项目之间切换Node版本。

# 查看本身的 npm 版本
$ npm --version

# 第一种新建项目方式——npm 5.2+ 时,如下命令会安装最新版 CRA
$ npx create-react-app my-app
# 第一种新建项目方式——npm 版本小于等于 5.1 时
$ create-react-app my-app

# 第二种新建项目方式
# npm 6+ 开始支持 npm init <initializer> 
$ npm init react-app my-app

# 第三种新建项目方式
$ yarn create react-app my-app

项目的文件结构

经过命令行的构建,咱们初始化了第一个 CRA 项目,其中帮咱们生成的项目目录结构以下(只有 src 下的文件才会被 Webpack 处理,只有 public 下的文件才能被 public/index.html 使用):

my-app
├── .git # 隐藏文件夹,会初始化第一个 Commit 记录
├── README.md
├── node_modules
├── package.json # 依赖配置文件
├── .gitignore
├── [floder_name] # 根目录下能够创建其余文件夹,但不会被用在生产环境中
├── public # 只有 public 下的文件才能被 public/index.html 使用
│   ├── favicon.ico
│   ├── index.html # public/index.html 页面模板
│   └── manifest.json
└── src # 只有 src 下的文件才会被 Webpack 处理
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── [floder_name] # 能够创建其余文件夹,以被 Webpack 成功导入
    ├── index.css
    ├── index.js # JavaScript 打包入口文件
    ├── logo.svg
    └── serviceWorker.js

关于 package.json、index.js 和 public/index.html 文件夹,咱们经过“实战 2”已经有所了解。前者是 JavaScript 打包入口文件,一般连接整个业务代码;后者是页面模板,是打包后整个静态页面的总入口。

这里对如下两个文件的出现进行简要的意义归纳。
_

  • src/serviceWorker.js:提供渐进式 Web 应用的核心功能,不论网络情况如何都能当即加载,而且在不须要网络请求(离线时)的状况下也能展现 UI ;
  • public/manifest.json:是渐进式 Web 应用将自身添加至桌面的功能依赖文件,也能够对图标、名称等信息进行配置。

运行 CRA 项目

CRA 默认提供了运行、测试、打包、部署以及弹出项目的命令。其中的一些贴士:

  • npm start 内置热更新机制,代码改动时页面自动刷新;
  • npm test 以交互方式运行测试观察程序,默认状况下运行与自上次提交以来更改的文件相关的测试;
  • npm run build 将要生产的应用程序生成到生成文件夹。它在生产模式下正确捆绑了React,并优化了构建以得到最佳性能。生成文件被压缩,而且文件名包含哈希;
  • npm run eject 将内置的各类 Webpack 配置弹出到项目中,让咱们能够进行自定义。同时此操做不可逆,意味着咱们承担了弹出配置后的风险。一般不推荐弹出,能够经过 React App Rewired 库进行配置注入。
# ---- 运行 ----
$ npm start
$ open http://localhost:3000
# ---- 测试 ----
$ npm test
# ---- 打包 ----
$ npm run builds
# ---- 弹出配置 ----
$ npm run eject

搭建 CRA 生态

根据官方文档的思路,咱们还能从更多角度拓展 CRA 的使用边界,下面进行概要介绍。

  • 为开发环境添加额外功能:包括“配置编辑器风格”、“开发隔离组件”、“分析打包文件”和“添加 HTTPS 支持”;
  • 添加样式与静态资源支持:包括“添加样式表文件”、“添加 CSS Modules 支持”、“添加 Sass 支持”、“添加 PostCSS 支持”、“添加图片文字和字体支持”、“添加 GraphQL 支持”、“使用 public 文件夹”、“进行代码拆分”;
  • 添加业务驱动支持:包括安装各类依赖项如“BootStrap”、“Flow”、“TypeScript”、“Delay”、“Router”,以及“导出组件”、“使用全局变量”、“配置环境变量”、“制做渐进式 Web 应用”和“建立生产环境”;
  • 添加测试支持:包括“运行测试”和“调试测试”;
  • 添加后端集成支持:包括“在开发环境中代理 API 请求”、“使用 AJAX 请求获取数据”、“集成后端 API”和“使用 Title & Meta 标签”;
  • 部署进阶:包括“静态服务器”、“Azure”、“Firebase”、“Github Pages”等平台的部署等。

这里没法深刻展开,每个点均可以是一个新的实战,当咱们须要某个功能时即可以查阅相关文档来主动探索。其中“分析打包文件”的解读见“实战 4”。

实战 4:使用 Source Map Explorer 分析打包文件

# 安装文件分析工具 source-map-explorer
$ sudo npm install --save source-map-explorer
# 打包项目
$ npm run build
# 将以下命令放入 package.json 中并生成快捷方式 npm run analyze
# $ source-map-explorer 'build/static/js/*.js'
# 注意此命令直接在命令行输入会提示找不到相关命令
$ npm run analyze

对于一个刚被 CRA 生成的 React App 来讲,分析的结果以下,包大总计 129.38k。

实战 5:在已有的 React 项目中引入/升级 CRA

回到刚才“实战 2”创建的 react-webpack-steper 项目中,当咱们已经编写了一部分业务时,可否直接在当前项目中无痛引入 CRA?

解决思路即是:在大多数状况下,更改 package.json 中的 react-scripts 版本并删除没必要要文依赖配置,接着在此文件夹中运行 npm install 就足够了,但最好参考更改日志以了解潜在的重大更改。CRA 致力于将重大更改保持在最低限度,以即可以轻松升级 React 脚本。

# 卸载 CRA 自己已经提供的依赖
$ sudo npm uninstall --save webpack webpack-cli webpack-dev-server
$ sudo npm uninstall --save-dev @babel/cli @babel-core @babel/preset-env @babel/preset-react
$ sudo npm uninstall --save-dev babel-loader babel-plugin-module-resolver html-webpack-plugin
# 删除 CRA 不须要使用的文件
$ rm webpack.config.js .babelrc
# 删除 node_modules
$ rm -rf node_modules
# 手动安装 React Script
$ sudo npm install --save react-scripts@latest
# 因为 CRA 默认规则,将 src/index.html 移至 public/index.html
$ mkdir public
$ mv src/index.html public
# 在 package.json 中添加 React Script 启动命令
$ vim package.json

package.json 中添加/覆盖以下指令。

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

再次执行便可。因为每一个人的具体配置不必定一致,可根据自身所遇问题进行搜索。升级原理相似。

# 当没有 BrowsersList 时,CRA 会进行询问并帮助咱们生成
$ npm start

实战 6:使用 React App Rewired 注入新配置

CRA 官方并不推荐使用 npm run eject 弹出配置,这会增长更多的 Webpack 维护工做。对于实在想改的 Webpack 配置来讲,咱们可使用 React App Rewired 库进行配置注入,这里来作个小例子。

此工具能够在不 'eject' 也不建立额外 react-scripts 的状况下修改 create-react-app 内置的 webpack 配置,而后你将拥有 create-react-app 的一切特性,且能够根据你的须要去配置 webpack 的 plugins, loaders 等。

继续使用 react-webpack-steper 项目,咱们的简易目标是增长 devServer 本地代理。

第一步:安装依赖并进行基础配置

# 安装依赖
$ sudo npm install --save-dev react-app-rewired customize-cra
# 根目录创建 config-overrides.js
$ touch config-overrides.js
# 修改 package.json
$ vim package.json
# 运行项目
$ npm start

其中,config-overrides.js 的初始代码为:

/* config-overrides.js */
module.exports = function override(config, env) {
  //do stuff with the webpack config...
  return config;
}

package.json 的修改思路为:

/* package.json */
"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
- "build": "react-scripts build",
+ "build": "react-app-rewired build",
- "test": "react-scripts test --env=jsdom",
+ "test": "react-app-rewired test --env=jsdom",
  "eject": "react-scripts eject"
}

第二步:编写配置,进行代理

# 新增配置文件
$ mkdir config
$ touch config/proxy.js
# 修改 config-overrides.js
$ vim config-overrides.js

其中,config/proxy.js 源码是:

module.exports = {
  '/api/**': {
      target: 'http://110.114.120.120:8080',
      secure: false,
      changeOrigin: false,
  },
}

config-overrides.js 修改成:

const { overrideDevServer } = require('customize-cra')
const proxy = require('./config/proxy')

module.exports = {
  devServer: overrideDevServer((config) => {
      config.proxy = proxy
      return config
  }),
}

此时,本地的全部 api 开头的接口请求都会被转发到 http://110.114.120.120:8080 的模拟后端 IP 上。

对 CRA 将来版本的简单展望

截止目前(2020-01-10),CRA 的最新版本是 v3.3.0,咱们能够从 Github 的 MileStone 中看到将来可能会改善的功能,其中整理并以下所述。

  • v3.x:添加多入口文件支持(不仅是一个 index.js 入口);使用 worker-loader 添加对 WebWorker 的支持;更早地检查 Node 的版本;添加对子资源完整性 SRI 支持;生产环境中预加载脚本和连接...
  • v4.0:支持 Webpack 5.0(Webpack 目前最新版 v4.41.5,v5 也推出了一年多内测版);在 tsconfig.json 和 jsconfig.json 里新增对 baseUrl 和 paths 的支持(方便写 @ 绝对路径等);支持 Jest 配置中设置browser 为 true(根据环境提供正确的 Node 或 Browser 模块)...
  • v100.0:提供构建过程当中的监视模式;适用于 Hooks 的热加载...

让咱们一块儿持续关注。

结语

回顾文章,咱们从初始化 React App 的多种方式,引出 CRA 的必要性再对其进行较为充分的解释,最后配上 6 个角度来从一些角度对 CRA 的使用方式进行了实战,最后回归到 CRA 的版本展望之中。

感谢你的阅读,若是你有什么更多的疑惑,CRA 的官方文档 + 开源仓库必定会知足你的一切。

最后,一块儿拜读一下 CRA 和 Redux 做者、React 的核心贡献者 Dan Abramov 发布的这篇“个人十年回顾”文章。

如今咱们能够开始正式深刻地学习 React 技术栈了。

相关文章
相关标签/搜索