React应用的离线预缓存、性能优化与发布指南
1. 离线预缓存(Precache: Work Offline)
渐进式Web应用(PWA)的核心功能之一是能够离线工作,我们可以使用
serviceWorker
来实现这一点。在使用Create React App(CRA)时,
serviceWorker
包含在
index.tsx
文件中。
1.1 启用离线功能
默认情况下,CRA中的
serviceWorker
是未注册的,代码如下:
serviceWorker.unregister()
要启用离线功能,只需将
serviceWorker
的状态改为注册:
serviceWorker.register()
在生产环境构建时,我们可以在
index.tsx
组件中添加如下代码:
const rootElement = document.getElementById('root')
if (rootElement && rootElement!.hasChildNodes()) {
hydrate(<AppRouter />, rootElement)
serviceWorker.register()
} else {
render(<AppRouter />, rootElement)
}
// serviceWorker.unregister()
再次构建项目(
$ yarn build
)后,会出现一个新文件:
build/precache-manifest.[string].js
。
1.2 验证离线功能
要查看
serviceWorker
的工作情况,需要再次运行发布构建脚本:
$ yarn build:serve
打开Chrome开发者工具的Network标签,在Size列中可以看到显示为
ServiceWorker
。此时,关闭网络连接,或者在Chrome开发者工具的Network标签中勾选
Offline
复选框,刷新应用,应用仍然可以正常工作,就像在线一样。
1.3 离线工作原理
CRA的Workbox默认预缓存策略是
CacheFirst
,即静态资源首先从
service worker
缓存机制中获取,如果失败则发起网络请求。Workbox支持不同的策略,如
CacheOnly
、
NetworkFirst
等,但如果要使用除默认策略之外的其他策略,可能需要将CRA项目弹出(eject)。更多关于此功能的信息可以查看:https://create-react-app.dev/docs/making-a-progressive-web-app/。
2. 使用useCallback记忆函数
在使用
useEffect
和自定义函数时,可能会出现无限循环的问题。例如:
useEffect(() => {
draw()
})
const draw = () => {
// TODO
}
useCallback()
可以帮助解决这个问题,它可以与
useEffect()
一起使用,防止函数的重新创建。示例代码如下:
useEffect(() => {
memoizedDrawCallback()
}, [memoizedDrawCallback])
const memoizedDrawCallback = useCallback(() => {
// TODO using data as dependency
}, [data])
通过将函数包装在
useCallback
中,并定义函数的依赖项,可以确保只有当依赖项发生变化时,函数才会重新创建。例如,可以在依赖项数组中列出所需的数据或属性:
[props.bottom, props.data, props.fill, props.height, props.left, props.right, props.top, props.width]
这样,
memoizedDrawCallback
函数在每次渲染DOM周期更新时不会重新构建,从而避免了潜在的无限循环。
3. 选择启动项目
在开发React应用时,选择合适的启动项目非常重要。以下是一些需要考虑的因素:
3.1 开发阶段发布构建的原因
在开发阶段创建发布构建很重要,因为它能提供比使用已优化且准备好部署的库更真实的构建。在项目开发过程中,代码的更改可能很大,因此需要不断创建发布构建,而不是等到冲刺阶段结束的最后一刻才发现构建失败或无法按预期工作。建议快速且频繁地进行发布,甚至一天发布两次。
3.2 选择工具
在选择发布工具时,有许多付费和免费的解决方案可供选择,这可能会让人感到不知所措。以下是一些常见的选择:
| 类型 | 工具 | 说明 |
| ---- | ---- | ---- |
| 免费解决方案 | GitHub pages、Vercel、Firebase、Netlify、Heroku等 | 适用于概念验证(POC)或小型非商业项目 |
| 付费解决方案 | Amazon AWS(Lambda用于无服务器)、Azura(Azure Functions用于无服务器)、Alibaba cloud(Function Compute用于无服务器)等 | 传统的服务器解决方案或无服务器解决方案 |
需要注意的是,许多免费解决方案在扩展时通常会开始收费,因此需要仔细检查和考虑。同时,建议记录项目的设置过程,以避免被特定的解决方案束缚,因为价格和条款经常变化。
3.3 SPA vs. SSR
在决定使用React作为Web技术后,首先需要决定是将应用作为单页应用(SPA)还是使用服务器端渲染(SSR)。
-
SPA
:渲染在客户端进行,外部资源使用有限。
-
SSR
:应用能够在服务器上显示内容,而不是像单页应用那样在浏览器中渲染。
使用SSR的优点包括减轻用户机器负担和能够与后端Node.js共享代码,但缺点是会增加应用的复杂性,并且在服务器繁忙时会降低响应时间。如果已经在使用SPA或SSR,并且需要在两者之间进行转换,由于React组件的设计理念,只要组件构建正确,就可以通过移动组件来设置项目。
3.4 SPA和SSR启动项目
选择SSR或SPA后,需要选择启动库。以下是一些常见的启动项目:
-
CRA
:Facebook推荐的启动项目,基于SPA技术。将其转换为纯SSR应用是可能的,但需要弹出项目并自行管理配置。
-
Next.js
:最流行的基于SSR的React启动项目,被许多成功的公司使用,如Netflix、GitHub、Hulu和Uber。
-
其他启动库
:Gatsby(提供无服务器渲染)、React Boilerplate(专注于离线模式和可扩展性)、React Slingshot(使用一些有主见的库构建)、Razzle(基于SSR,无需配置)等。
此外,也可以从头开始创建项目,自行安装所需的库并管理配置,虽然这样需要更多的设置工作,但可以确保项目完全符合需求。
4. 创建和发布SSR应用(Next.js)
4.1 设置Next.js启动项目
使用以下命令创建一个简单的Next.js React项目,并使用D3库:
$ yarn create next-app
在终端提示输入项目名称时,可以选择自己喜欢的名称,例如
nextjs-ts-chart
。安装完成后,切换到项目目录:
$ cd nextjs-ts-chart
下载完库后,运行应用:
$ yarn run dev
$ open localhost:3000
4.2 安装TypeScript
Next.js默认使用JS,但建议为项目设置TypeScript以进行类型检查:
$ yarn add -D typescript @types/react @types/node
运行这些库后,
tsconfig.json
文件会自动添加到项目中。
4.3 安装D3
安装D3的
select
模块:
$ yarn add d3-selection @types/d3-selection
4.4 创建Rectangle.tsx组件
在项目中创建一个
components
文件夹,并添加
Rectangle.tsx
组件:
// components/Rectangle/Rectangle.tsx
import React, { useEffect, RefObject } from 'react'
import { select } from 'd3-selection'
const Rectangle = () => {
const ref: RefObject<HTMLDivElement> = React.createRef()
useEffect(() => {
draw()
})
const draw = () => {
select(ref.current).append('p').text('Hello World')
select('svg').append('g').attr('transform', 'translate(250, 0)').append('rect').attr('width', 500).attr('height', 500).attr('fill', 'tomato')
}
return (
<div className="Rectangle" ref={ref}>
<svg width="500" height="500">
<g transform="translate(0, 0)">
<rect width="500" height="500" fill="green" />
</g>
</svg>
</div>
)
}
export default Rectangle
4.5 更新index.ts
将
index.js
改为
index.ts
,并添加
Rectangle.tsx
组件,同时移除其他代码:
// src/component/pages/index.tsx
import Rectangle from "../components/Rectangle/Rectangle"
import styles from '../styles/Home.module.css'
import React from "react";
export default function Home() {
return (
<div className={styles.container}>
<Rectangle />
</div>
)
}
4.6 使用Express发布Next.js应用
4.6.1 安装express库
$ yarn add -D express
4.6.2 创建server.js文件
创建一个Express服务器文件,允许传递端口或设置默认端口为9000,并允许传递
NODE_ENV
以告知应用是在开发还是生产环境中运行:
// server.js
const express = require('express')
const next = require('next')
const port = process.env.PORT || 9000;
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log(`Server Ready on http://localhost:${port}`)
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
4.6.3 构建和部署应用
使用以下命令构建发布版本的应用:
$ yarn build
在本地部署应用时,需要在终端中设置环境变量:
-
Windows
:
$ SET NODE_ENV=development
- macOS/Linux :
$ export NODE_ENV=development
通过以上步骤,我们可以实现React应用的离线预缓存、性能优化以及使用Next.js创建和发布SSR应用。这些技术可以帮助我们提高应用的性能和用户体验,同时根据不同的需求选择合适的启动项目和发布工具。
5. 选择发布工具的决策流程
为了更清晰地展示选择发布工具的决策过程,我们可以使用 mermaid 格式的流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始选择发布工具]):::startend --> B{是否需要免费方案?}:::decision
B -->|是| C{是否会大规模扩展?}:::decision
C -->|否| D(选择GitHub pages、Vercel等):::process
C -->|是| E(考虑付费方案):::process
B -->|否| E
E --> F{是否需要服务器?}:::decision
F -->|是| G(选择传统服务器方案如Amazon AWS等):::process
F -->|否| H(选择无服务器方案如Amazon Lambda等):::process
这个流程图展示了从开始选择发布工具到最终确定方案的决策过程。首先考虑是否需要免费方案,若需要则进一步考虑是否会大规模扩展;若不需要免费方案则直接考虑付费方案。在付费方案中,再根据是否需要服务器来选择传统服务器方案或无服务器方案。
6. 总结与最佳实践
6.1 性能优化总结
通过使用
serviceWorker
实现离线预缓存,我们可以让 React 应用在离线状态下正常工作,提高用户体验。同时,使用
useCallback
可以避免函数的不必要重新创建,防止潜在的无限循环,优化应用性能。以下是性能优化的关键步骤总结:
1.
启用离线预缓存
:
- 在
index.tsx
中注册
serviceWorker
:
serviceWorker.register()
- 构建项目:
$ yarn build
- 运行发布构建脚本:
$ yarn build:serve
-
使用
useCallback记忆函数 :
useEffect(() => {
memoizedDrawCallback()
}, [memoizedDrawCallback])
const memoizedDrawCallback = useCallback(() => {
// TODO using data as dependency
}, [data])
6.2 项目选择与发布总结
在选择启动项目和发布工具时,需要综合考虑多个因素,如项目需求、团队经验、成本等。以下是项目选择与发布的关键要点总结:
| 项目类型 | 特点 | 适用场景 |
| ---- | ---- | ---- |
| SPA(单页应用) | 渲染在客户端,外部资源使用有限 | 对响应速度要求高,交互性强的应用 |
| SSR(服务器端渲染) | 在服务器上显示内容,可减轻用户机器负担 | 需要更好的 SEO,对服务器性能要求较高的应用 |
在选择启动项目时,可以根据项目需求选择 CRA、Next.js 等不同的启动库。在发布应用时,根据项目规模和预算选择免费或付费的发布工具。
6.3 最佳实践建议
- 频繁发布 :在开发阶段频繁创建发布构建,及时发现和解决问题,避免在项目后期出现构建失败的情况。
- 记录设置过程 :详细记录项目的设置过程,包括使用的库、配置信息等,以便在需要时进行修改和迁移。
- 持续优化 :不断关注应用的性能指标,根据用户反馈和数据分析进行持续优化,提高应用的性能和用户体验。
通过遵循这些最佳实践,我们可以更高效地开发和发布 React 应用,为用户提供更好的服务。
总之,React 应用的开发和发布涉及多个方面的技术和决策。通过合理运用离线预缓存、性能优化技巧,选择合适的启动项目和发布工具,我们可以构建出高性能、用户体验良好的应用。同时,持续学习和实践,不断优化应用,才能跟上技术发展的步伐。
超级会员免费看
62

被折叠的 条评论
为什么被折叠?



