1.为什么要服务端渲染
因为公司后端服务在 k8s 上,是分布式的微服务,之前端全部打包部署在了物理机器(虚拟机)nginx 上,如果通过 helm 做应用商店的话,nginx 前端这部分无法处理,包括灰度部署,CI 等,全部都只能做到接口级别的处理,并不能连带静态资源文件一起处理,所以基于分布式的前端整改迫在眉睫。
偶然发现了 ngx-planet,整篇文章基于前几篇文章,可以看之前的几篇文章。
2.如何基于 ngx-palnet 进行服务端渲染
2.0 有路由前缀的情况下服务端渲染 ngx-planet 如何改进
在 start
函数中监听路由阶段,其中的 startWith
过滤路由要把 location.pathname
修改好,要将前缀去除掉,至于如何动态去除不写死,仁者见仁智者见智。
2.1 首先,准备打包好的静态文件
将 build
命令修改,注意 --deploy-url
的意思是,打包完成后,静态资源路径是什么
"build": "ng build --prod --deploy-url=/static/star-universe/ --base-href=/star-universe",
打包后的 index.html 如图,静态资源路径变成了 /static/star-universe
前缀,这里和 base-href
不能冲突,否则在渲染时有死循环问题
其次 base-href
就是项目访问路径前缀
然后修改 angular.json
中的 build
放到你的静态资源目录,这样在执行 npm run build
后静态资源自动放入后台项目中的静态目录中
2.2 准备 Portal 后台项目
我的项目基于 SpringBoot 自动生成,项目结构如下
以下是用到的 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 的静态资源处理,通过实现 WebMvcConfigurer
的 addResourceHandlers
函数,注意函数传参数的静态资源路径谓 /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
中的应用注册,resourcePathPrefix
和 manifest
全都加入应用路径完成远程注册
[ { "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 准备子项目前台项目
同样修改 build
和 angular.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.看效果
这样,静态资源全都被远程请求过来了
4.这种远程技术可以运用到什么地方
首先组件共享的好处不说了,结合了后端微服务的 真正的
前端微服务而不是依托于 nginx
静态部署的前端微服务
可以优化开发流程,可以做灰度部署了,可以完善 CI 了等等,好处也有,坏处也有。有利有弊,看各自需要吧。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于