惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
O
OpenAI News
美团技术团队
月光博客
月光博客
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
Webroot Blog
Webroot Blog
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Tenable Blog
S
Security Affairs
博客园_首页
S
Schneier on Security
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
Spread Privacy
Spread Privacy
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
Vercel News
Vercel News
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 最新话题
D
DataBreaches.Net
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - Franky
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Check Point Blog
H
Hacker News: Front Page

动物的光合作用

使用 Peer Relay 提高 Tailscale 的速度 内网穿透下 NAS 使用 DNS 轮循作为负载均衡 <众安车保>上当指南 - 动物的光合作用 JS 中的 Shebang/Hashbang - 动物的光合作用 我的自建 NAS - 动物的光合作用 React 组件中复用代码的方式 - 动物的光合作用 负载均衡下的前端资源更新策略 - 动物的光合作用 CSS 基于视区的长度单位 - 动物的光合作用 Excalidraw 支持自定义字体 - 动物的光合作用 我用 Docker 部署的一些服务 - 动物的光合作用 CSS 书写模式和逻辑属性 - 动物的光合作用 Mac mini 搭建外网可访问的简易 NAS - 动物的光合作用 React Fragment 添加事件监听? - 动物的光合作用 如何在 React 解决竞态条件 - 动物的光合作用 使用脚本备份 Github 仓库 - 动物的光合作用 高性能 React 应用的几个小技巧 - 动物的光合作用 复习 DOM 事件 - 动物的光合作用 我的博客架构变迁之路 - 动物的光合作用 浏览器和 JavaScript 的一些新特性 - 动物的光合作用 useCallback 的误区 - 动物的光合作用 在 React 中使用事件分离状态 - 动物的光合作用 如何处理 RESTFUL 数据异常导致的前端错误 - 动物的光合作用 基于 Node.js 的 WebFont 解决方案
大量活动页面持续性维护的解决方案 - 动物的光合作用
mebtte · 2022-10-20 · via 动物的光合作用

大量活动页面持续性维护的解决方案

在我负责的业务里面, 有个项目用于存放运营活动页面, 通常情况下每次运营活动都会相应地搭配一个或数个活动页面. 这个项目使用 react 构建 UI, 活动页面没有 SEO 的需求, 所以采用的是浏览器渲染. 同时使用前端路由, 每个活动页面都是 react-router 的子路由. 随着时间的增长, 已经包含超过 150 个活动页面, 所有的页面加上基础的容器组件构成了一个超大的单体应用.

单体架构
单体架构

但是这个项目的架构并不合理.

首先, 各个活动页面之间并没有联系, 由于这是一个单体应用, 导致打开任何一个活动页面都会加载整个应用, 所以随着页面的增加, 应用的体积也会越来越大. 为了避免这种情况, 需要进行代码分割, 每个页面作为一个模块进行动态加载(dynamic import), 例如使用 react-loadable 或者 lazy + Suspense 的方式.

其次, 所有活动页面共用相同的依赖, 像是一些本地模块(components/utils/…)或者 npm package. 很多过期的活动页面只需要让运营或者用户能够访问到就可以, 其实已经不再需要维护了, 当修改本地模块或者升级 npm package 版本遇到不兼容的情况时, 需要修改所有调用的代码, 也包括不再维护的页面, 页面数量的增加会导致维护成本越来越高. 比如这个项目 react 的版本依然是 16, 升级到 18 的话需要调整大量已过期页面的 class component.

最后是打包的问题. 这个项目使用 webpack 构建, 生产环境下 150+ 页面需要 10 分钟以上的打包时间.

基于以上问题考虑, 我们创建了一个新的项目用于后面的活动页面, 这里有个仓库用于展示最小的在线 DEMO(Served by Vercel).

首先, 新的项目使用 Parcel 进行打包. 之所以使用 Parcel, 有这几个原因:

  • 支持 HTML 文件作为入口. 在 HTML 作为入口的情况下, 可以为每个活动页面建立自己的 HMTL 文件, 这样使得每个活动页面都是独立的子应用, 避免旧项目所有活动页面耦合的问题. 使用 webpack 也可以做到多个活动页面独立, 每个页面单独一个入口并添加页面对应的 html-webpack-plugin 或者一个页面对应一份 webpack 配置(webpack 配置支持数组), 不过这种方法会让 webpack 的编译速度大打折扣, 并且会导致修改代码后的增量编译非常慢.
  • 相对于 webpack, Parcel 的配置更加简单, 多数情况下可以做到零配置. 在这个项目上我们只添加了额外的插件, 而且新加页面的情况下完全不用修改配置.
  • Parcel 底层使用 SWC 作为编译器, SWC 使用 Rust 编写, 多核情况下编译速度是 babel 的 70 倍.
SWC
SWC

因为每个新页面都要创建对应的 HTMLJS 文件, 这种重复性的工作适合使用脚本减少工作量, 所以编写了新建页面的脚本, 通过 npm run new-page 就可以新建页面.

在旧项目上, 因为每个页面都是 react-router 的子路由, 所以必须使用 react 编写. 但是, 新项目每个页面都是彼此独立的子应用, 不必受制于其他页面使用的框架或者库, 可以实现 A 页面用的是 react, 而 B 页面用的是 vue. 所以新建页面的脚本预置了 react/vue/vanilla 三种模板, 当然, 也可以手动新建页面使用任何框架或者库.

通过脚本使用模板新建页面

页面增加导致的维护成本越来越高的问题, 也就是已完结的活动因为仍需要访问到页面, 所以不能删除页面源码, 修改过期页面涉及到的公共模块导致我们需要持续性地维护这些过期的页面, 页面数量越多, 维护的成本越高.

所以, 我们提出了归档的概念. 像这些过期的页面, 我们将编译后的产物提交到 git, 然后删除源码, 保证了页面的正常访问和避免了后续维护. 同时, 过期页面后续作为静态资源, 后续不需要重复编译, 避免了页面的累积导致编译时间越来越长的问题.

同样地, 我们使用脚本来进行归档, 归档的流程是这样的:

  1. 选择要进行归档的页面
  2. 利用 Parcel API 只编译归档的页面
  3. 将构建后的产物复制到 Parcel 的静态目录
  4. 移除归档页面的源码
归档一个页面

由于开发模式下 Parcel 不支持自动索引静态资源的 index.html, 所以要手动补全路径. 在测试和线上环境我们使用 nginx 提供静态资源服务, nginx 会自动索引 index.html, 所以访问 b.mebtte.com/bbbb.mebtte.com/bbb/index.html 是一致的.

为了降低维护成本, 避免同时维护新旧两个项目, 旧项目的活动页面会在全部活动结束后迁移到新的项目, 然后进行归档. 比如旧项目的域名是 a.mebtte.com, 新项目的域名是 b.mebtte.com, 在页面迁移到新项目并归档后, 只需要将 a.mebtte.com 通过 HTTP 301 重定向到 b.mebtte.com, 由于迁移过程中保证了页面的路径不变, 从而重定向后的 URL 能够正确地访问到页面, 实现了无缝切换.