如何部署一个 Web 应用?前端开发者(Frontend Developer)日常工作不仅仅是画界面,积累到一定程度,必须对自己的交付物(以 Web 界面呈现的应用)的部署方式和数据资源的存储过程有所了解,就像我之前一篇文章所说的,弄清楚整个过程可以积累知识,并能从一开始就通过架构的对比来衡量 ROI。下面谈谈我经历的交付方式以供参考:

GitHub Pages

如果产出的是纯静态的页面用于做一些展示,比如个人主页或者项目介绍,那么 GitHub Pages 就非常合适。直接创建项目,添加你的 index.html 就可以用于展示了。如果需要 webpack 编译,最好选择一个专门用于部署的分支,再配合脚本或者 GitHub Actions(workflows)可以很方便地自动化部署页面。

插件

不论是浏览器插件、编辑器插件还是特定软件(Sketch和iTerm2等) 插件,只要是插件,就必须跟宿主环境耦合,按照其要求的方式:放在固定文件夹或上传到对应服务器。

前后端不分离

在前端开发刀耕火种的岁月里,没有现代的 MVC 和 MVVM 开发框架,前后端往往是不分离的。为了快速生成 HTML,我们需要借助模板语言,实现用户界面与业务数据尽可能地分离,这样就可以将模板代码嵌入到后端语言所启动的 Web 服务里,运行时用模板引擎和业务数据渲染出标准的 HTML 文件。常见的模板引擎见下图:

templateEngine
这种情况的部署方式按照后端指定的方式和路径即可。由于 building 和 hosting 不分离,运行时需要先调用依赖获取数据后进行 compile,用户访问速度会受到影响。在生产环境中需服务端开发人员和运维人员配合,才能构建出高性能、高可靠和安全的站点。

前后端分离

借助 Ajax 和现代开发框架,我们可以实现完全的前后端分离,也就是前端只关心静态文件,使用网络请求来获取业务数据。所以这种模式下的部署,不论是 CSR 还是 SSR,最终都是静态文件的部署,有两种方式:

  1. 借助 Apach 和 Nginx 等 Web 服务器,自己动手部署到服务器上。大公司内部往往有静态文件服务器节点,所以不需要开发人员手动搭建;

  2. 静态文件最好的归宿是 CDN,其实现机制是利用全局负载均衡系统根据客户端的 IP 地址、请求的 URL 和相应的物理地址区域,获取到距离客户端最近且有相应资源的缓存服务器,将其地址返回即可。借助缓存和分发的优势,我们可以加速访问静态资源。一般公司内部的静态文件节点往往也是绑定了 CDN 厂商提供的服务。

静态文件(Markup)产出后,结合 API 和 JavaScript,就可以创造出任何想要的页面,即 JAMStack

Generate markup, decorate with JavaScript and APIs.

ServerLess

运维层面的 ServerLess 指的是开发者只关心业务代码,对运行时的环境和资源通过 KVM 和 Docker 等虚拟化和容器技术,隔离了硬件以及运行在这之上的操作系统,从而实现根据业务需要地动态扩缩容。这就要求我们的应用尽可能拆分,以实现无状态地函数调用,这也就是 MicroService 和 FaaS 的概念。服务端需要做的本质上跟上文的 JAMStack 同一理念:

Write locally, compile to the cloud.

微前端

对应到前端开发者,就有了微前端的概念,简单理解就是在大型前端项目中,多人分别开发各个子模块,再接入到一个总的项目(可以理解为壳子)中,各个模块协作来完成一个大而全的项目。利用微件拆分来达到工程拆分治理的方案,不依赖于整体工程的技术栈,解耦开发和部署,可以解决工程膨胀、开发维护困难等问题,同时可以简化大公司内部的单点登录和权限管理等内部服务接入成本。这种模式下,子模块的前端部署,如果像之前提到的方式,分开部署和运行,会导致需要重新鉴权(也就是接入公司层面的登录和权限),发挥不出微服务的好处。

解决办法是在主工程接入一套鉴权,子模块全部走代理流程。子模块上线到静态文件节点后,静态资源通过主工程反向代理从而运行在相同的路径中,而请求全部用相对路径,在主工程后端来转发各个模块对应的真实请求 API 地址,从而抹平差异和解决跨域。

在开发中,我碰到的能体现真正的面向对象编程的场景是一个生成新闻的项目。所有新闻内容通过 SSR 生成静态 HTML,存储到 CDN ,而给 CDN 配置一个面向业务的域名,这样访问某个新闻页其实访问的是 CDN 上对应的文件,从而避免了使用具体服务器面临的扩容和大量请求的可用性等问题。所以真正实现了没有服务器。

微服务

通常配合公司内部的云基础应用建设,前端可以往前走出边界探索后端服务,有两种常见的应用:

  1. 代理静态文件

    也就是帮助 SPA 部署静态文件。通过 NodeJs(或其他) 服务建设一个中台服务,接收 Webpack 打包后的文件到固定的目录下,然后提供访问即可。这样方便简单的类似营销活动和招聘页面等上线运行,省去业务开发者申请域名和服务器等运维工作。 如有需要,也可以建设反向代理的配置来支持自定义域名,以及实现静态站点发布的版本历史记录和回滚等功能。

  2. 作为服务

    依赖云的基础建设,可以将任何一段特定功能的代码放在云端执行,方便部署的同时赋能,比如可以动态扩缩容、方便统计和日志记录等。比如一个上传图片服务,通过配置文件声明依赖(如系统要求、NodeJs 版本和第三方依赖等)后,可直接部署到云端供全公司调用。

结语

重剑无锋,没有最好的方式!根据业务的需要使用最合适的部署方式才是最优解。