学习自动部署create-react-app

为什么要学习create-react-app部署

创建一个CI/CD工作流,CI/CD代表持续集成和持续部署。因此持续集成是一种实践,其中一个或多个协作者经常将代码提交到共享存储库。通过更频繁地提交代码,我们将更容易检测错误的来源,因此,我们将在本节中创建的工作流中需要做的是,每当有人在我们的存储库中提交一些代码时,我们需要确保这些代码不会破坏任何测试或引入任何错误。所以我们需要运行一些测试并确保它们成功运行,我们也可以检查其他的东西,例如:确保代码格式正确,以防我们遵循某种格式样式。我们也可以做其他事情,正如我们将看到的。但最后,在我们通过所有检查之后,我们需要将我们的代码部署到某个服务器中,所以为了尝试这些东西,我们需要有一个我们需要测试和部署的应用程序,所以就选用了样板 React 应用程序。

使用create-react-app的方法

  • 使用工具为:vscode

  • create-react-app 官方网站地址

  • 部署到的服务器网站:https://surge.sh

  • 确保本地机器安装了 nodejsnpm

本地 create-react-app项目的创建

  1. 在你需要创建项目的位置按 shift+鼠标右菜单 >在此处打开命令窗口在此处打开PowerShell窗口 输入:
    npx create-react-app react-app --use npm 如果出现Happy Hacking说明安装成功
    使用 npm 拉取项目,并在本地创建一个react-app文件夹存储项目文件。

  2. 然后 cd react-app 进入react-app文件夹

  3. code . 使用 vscode 打开所在文件,注意 命令中的 空格 和 “ . “

运行、构建、测试create-react-app项目

  1. 在vscode 中新建一个 终端 输入:
    npm run start 会在本地主机端口3000上打开我们的浏览器 localhost:3000,展示网页内容

  2. 如果我们在app.js中 删除 React 并保存,展示的网页也会随着改变。在命令中输入ctrl+c结束程序运行。

  3. 测试项目:先 clear 清除缓存,然后运行: npm run test
    如果你上面删除了 React 这个测试将会出现错误,因为文件不完整了,测试时App.test.js中的 screen.getByText(/learn react/i)有检查文件是否完整的作用。如果我们还原 React 保存,再运行 npm run test 时错误将会消失。

  4. 环境变量 CI 的作用:尽管我们建议在开发过程中以监视模式运行测试,但您可以通过传入标志来禁用此行为。在大多数 CI 环境中,系统会为您处理此问题。对于非 CI 环境,您可以传递 :
    --watchAll=false标志以禁用测试监视。CI 命令的使用方法:
    Windows (cmd.exe): set CI=true&&npm test set CI=true&&npm run build
    Windows (Powershell): ($env:CI = "true") -and (npm test) ($env:CI = "true") -and (npm run build)
    具体请参阅 官方说明

  5. 生成覆盖率报告。如果我们不熟悉测试,覆盖率报告可让我们知道测试了多少代码,哪些文件已测试,哪些没有测试等待。命令:npm run test -- --coverage 会在项目目录下生成一个 coverage 文件夹,打开react-app\coverage\lcov-report\index.html下的文件就能看到覆盖率报告。

  6. 构建应用:我们在部署项目到服务器的时候,并不会直接部署 react-app文件夹,这个文件夹只是保存源代码,也没有对项目进行优化,有我们在部署时不需要的 node_modules文件夹。我们在运行构建命令:
    npm run build 时,将会在项目目录下生成一个优化了的文件夹react-app\build build文件夹,他针对编写的代码进行了缩小和优化。

部署到网站服务器 surge.sh

  1. surge 是一个简单的静态网站,它只有html、css和javascript。

  2. 全局安装:npm install --global surge用于全局安装 Surge 这个静态网站和单页应用部署工具。在安装 Surge 之前,需要确保你的计算机上已经安装了 Node.js 环境。

  3. 部署到网站:运行命令:surge 时,如果你是第一次使用,则必须创建一个帐户

    PS D:\react-app> surge
    Welcome to surge! (surge.sh)
    Login or create surge account by entering email & password.
    email: 1907@qq.com
    password: # 输入密码时不会显示
    Running as 19807@qq.com (Student)
    project: D:\react-app\build
    domain: ruthless-toys.surge.sh # 这个是部署以后的访问网址
    size: 15 files, 544.1 KB
    upload: [=========================] 100%
    CDN: [=========================] 100%
    encryption: [=========================] 100%
  4. 修改以后的重新部署:如果我们 删除了 React 并保存,就需要重新部署。在cscode终端进行如下命令:
    构建修改的项目:npm run build
    重新部署修改的项目:输入 surge命令时会出现如下代码:

    PS D:\react-app> surge
    Running as 1907@qq.com (Student) # 这个是帐号
    project: D:\react-app\build # 这里需要输入 build 回车
    domain: auspicious-range.surge.sh # 这里和第一次部署时的域名不一样,需要修改成第一次部署时的域名,把这一行的内容全部删除 只余下如:"domain:" 然后在后面加上第一次部署时的域名,回车。
    #我这里是 domain: ruthless-toys.surge.sh

编码格式风格

如果想要让我们的代码遵循某种编码格式风格,让每个修改代码的人都遵循同样的格式样式,可以使用一个叫做Prettier 的工具,并且 Prettier 可以检查我们文件夹中的代码是否遵循某些格式规则,如果不正确,它将返回错误。

  1. Prettier网站

  2. 安装Prettier。这个安装不是全局安装,是在我们的项目中安装。
    npm install --save-dev --save-exact prettier

    PS D:\react-app> npm install --save-dev --save-exact prettier
    added 1 package in 5s
    264 packages are looking for funding
    run `npm fund` for details
    PS D:\react-app>
  3. 生成编码风格 打开这个网站 ,在左边的菜单选项中选择一些你自己喜欢的编码格式,然后在网页左下角的底部点击Copy config Json,就会将你选择好的编码格式复制到粘贴板上。
    然后在项目根目录下新建文件”.prettierrc”,将粘贴板上的内容粘贴到这个文件里保存。
    在根目录下再创建”.prettierignore”文件,它与”.gitignore”类似,都是让Prettier知道在格式化代码时想要忽略哪此文件。在这个例子中,我们确实不需要格式化”build”文件夹,因为它是自动生成的,还有”coverage”、“node_modules”文件夹,这些都是自动生成的。还有文件”package-lock.json”。那么这个文件的内容就如下所示:

    build
    coverage
    node_modules
    package-lock.json
  4. 格式化编码风格。现在我们有了编码格式配置和忽略的规则,我们就可以运行”Prettier”,因为我们不是全局安装Prettier,所以不能直接使用”prettier”这个命令,必须使用”npx prettier” 然后使用”check”标志。**/*.js要检查的文件类型。
    检查某些文件的格式是否正确。命令:npx prettier --check "**/*.js",运行后如下:

    PS D:\react-app> npx prettier --check "**/*.js"
    Checking formatting...
    [warn] src/App.js
    [warn] src/App.test.js
    [warn] src/index.js
    [warn] src/reportWebVitals.js
    [warn] src/setupTests.js
    [warn] Code style issues found in 5 files. Run Prettier with --write to fix.
    PS D:\react-app>

    如果我们运行**npx prettier –check检查代码,如果发现有未格式化的文件,它将返回一个非零退出代码,这意味着错误并且运行的工作流程将失败退出,这就是我们所需要的。

  5. Prettier 修改编码格式。Prettier不仅可以检查格式,还可以按标准强制修改代码。用vscode打开”react-app\src\App.test.js”文件,假设我们以正确的格式修复它,可以在终端中运行:
    npx prettier --write "**/*.js" 我们将修复任何格式不正确的JavaScript文件。

    PS D:\react-app> npx prettier --write "**/*.js"
    src/App.js 58ms
    src/App.test.js 10ms
    src/index.js 10ms
    src/reportWebVitals.js 7ms
    src/setupTests.js 3ms
    PS D:\react-app>

    从上面的代码可以看出,它已经修改了这个项目里的一些文件,还返回了已修复的文件列表。运行”clear”后,再次运行检查:npx prettier --check "**/*.js"时,应该不会收到任何错误。

    PS D:\react-app> npx prettier --check "**/*.js"
    Checking formatting...
    [warn] src/App.js
    [warn] src/App.test.js
    [warn] src/index.js
    [warn] src/reportWebVitals.js
    [warn] src/setupTests.js
    [warn] Code style issues found in 5 files. Run Prettier with --write to fix.
    PS D:\react-app> npx prettier --write "**/*.js"
    src/App.js 58ms
    src/App.test.js 10ms
    src/index.js 10ms
    src/reportWebVitals.js 7ms
    src/setupTests.js 3ms
    PS D:\react-app> npx prettier --check "**/*.js"
    Checking formatting...
    All matched files use Prettier code style!
    PS D:\react-app>
  6. 创建自动修改代码。上面的代码我们都是手动运行命令去修改的格式化,我们可以在package.json这个文件中加2个npm代码脚本。

    "scripts": {//下面的2行是新加的,在脚本中的代码不需要在前面加 NPM 命令。
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "format:check":"prettier --check \"**/*.{js,jsx,yml,yaml,json,css,scss,md}\"",
    "format":"prettier --write \"**/*.{js,jsx,yml,yaml,json,css,scss,md}\""
    },

    将上面的代码保存,然后在终端运行以下命令,就可以看到调用了上面的刚添加的脚本。

    PS D:\react-app> npm run format:check       # 如果是修改,就将 format:check替换为:format
    > react-app@0.1.0 format:check
    > prettier --check "**/*.{js,jsx,yml,yaml,json,css,scss,md}"
    Checking formatting...
    [warn] src/index.css
    [warn] Code style issues found in the above file. Run Prettier with --write to fix.
    PS D:\react-app>

    这样我们就有了一个可以在工作流程中运行的命令,以检查我们提交的代码格式是否与在”.prettierrc”中定义的规则相匹配,如果不匹配,将停止我们的工作流程,不会部署一些格式错误的代码

工作流程图示例

流程图

  • 假如有2个分支DevelopMaster都被锁定了,没人能直接将代码推入其中,如果有人想将代码推入其中,必须先打开一个拉取请求,然后这个拉取请求必须被批准合并到这些分支中的一个。主分支Master包含可部署的代码,Develop包含源码,除非我们想将代码部署到服务器,否则Develop分支它将不会有任何内容被推送到Master分支。

  • 假如现在有一名成员想要开发某一个功能,他将创建一个新分支Feature1,功能完成后,他将打开一个新的拉取请求,这时将运行一个工作流,检查他提交的代码格式是否符合我的标准规范,一旦通过检查,将会合并到Develop分支中,合并以后将再次运行一个工作流对Develop中的代码进行一次检查,同时将代码部署到某个临时服务器,所以我们将有2个Surge URL,一个用于正常使用,一个用于代码测试。假如现在Develop分支有足够的功能想要发布时,将打开一个请求合并到Master分支中,推送时将会运行一个工作流,检查代码格式是否正确,如果正确将被合并到Master分支中,合并后将会再次运行一个工作流,仔细检查测试和代码格式,然后将正式发布。

  • 第一步细节:

    graph LR
        a(Feature1) -->b(PullRequest)-->c(Run Workflow)-->|ok?Merge|d(Develop)

    Request将一个Feature分支合并到Develop中时,我们当然会安装我们的依赖项,因为在NPM的情况下,不会将node_modules文件夹中的项目依赖文件推送到存储库中,所以要运行项目的话,就要安装依赖项。接下来将检查代码格式——>运行代码测试——>生成覆盖率报告并上传覆盖率报告——>缓存依赖项以便下次运行。

编写工作流

新建属性文件

用vscode打开项目react-app文件夹,在根目录新建文件夹.github\workflowsworkflows文件夹下新建文件CODEOWNERS,这个文件中只需定义谁拥有存储库中的某些文件。

*  @jinwei26
*.js @jinwei26
*.yml @alialaa17
/public/ @jinwei26

上传项目到Github存储库

登录Github,点击右上角**+,然后点击New repository创建存储库,Repository name填入仓库名react-app,选中Public,点击下面的create repository**完成创建。停留在创建完成的这个页面先不要动,这个网页的创建存储库的信息在下面要使用到。

在vscode上新建终端,输入git init初始化项目文件夹下的**.git**文件夹。如果没有这个文件夹的话会自动创建这个文件夹。

git init
git add -A # 增加文件到推送队列。
git commit -m"init" # 设置推送信息

回到创建存储库完成后的信息页面,点击上面的SSh,下面的仓库链接地址也会跟着变化的。然后复制信息页上的git remote add origin [email protected]:<用户名>/react-app.git粘贴到终端回车,复制git push -u origin main到终端回车,如果没有错误,就可以在仓库中查看上传的项目了。如果出现错误:

error: src refspec main does not match any
error: failed to push some refs to 'github.com:jinwei26/react-app.git'

就是本地配置中的分支和远程仓库配置中的分支不统一。可以查看项目路径下react-app.git\refs\heads的文件是哪个名称,这个名称就是本地git配置的分支名称,看是否与远程仓库的分支相同,如果不相同,在终端中输入git branch -m master main将本地分支master修改为main`。

新建Develop分支

在Github仓库的项目名下,点击分支名边的下黑三角,在Find or create a branch…框中填入develop作为分支名,然后点击选项卡中的Create branch develop from main就会创建一个develop分支。

保护main分支和develop分支

在Github存储库中打开文件项目的齿轮型Setting,在左边的菜单栏中点击Branches,在网页右边显示的页面Branch protection rules中点击Add branch ruleset,然后在Ruleset Name中随便填入规则名。在下面的选择项中选中如下几项:

  • Require a pull request before merging(合并前需要拉取请求。要求所有提交都对非目标分支进行提交,并通过拉取请求提交,然后才能合并)
  • Required approvals(所需审批,1人批准,就选1)
  • Dismiss stale pull request approvals when new commits are pushed。 (推送新提交时忽略过时的拉取请求批准。推送的新的可审核提交将忽略之前的拉取请求审查批准)
  • Require review from Code Owners。(需要代码所有者审核。要求在修改具有指定代码所有者的文件的拉取请求中进行批准审查)
  • Require status checks to pass。(需要状态检查才能通过。选择在更新 ref 之前必须通过的状态检查。启用后,提交必须首先推送到检查通过的另一个 ref )
  • Require branches to be up to date before merging。(要求分支在合并前保持最新状态。是否必须使用最新代码测试针对匹配分支的拉取请求。除非至少启用一项状态检查,否则此设置不会生效)

然后点击下面的Create,可能会要求输入密码

创建工作流yml文件

在项目路径react-app.github\workflows下创建ci.yml文件,文件内容如下:

name: CI
on:
pull_request:
branches: [develop]
push:
branches: [develop]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "20.x"
- run: npm ci
- run: npm run format:check
#- run: npm test -- --coverage
env:
CI: true
- name: Build Project
if: github.event_name == 'push'
run: npm run build
- name: Deploy to Staging
if: github.event_name == 'push'
run: npx surge --project ./build --domain ruthless-toys.surge.sh
env:
SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }} # 登录surge用户名变量
SURGE_TOKEN: ${{ secrets.GITHUB_TOKEN }} # surge token

在vscode中打开的终端中输入命令surge token可以得到surge的token,surge whoami可以查看登录的邮箱。

PS D:\react-app> surge token
b39e96c164d8288a961161ab709e621a
PS D:\react-app> surge whoami
[email protected] - Student
PS D:\react-app>

在github仓库中打开react-app项目的设置网在左边菜单栏中点击Secrets and variables选择其下的Actions点击,在新网页中点击选项卡中的Secrets点击其下的New repository secret,然后添加变量。第一个变量名为:SURGE_LOGIN其值为邮箱[email protected],点击Add secret完成第一个变量添加,然后添加 第二个变量,名为SURGE_TOKEN,其值为b39e96c164d8288a961161ab709e621a添加完成后点击Add secret

使用包构建版本

semantic-release包构建release版本。在项目根目录下新建文件release.config.js代码内容:

module.exports = {
branches: "main",
repositoryUrl: "https://github.com/jinwei26/react-app",
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/github"
]
};

在上面的yml文件中新一个name

- name: Create a Release
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}