迫于课程实践要做一个在线教学直播平台,就拿 React 练练手吧。

既然是一个教学直播平台,就先起名叫做 SooMooc 了 🎉

技术栈说明

  • React:前端框架
  • React Ant Design:组件库
  • OBS:直播推流工具
  • livego:直播服务器
  • flv.js:网页视频播放器

初始化项目

因为之前有看过一个 React + TypeScript 的实战视频,这次干脆也试着用 TS 写咯。

先在命令行创建项目。

1
2
npm install -g create-react-app
npx create-react-app soomooc --template typescript

修改一下 tsconfig.json 里的 compilerOptions,修改一下 baseUrl,便于以后的 import 操作。

1
"baseUrl": "./src",
code

antd

安装 antd 样式库。

在 TypeScript 中使用 - Ant Design

1
yarn add antd

修改 src/App.css,在文件顶部引入 antd 的样式。

1
@import '~antd/dist/antd.css';

craco

为了实现主题的自定义和模块化的 CSS 书写方式,我们需要安装 craco 插件,注意这里有两个包。

1
2
3
4
# 自定义主题
yarn add @craco/craco craco-less
# 模块化书写 CSS
yarn add @emotion/styled

安装完之后在根目录新建一个文件 craco.config.js,可以在这里自定义主题配色、字体等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const CracoLessPlugin = require('craco-less')

module.exports = {
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {
// '@primary-color': 'rgb(0, 82, 204)',
'@font-size-base': '16px',
},
javascriptEnabled: true,
},
},
},
},
],
}

这里把字体大小设置成 16px,是为了方便后续可以设置成 font-size: 62.5% ,最终实现1rem = 10px

修改一下 App.css

1
2
3
4
5
6
7
html {
font-size: 62.5%;
}
html body #root .App {
min-height: 100vh;
}

顺便改一下 package.json 里面的命令脚本。

code

commitlint

安装 commitlint,用于规范 git 提交格式。

conventional-changelog/commitlint: 📓 Lint commit messages (github.com)

  1. 安装库

    1
    yarn add @commitlint/config-conventional @commitlint/cli -D
  2. 在项目根目录新建文件 commitlint.config.js

    1
    module.exports = {extends: ['@commitlint/config-conventional']}
  3. 安装并配置 husky,用于在 git commit 前进行格式检查。

    1
    2
    3
    4
    5
    6
    7
    8
    # Install Husky v6
    yarn add husky --dev

    # Activate hooks
    yarn husky install

    # Add hook
    npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

提交格式如下:

1
git commit -m <type>[optional scope]: <description>

常用 type:

  • build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
  • ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
  • docs:文档更新
  • feat:新增功能
  • fix:bug 修复
  • perf:性能优化
  • refactor:重构代码(既没有新增功能,也没有修复 bug)
  • style:不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等)
  • test:新增测试用例或是更新现有测试
  • revert:回滚某个更早之前的提交
  • chore:不属于以上类型的其他类型(日常事务)

直播组件 demo

参考 gwuhaolin/reflv: react component wrap flv.js (github.com)

先写一个播放器的 demo,熟悉一下推拉流所需要的技术栈。

新建 src/components 文件夹,存放通用组件。

新建 src/screens 文件夹,存放页面相关组件。

image-20210508204130604

live-player.tsx

live-player.tsx 组件是对 flv.js 的封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { useEffect, useRef } from 'react'
import flvjs from 'flv.js'

interface LivePlayerProps {
type?: string
url: string
}

export const LivePlayer = (props: LivePlayerProps) => {
const flvRef = useRef<flvjs.Player>()
const videoRef = useRef<HTMLVideoElement>(null)
useEffect(() => {
if (flvjs.isSupported()) {
flvRef.current = flvjs.createPlayer({
type: 'flv',
isLive: true,
cors: true,
...props,
})
if (videoRef.current) {
flvRef.current.attachMediaElement(videoRef.current)
flvRef.current.load()
}
}
}, [props])

return (
<div className={'video-container'}>
<video ref={videoRef} className={'video'} width="80%" controls>
{`Your browser is too old which doesn't support HTML5 video.`}
</video>
</div>
)
}

demo.tsx

demo.tsx 界面组件用于展示播放器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* @jsxImportSource @emotion/react */
import { LivePlayer } from 'components/live-player'
import styled from '@emotion/styled'

export const Demo = () => {
return (
<PlayerContainer>
<h2 css={{ 'font-size': '3rem' }}>SooMooc Demo</h2>
<LivePlayer url="http://localhost:7001/live/demo.flv" type="flv" />
</PlayerContainer>
)
}

const PlayerContainer = styled.div`
text-align: center;
`

App.tsx

将 demo 界面组件包到 App 里。

1
2
3
4
5
6
7
8
9
10
11
12
import './App.css'
import { Demo } from 'screens/demo'

function App() {
return (
<div className="App">
<Demo/>
</div>
)
}

export default App

直播流程

在本地试用一下这个播放界面。

在开始推流之前,要先知道推流的地址,本项目使用 livego 作为推拉流的中介服务器。

在 GitHub 的 livego 上直接下载最新版 release 安装即可,我这边是 windows 版。

当然你也可以按照说明里下载源码自己进行编译

安装完成后直接在本地打开 livego.exe 运行服务器即可。

image-20210508212204659

可以看到这边的 RTMP 的接口是 1935,由于我们的服务器架在本地,所以推流的服务器地址应该是 rtmp://localhost:1935

主播需要安装并打开 OBS,对需要分享的屏幕进行自定义,点击左下角 ➕ 可以添加文字、图片、摄像头等。

image-20210508210837652

点击右下角设置,在推流界面填写我们刚刚知道的服务器地址和密钥。

image-20210508213903915

在 OBS 界面点击开始推流,此时 OBS 右下角会显示推流的速度和时间等信息。

image-20210508214024788

回到项目根目录,确认一下 demo.tsx 中的拉流地址是否一致。

1
<LivePlayer url="http://localhost:7001/live/demo.flv" type="flv" />

运行 React 项目。

1
yarn start

打开浏览器即可看到

image-20210508221140389

本地推拉流延迟大约2-3s,第一步大功告成。image-20210509193426944