项目部署以及版本更新检测

简介

在前端开发中,检测网站版本是否有更新是一个非常场景的需求。那么具体有哪些方式可以实现这一需求呢? 下面我就来分享一下我所接触到的方案

部署

部署一个react项目

在开始检测页面版本更新需求之前,我们先使用docker+nginx来部署一波react项目。因为我们需要模拟线上的真实环境。

  1. 创建React项目
ts 复制代码
npx create-react-app version-detect --template typescript

PS:这里我采用pnpm包管理器,脚手架默认采用的是npm包管理器此时通过pnpm import命令将npm项目转为pnpm项目

  1. 编写dockerFile文件用于构建镜像 首先来看一下docker的结构图,如下图可以看出宿主机docker项目之间的依赖关系。那么接下来就来编写dockerFile文件
  • 在项目的根目录创建.dockerignore文件用指定要忽略的文件和目录

    .git
    node_modules

  • 在项目的根目录创建Dockerfile文件用编写指定image的代码。指定镜像分为如下两个步骤
    步骤一: (构建前端静态的资源)

bash 复制代码
# 将node节点命名为builder
FROM node:17-alpine AS builder
# 指定工作目录
WORKDIR /app
# 将当前目录下的所有文件复制到工作目录当中。
COPY . ./
# 安装pnpm包管理器
RUN npm install -g pnpm
# 安装node_modules并且进行打包
RUN pnpm install && pnpm build

PS: FROM ...(基础镜像) AS ...(别名)就是给这个阶段的镜像起个别名,在后面引用这个阶段的镜像时直接使用别名
步骤二: (构建ngnix服务)

ts 复制代码
# 基于nginx镜像构建
FROM nginx:alpine
# 将工作目录设置为nginx静态资源目录
WORKDIR /usr/share/nginx/html
# 删除之前存在的默认文件
RUN rm -rf ./*
# 从builder中将/app/build复制到当前目录里
COPY --from=builder /app/build .
# 全局运行nginx并且关闭进程守护
ENTRYPOINT ["nginx", "-g", "daemon off;"]

最终代码如下:

  • 在项目中执行docker build ~构建镜像我们的镜像.如果你的Dockerfile
erlang 复制代码
docker build -t version-detect-nginx .

构建完成之后,就可以通过docker images命令或者用可视化桌面Docker Desktop看到构建的镜像了

  • 最后通过docker run ~来运行此项目,
ts 复制代码
# docker run 是指通过一个镜像启动一个容器,-p是一个端口映射,容器里面Nginx默认为80, 8080是指定宿主机端口, -d就是后台运行。--name version-detect-project就是定义容器的名字,version-detect-nginx就是指定镜像的名字
docker run  -p 8080:80 -d --name version-detect-project version-detect-nginx

Docker Desktop的用法 最终就可以通过http://localhost:8080/来访问部署好的react项目了

版本检测

通过上面的步骤,我们完成了基于docker+nginx的react项目部署,接下来我们就来实现版本更新检测的功能

唯一hash值

  1. hash文件的生成
    创建hash.js文件,生成一个唯一值用于标识当前版本
ts 复制代码
const crypto = require('crypto');
const fs = require('fs');
const data = crypto.randomBytes(16).toString('hex');
const hash = crypto.createHash('sha256').update(data).digest('hex');
fs.writeFile('./build/hash.txt', hash, (err) => {
  if (err) throw err;
});

修改package.json下的build命令

json 复制代码
 "build": "react-scripts build && node ./hash.js",

运行build命令之后就会生成hash.text文件 2. 在react项目添加轮训,请求hash.text文件。每隔1s请求一次。

ts 复制代码
 const oldHash = useRef(null)
  useEffect(() => {
    loopTimer();
  }, [])

  // 使用setTimeout模拟setInterval
  function loopTimer() {
    let timer: any = null;
    const interval = async () => {
      try {
        const { data } = await axios.get('/hash.txt')
        if (oldHash.current && oldHash.current !== data) {
          console.log('检测到版本更新了');
        } else {
          oldHash.current = data
        }
      } finally {
        timer = setTimeout(interval, 1000);
      }
    };
    setTimeout(interval, 1000);
    return {
      cancel: () => {
        clearTimeout(timer);
      },
    };
  }

重新打包react项目,然后重新部署。可以看到控制台打印了检测到版本更新了字段。然后我们就可以愉快的提示用户刷新页面了

通过HEAD请求

我们也可以通过轮训获取到当前项目协商缓存字段Etag来判断版本是否有更新。因为我们不需要获取到响应体只需要响应头的Etag数据即可,因此采用HEAD方法来实现

ts 复制代码
  // 使用setTimeout模拟setInterval
  function loopTimer() {
    let timer: any = null;
    const interval = async () => {
      try {
        const { headers } = await axios.head('')
        if (oldEtag.current && oldEtag.current !== headers.Etag) {
          console.log('检测到版本更新了');
        } else {
          oldEtag.current = headers.Etag
        }
      } finally {
        timer = setTimeout(interval, 1000);
      }
    };
    setTimeout(interval, 1000);
    return {
      cancel: () => {
        clearTimeout(timer);
      },
    };
  }

更新react项目重新部署之后etag发生了变化,因此就可以判定版本更新了

其他

当然你也可以使用SSE方案由后端主动告知前端版本更新等,本来想用nestJS实现一下的但时间有限,而且也不难可以参考神光大佬的实现方式

PS: 如果公司所有项目都需要检测项目版本是否更新可以编写webpack插件,让插件去注入轮询代码,这样子就不需要自己手动的一个个项目去编写注入了

本文的github demo链接地址

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试