一文带你揭秘前端资源无感升级的终极解决方案!

前言

在前端项目的部署过程中,我们经常会遇到一些问题,例如:如何在部署新版本时,避免影响到正在使用的用户?如何实现前端资源的无感升级?本文将通过 Ant Design Pro 项目为例,介绍如何将项目部署到腾讯云 COS,并修改 index.html 绑定的 JS 和 CSS 地址,从而实现前端资源的无感升级。

方案

在前端开发中,HTML、JS和CSS是三个主要组成部分。为了实现前端资源的无感升级,我们需要在更新JS和CSS资源时,确保用户能够在刷新页面后立即获取到最新的HTML,并渲染更新后的页面。所以方案很清晰:

  1. 使用版本控制策略:
    • 在更新JS和CSS资源时,可以通过添加hash值来区分不同的版本。这样,每次更新资源时,文件名会发生变化,从而避免浏览器缓存导致用户无法获取到最新资源的问题
  2. 动态更新HTML资源链接:
    • 在更新JS和CSS资源后,需要同步更新HTML中绑定的资源链接
  3. 利用浏览器缓存策略,合理设置HTTP缓存策略:
    • HTML不设置缓存:为了让用户每次刷新页面都能拿到最新的HTML
    • JS和CSS设置缓存:与HTML不同,我们希望浏览器能够缓存JS和CSS资源,以提高页面加载速度

大白话,就是通过切换index.html中绑定的资源,来实现无感升级。接下来我们具体操作一下

准备工作

首先,我们需要准备以下工具和资源:

  1. 一个已经创建好的 Ant Design Pro 项目
  2. 腾讯云账号,并开通 COS 服务
  3. Serverless Framework

步骤一:部署到腾讯云 COS

  1. 登录腾讯云控制台,进入 COS 管理页面,创建一个新的存储桶,设置存储桶的权限为公有读。

  2. 将存储桶设置成静态网站,这样可以直接通过域名访问 COS 存储桶目录下的index.html 文件

  3. 在 Ant Design Pro 项目根目录下新建 deploy/index.ts 文件,用于编写部署脚本:

typescript 复制代码
注意:安全起见,COS 的 SecretId/SecretKey 不能保存到前端代码中

// 关键代码
import COS from 'cos-js-sdk-v5';
import compressing from 'compressing';

const upload = (data, key) => {
    cos.uploadFile({
        Bucket: 'examplebucket-1250000000', /* 填入您自己的存储桶,必须字段 */
        Region: 'COS_REGION',  /* 存储桶所在地域,例如ap-beijing,必须字段 */
        Key: 'dist.zip',  /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
        Body: data, /* 必须,上传文件对象,可以是input[type="file"]标签选择本地文件后得到的file对象 */
        onFileFinish: function (err, data, options) {   /* 非必须 */
           console.log(options.Key + '上传' + (err ? '失败' : '完成'));
        },
    }, function(err, data) {
        console.log(err || data);
    });
}


// 执行文件压缩
compressing.zip
  .compressDir(distPath, zpiPath)
  .then(() => {
    console.log('压缩成功,准备上传');

    const data = fs.readFileSync(zpiPath);

    upload(data, 'dist.zip')
  })
  .catch((error) => {
    console.log('压缩失败', error);
  });

压缩打包文件目的是为了方便传输和存档,在处理回滚操作时,我们只需要解压对应的压缩包,就可以获取到回滚资源了

  1. COS 中有很多方便的工具可以用,有现成的工具可以对上传到 COS 中的 zip 文件进行解压,直接开启工具就好。利用 SCF 对 COS 中的 ZIP 文件进行解压。具体安装方法请参考官方文档:cloud.tencent.com/document/pr...

  2. 在 Ant Design Pro 项目根目录下,运行 npm run build 命令,将项目打包成静态资源。

  3. 在 package.json 中新建一条命令 "deploy": "npx tsx ./deploy/index.ts",并执行 npm run deploy, 将静态资源 ZIP 包上传到 COS 存储桶。

至此,我们已经将 Ant Design Pro 项目部署到了腾讯云 COS,接下来我们需要配置 Hash 路由,以及修改 index.html 绑定的 JS 和 CSS 地址。

步骤二:修改打包配置

为了实现版本的功能,我们还需要对配置文件进行一定的修改

  1. 在 Ant Design Pro 项目的 config.ts 文件中,设置打包配置:
javascript 复制代码
export default defineConfig({
  // 若不开启 hash 路由,在访问 COS 资源后,刷新浏览器会出现找不到资源的问题
  history: { type: 'hash' },
  /**
   * @name 开启 hash 模式
   * @description 让 build 之后的产物包含 hash 后缀。通常用于增量发布和避免浏览器加载缓存。
   * @doc https://umijs.org/docs/api/config#hash
   */
  hash: true,
  /**
   * 开启后,会生成 asset-manifest.json 文件,记录了打包后的资源名
   */
  manifest: {
    basePath: './'
  },
  ...
});
  1. 动态修改打包配置,确定打包后的访问路径
ini 复制代码
// 确定压缩包的名称
const uuid = uuidv4();
const afterDistName = `${uuid}-dist`;
const distPath = path.resolve(__dirname, `../../${afterDistName}`);

// 改写 config ,打包
export const onChangeConfig = (afterDistName = '') => {
  const configPath = path.resolve(__dirname, '../../config/config.ts');
  const configString = fs.readFileSync(configPath, { encoding: 'utf-8' });
  const old = 'export default defineConfig({';
  const now = `export default defineConfig({publicPath:'/${afterDistName}/',`;

  /* 每次打包都会生成新的 publicPath,这就相当于 `版本号` */
  // 改 config 中的 publicPath
  const newStr = configString.replace(old, now);

  fs.writeFileSync(configPath, newStr);
};

结合步骤一,就可以将带有版本号的 dist 资源上传到 COS

步骤三:修改 index.html 绑定的 JS 和 CSS 地址

  1. 更新 index.html 文件中绑定的 JS、CSS 资源地址,并将新版的 index.html 上传到 COS
javascript 复制代码
// distPath | afterDistName:步骤二中获取

// 更新index.html
const rewriteIndexHtml = (time = '') => {
  // 替换 html
  const htmlPath = `${distPath}/index.html`;
  const content = fs.readFileSync(htmlPath, { encoding: 'utf-8' });

  const jsonData = require(`${distPath}/asset-manifest.json`)
  const js = jsonData['./umi.js']
  const css = jsonData['./umi.css']

  // 更新 index.html 中绑定的资源
  const newContent = content.replace(js, `/${afterDistName}${js}`).replace(css, `/${afterDistName}${css}`)
  
  // 步骤一 中上传 COS 的代码
  // 将新的 index.html 上传到 COS,替换旧版本的 index.html
  upload(newContent, 'index.html)
}

步骤四

处理资源缓存,这里只需要处理 index.html 的缓存,进入 COS 对应的存储桶,点击编辑 index.html

json 复制代码
    'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0'
    'Expires': '0'

最终 COS 中的文件结构:

至此,我们已经修改了 index.html 绑定的 JS 和 CSS 地址,实现了前端资源的无感升级。当我们需要更新项目时,只需重新打包并上传静态资源到 COS 存储桶,用户刷新页面,就可以看到最新的内容。

前端部署,只需要执行npm run build && npm run deploy

彩蛋

以上所有的步骤都是通过前端 node 脚本实现,如果需要实现版本回滚的功能,就需要借助 Serverless 和数据库的能力(数据库也只是用于记录 afterDistName 值),我们的回滚功能只要读取历史 afterDistName 的值,然后重复 步骤三即可

js 复制代码
/** Serverless 中的伪代码 **/

// 模板页面
function readIndexHtml() {
    return `<html><head><meta charset="utf-8" /><title>Serverless COS Demo</title></head><body><h1>Serverless COS Demo</h1><select id="js-selector">{optioins}</select><script>
document.getElementById('js-selector').addEventListener('change', function () {
    const newJsUrl = this.value;
    // 此处可以换成 【步骤三】 的逻辑
    alert(newJsUrl)
});
</script></body></html>`
}

exports.main = async (event, context) => {
try {
    // 获取切换版本的 UI 代码,用于浏览器渲染
    const indexHtml = readIndexHtml();
    
    // 这里使用 mock 数据。实际业务中,应该从数据库中,获取当前所有版本
    const versions = ['js_url1', 'js_url2', 'js_url3']
    const versionStr = versions.map(item => `<option value="${item}">${item}</option>`).join('')
    // 重组 html
    const newIndexHtml = indexHtml.replace('{options}', versionStr)
    
    return {
        isBase64Encoded: false,
        statusCode: 200,
        headers: { 'Content-Type': 'text/html' },
        body: newIndexHtml,
    };
} catch (err) {
    return {
        isBase64Encoded: false,
        statusCode: 500,
        headers: { 'Content-Type': 'text/plain' },
        body: 'Error',
    };
}

};

需要开通外网 HTTP 访问 Serverless 函数的服务

这样我们就可以通过访问 Serverless 进行版本切换

总结

本文以 Ant Design Pro 项目为例,介绍了如何将项目部署到腾讯云 COS,并结合 Serverless 的能力,实现前端资源的无感升级。通过这种方式,我们可以在项目更新时,让用户无感的升级到最新的版本,提升用户体验。

需要注意的是,这种方式适合个人项目。如果需要更加安全和高效的方式,还是需要结合后台数据库和接口实现

相关推荐
小远yyds15 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱1 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai1 小时前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨1 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking2 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓3 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4113 小时前
无网络安装ionic和运行
前端·npm
理想不理想v3 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试