前端公共模块替换

背景

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

前端公共模块替换_第1张图片

目前,采用这三种技术栈的页面都存在,需要全部更换。

改变前:

前端公共模块替换_第2张图片

改变后:

前端公共模块替换_第3张图片

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应用很好地集成。

前端公共模块替换_第4张图片

sitemesh如何工作?

SiteMesh 充当 Servlet 过滤器,拦截返回到 Web 浏览器的HTML,提取相关内容并将其合并到称为装饰器的模板中。过滤器将任何 html、jsp 或其他 Web 框架页面的内容放入称为装饰器的预定义模板中

前端公共模块替换_第5张图片

sitemesh在卖家中心中的应用

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

前端公共模块替换_第6张图片

卖家中心的执行流转时序图如下:

前端公共模块替换_第7张图片

(1)webagent网关服务中的路由配置如下,/agentBuy/seller/*请求会经过seller-center拦截,而seller-center服务中没有/agentBuy/seller/*请求的controller层,会继续匹配网关路由,走到agentBuy服务中

前端公共模块替换_第8张图片

image-20211027145018176.png

(2)agentBuy服务中有/agentBuy/seller/*请求的controller层,返回被装饰的内容区域html页面

(3)seller-center拦截返回到web浏览器的html,提取其中相关内容(headbody)并将其合到装饰页面模板中(

前端公共模块替换_第9张图片

公共模块是怎么注入的?

在上面模板尾部中有注入以下脚本:

翻阅代码发现页面中的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 = prePath + asset;
      head.appendChild(link);
    }
    if (/\\.js$/.test(asset)) {
      var body = document.getElementsByTagName("body")[0];
      var script = document.createElement("script");
      script.src = 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),然后再加载渲染其他子应用,但是如何控制加载渲染子应用的顺序呢?毕竟其他子应用是挂载在公共子应用里面的。

前端公共模块替换_第10张图片

因此,调整公共模块只需要修改公共子应用(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...

你可能感兴趣的:(前端公共模块替换)