前端公共模块替换

背景 公司中后台管理系统经历几年的迭代维护,其公共模块部分(HeaderSlider)的主题与现在UI风格不一致,需要更换。但是,该项目几年前的老项目了,技术栈在逐步的演进,初始是Freemaker引擎搭建的前后端未分离项目,后面部分旧页面采用React重构,新页面采用React开发,使用iframe标签嵌套React页面,再后来引入了微前端的概念,使用single-spa-react改造项目中的React页面。
前端公共模块替换
文章图片

目前,采用这三种技术栈的页面都存在,需要全部更换。
改变前:
前端公共模块替换
文章图片

【前端公共模块替换】改变后:
前端公共模块替换
文章图片

Freemarker 卖家中心中后台项目,每个页面都有相同的部分,比如顶部、导航、底部,如果每个页面都写一遍,等到项目庞大时,某天需要修改这些公共模块了,你需要将所有页面都改一遍,这真的很崩溃。但是sitemesh会让你轻松应对!
什么是sitemesh

SiteMesh is a lightweight and flexible Java web application framework that applies the Gang of Four decorator pattern to allow a clean separation of content from presentation.
SiteMesh 是一个网页布局和修饰的框架,利用它可以将网页的内容和页面结构分离,以达到页面结构共享的目的。
Sitemesh是由一个基于Web页面布局、装饰以及与现存Web应用整合的框架。它能帮助我们在由大
量页面构成的项目中创建一致的页面布局和外观,如一致的导航条,一致的banner,一致的版权,等等。
它不仅仅能处理动态的内容,如jsp,php,asp等产生的内容,它也能处理静态的内容,如htm的内容,
使得它的内容也符合你的页面结构的要求。甚至于它能将HTML文件象include那样将该文件作为一个面板
的形式嵌入到别的文件中去。所有的这些,都是GOFDecorator模式的最生动的实现。尽管它是由java语言来实现的,但它能与其他Web应用很好地集成。
前端公共模块替换
文章图片

sitemesh如何工作?
SiteMesh 充当 Servlet 过滤器,拦截返回到 Web 浏览器的HTML,提取相关内容并将其合并到称为装饰器的模板中。过滤器将任何 html、jsp 或其他 Web 框架页面的内容放入称为装饰器的预定义模板中
前端公共模块替换
文章图片

sitemesh在卖家中心中的应用
在公司卖家中心的中后台项目中,我们将sitemesh拦截器与Application拆成独立的服务,分别对应着seller-center拦截服务和agentBuy应用服务,因为使用sitemeshweb容器可能有多个,将sitemesh独立拆出来可以复用。因此,架构图变成如下形式:
前端公共模块替换
文章图片

卖家中心的执行流转时序图如下:
前端公共模块替换
文章图片

(1)webagent网关服务中的路由配置如下,/agentBuy/seller/*请求会经过seller-center拦截,而seller-center服务中没有/agentBuy/seller/*请求的controller层,会继续匹配网关路由,走到agentBuy服务中
前端公共模块替换
文章图片

前端公共模块替换
文章图片

(2)agentBuy服务中有/agentBuy/seller/*请求的controller层,返回被装饰的内容区域html页面
(3)seller-center拦截返回到web浏览器的html,提取其中相关内容(headbody)并将其合到装饰页面模板中(
前端公共模块替换
文章图片

公共模块是怎么注入的?
在上面模板尾部中有注入以下脚本:

翻阅代码发现页面中的Header、Slider部分并不是在上面模板中实现的,而是通过script引入seller-react-frame.js,并执行脚本将Header DOM、Slider DOM分别注入到
seller-react-frame.js是在seller-react-frameReact)项目中生成的,该项目中实现了HeaderSlider组件并指定挂载的元素,构建项目会生成jscss资源文件。构建完后再执行一个脚本,该脚本会写入一个自执行函数到seller-react-frame.js文件,自执行函数的作用是将asset-manifest.json资源清单中的jscss动态注入的页面中
// seller-react-frame项目 // 1、构建命令 "build": "cross-env PUBLIC_URL=./ react-app-rewired build && node ./scripts/build-entry-js.js",// 2、入口文件 import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import { TopBar, SideBar } from "@casstime/seller-components"; import "@casstime/seller-components/style.scss"; ReactDOM.render(, document.getElementById("seller-topbar")); ReactDOM.render(, document.getElementById("seller-sidebar")); // 3、执行build-entry-js.js生成seller-react-frame.js const fs = require("fs"); const assetManifest = require("../build/asset-manifest.json"); const entries = assetManifest.entrypoints; fs.writeFileSync( "./build/seller-react-frame.js", `; (function loadAssets() { var scripts = Array.from(document.getElementsByTagName('script')); var targetScripts = scripts.filter(function(item) {return item.src.indexOf('seller-react-frame.js') > -1}); var prePath = ''; if (targetScripts.length) { var targetScript = targetScripts[0]; prePath = targetScript.src.slice(0, targetScript.src.indexOf('seller-react-frame.js')); } ${JSON.stringify(entries)}.forEach(function(asset) { if (/\\.css$/.test(asset)) { var head = document.getElementsByTagName("head")[0]; var link = document.createElement("link"); link.rel = "stylesheet"; link.href = https://www.it610.com/article/prePath + asset; head.appendChild(link); } if (//.js$/.test(asset)) { var body = document.getElementsByTagName("body")[0]; var script = document.createElement("script"); script.src = https://www.it610.com/article/prePath + asset; body.appendChild(script); } }); })(); ` );

因此,如果我们需要调整公共模块,只需要修改HeaderSlider组件,并重新构建、部署seller-react-frame。如果遇到缓存问题拉取的不是最新seller-react-frame.js,则需要刷一下CDN
Freemarker + iframe Freemarker + iframe跟纯使用`Freemarker唯一的不同点就是内容变化的区域只有一个架子,里面使用iframe页面嵌套React页面,比如:
// 内容变化区域 ftl <#include "../includes/head_storemgr.ftl" > <#assign userLoginId = User.getUserId()>

其他公共模块还是由seller-react-frame.js脚本注入的。因此,调整公共模块还是需要修改HeaderSlider组件,并重新构建、部署seller-react-frame
microfe 公司微前端项目稍微有点特殊,基座项目(microfe-seller-base)中并没有包含公共模块,而是将公共模块也抽离成子应用。基座项目根据路由首先加载渲染公共子应用(microfe-seller-common),然后再加载渲染其他子应用,但是如何控制加载渲染子应用的顺序呢?毕竟其他子应用是挂载在公共子应用里面的。
前端公共模块替换
文章图片

因此,调整公共模块只需要修改公共子应用(microfe-seller-common)工程,然后重新构建、部署。
参考:
https://docs.huihoo.com/sitem...
https://en.wikipedia.org/wiki...
http://www.blogjava.net/over1...
https://zhuanlan.zhihu.com/p/...
https://blog.csdn.net/xuanwug...

    推荐阅读