关于微前端实现原理与 ngx-planet(四) 服务端渲染

本贴最后更新于 1480 天前,其中的信息可能已经沧海桑田

1.为什么要服务端渲染

因为公司后端服务在 k8s 上,是分布式的微服务,之前端全部打包部署在了物理机器(虚拟机)nginx 上,如果通过 helm 做应用商店的话,nginx 前端这部分无法处理,包括灰度部署,CI 等,全部都只能做到接口级别的处理,并不能连带静态资源文件一起处理,所以基于分布式的前端整改迫在眉睫。

偶然发现了 ngx-planet,整篇文章基于前几篇文章,可以看之前的几篇文章。

2.如何基于 ngx-palnet 进行服务端渲染

2.0 有路由前缀的情况下服务端渲染 ngx-planet 如何改进

image.png

start 函数中监听路由阶段,其中的 startWith 过滤路由要把 location.pathname 修改好,要将前缀去除掉,至于如何动态去除不写死,仁者见仁智者见智。

2.1 首先,准备打包好的静态文件

build 命令修改,注意 --deploy-url 的意思是,打包完成后,静态资源路径是什么

"build": "ng build --prod --deploy-url=/static/star-universe/ --base-href=/star-universe",

image.png

打包后的 index.html 如图,静态资源路径变成了 /static/star-universe 前缀,这里和 base-href 不能冲突,否则在渲染时有死循环问题

其次 base-href 就是项目访问路径前缀

然后修改 angular.json 中的 build 放到你的静态资源目录,这样在执行 npm run build 后静态资源自动放入后台项目中的静态目录中

image.png

2.2 准备 Portal 后台项目

我的项目基于 SpringBoot 自动生成,项目结构如下

image.png

以下是用到的 maven 配置文件

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.yunzainfo.cloud</groupId> <artifactId>star-universe</artifactId> <version>0.0.1-SNAPSHOT</version> <name>star-universe</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

一个 Controller 负责重定向路由到 index.html

package com.yunzainfo.cloud.staruniverse.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; @Controller public class StaticController { @RequestMapping(value = {"/star-universe", "/star-universe/**"}) public String index(HttpServletRequest request) { System.out.println(request.getRequestURI()); return "index"; } }

portal 的静态资源处理,通过实现 WebMvcConfigureraddResourceHandlers 函数,注意函数传参数的静态资源路径谓 /static/star-universe/** 要和 --deploy-url 对应起来,保证 index.html 中的静态资源被正确加载

package com.yunzainfo.cloud.staruniverse.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/star-universe/**").addResourceLocations("classpath:/static/"); } }

然后是 portal 的 applicaiton.yml,给一个端口吧,这里我选择的是 3000,和 proxy.config 中的相同,至于静态资源路径为什么是 /static 也是为了和注册应用时的路径保持一致

server: port: 3000 spring: thymeleaf: cache: false prefix: classpath:/static/

关于 app.component 中的应用注册,resourcePathPrefixmanifest 全都加入应用路径完成远程注册

[ { "name": "star-dust", "hostParent": "#wormhole", "hostClass": "star-dust", "routerPathPrefix": "/star-dust", "stylePrefix": "star-dust", "resourcePathPrefix": "http://localhost:3001/static/star-dust/", "loadSerial": true, "preload": false, "switchMode": "coexist", "scripts": [ "main.js" ], "styles": [ "styles.css" ], "manifest": "http://localhost:3001/static/star-dust/manifest.json" } ]

2.3 准备子项目前台项目

同样修改 buildangular.json 然后打包

2.4 准备子项目后台项目

这里唯一和 portal 项目不同的时,要加入跨域访问允许,因为 portal 加载 js/css 的时候是远程加载的。

package com.yunzainfo.cloud.stardust.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.*; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/star-dust/**").addResourceLocations("classpath:/static/"); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowCredentials(true) .allowedOrigins("http://localhost:3000", "http://localhost:3001", "http://localhost:3002", "http://localhost:3003") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .maxAge(3600) .allowCredentials(true); } }

其余和 portal 一致,只是路径不一样

3.看效果

image.png

image.png

这样,静态资源全都被远程请求过来了

4.这种远程技术可以运用到什么地方

首先组件共享的好处不说了,结合了后端微服务的 真正的 前端微服务而不是依托于 nginx 静态部署的前端微服务

可以优化开发流程,可以做灰度部署了,可以完善 CI 了等等,好处也有,坏处也有。有利有弊,看各自需要吧。

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...