深入浅出 Create React App

作者: hylerrix | 来源:发表于2020-01-10 10:33 被阅读0次

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

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

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

    本文面向的读者是:

    • 前端开发初学者或 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 不直接相关的技术点会略略而过,欢迎从点到面主动学习更多。以下是官方源码仓库以及官方文档地址:

    项目的文件结构

    通过命令行的构建,我们初始化了第一个 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 打包入口文件,通常链接整个业务代码;后者是页面模板,是打包后整个静态页面的总入口。

    这里对以下两个文件的出现进行简要的意义概括。<br />_

    • 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 技术栈了。

    相关文章

      网友评论

        本文标题:深入浅出 Create React App

        本文链接:https://www.haomeiwen.com/subject/zgdpactx.html