前端高级进阶:前端部署的发展历程

本文涉及的产品
对象存储 OSS,20GB 3个月
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
对象存储 OSS,恶意文件检测 1000次 1年
简介: 前端高级进阶:javascript 代码是如何被压缩前端高级进阶:如何更好地优化打包资源前端高级进阶:网站的缓存控制策略最佳实践及注意事项前端高级进阶:在生产环境中使你的 npm i 速度提升 50%前端高级进阶:使用 docker 高效部署你的前端应用前端高级进阶:CICD 下的前端多特性分支环境的部署前端高级进阶:前端部署的发展历程更多文章: 前端工程化系列我在 github 上新建了一个仓库 每日一题,每天一道面试题,欢迎交流。前端面试题小记前端大厂面经大全集计算机基础面试题小计前端一说起刀耕火种,那肯定紧随着前端工程化这一话题。随着 react/vue/ang

前端高级进阶:javascript 代码是如何被压缩
前端高级进阶:如何更好地优化打包资源
前端高级进阶:网站的缓存控制策略最佳实践及注意事项
前端高级进阶:在生产环境中使你的 npm i 速度提升 50%
前端高级进阶:使用 docker 高效部署你的前端应用
前端高级进阶:CICD 下的前端多特性分支环境的部署
前端高级进阶:前端部署的发展历程
更多文章: 前端工程化系列
我在 github 上新建了一个仓库 每日一题,每天一道面试题,欢迎交流。

前端面试题小记
前端大厂面经大全集
计算机基础面试题小计
前端一说起刀耕火种,那肯定紧随着前端工程化这一话题。随着 react/vue/angular,es6+,webpack,babel,typescript 以及 node 的发展,前端已经在逐渐替代过去 script 引 cdn 开发的方式了,掀起了工程化这一大浪潮。得益于工程化的发展与开源社区的良好生态,前端应用的可用性与效率得到了很大提高。

前端以前是刀耕火种,那前端应用部署在以前也是刀耕火种。那前端应用部署的发展得益于什么,随前端工程化带来的副产品?

这只是一部分,而更重要的原因是 devops 的崛起。

为了更清晰地理解前端部署的发展史,了解部署时运维和前端(或者更广泛地说,业务开发人员)的职责划分,当每次前端部署发生改变时,可以思考两个问题

缓存,前端应用中http 的 response header 由谁来配?得益于工程化发展,可以对打包后得到带有 hash 值的文件可以做永久缓存
跨域,/api 的代理配置由谁来配?在开发环境前端可以开个小服务,启用 webpack-dev-server 配置跨域,那生产环境呢
这两个问题都是前端面试时的高频问题,但话语权是否掌握在前端手里

时间来到 React 刚刚发展起来的这一年,这时已经使用 React 开发应用,使用 webpack 来打包。但是前端部署,仍是刀耕火种

本篇文章要求你有一定的 Docker,DevOps 以及前端工程化的知识储备。如果没有的话,本系列文章以及 个人服务器运维指南 中的 Docker 部分会对你有所帮助。

刀耕火种
一台跳板机

一台生产环境服务器

一份部署脚本

前端调着他的 webpack,开心地给运维发了部署邮件并附了一份部署脚本,想着第一次不用套后端的模板,第一次前端可以独立部署。想着自己基础盘进一步扩大,前端不禁开心地笑了

运维照着着前端发过来的部署邮件,一遍又一遍地拉着代码,改着配置,写着 try_files, 配着 proxy_pass。

这时候,前端静态文件由 nginx 托管,nginx 配置文件大致长这个样子

server {
listen 80;
server_name shanyue.tech;

location / {

# 避免非root路径404
try_files $uri $uri/ /index.html;

}

# 解决跨域

  location /api {
    proxy_pass http://api.shanyue.tech;
  }

# 为带 hash 值的文件配置永久缓存
location ~* .(?:css|js)$ {

  try_files $uri =404;
  expires 1y;
  add_header Cache-Control "public";

}

location ~ ^.+..+$ {

  try_files $uri =404;

}
}
复制代码
不过...经常有时候跑不起来

运维抱怨着前端的部署脚本没有标好 node 版本,前端嚷嚷着测试环境没问题

这个时候运维需要费很多心力放在部署上,甚至测试环境的部署上,前端也要费很多心力放在运维如何部署上。这个时候由于怕影响线上环境,上线往往选择在深夜,前端和运维身心俱疲

不过向来如此

鲁迅说,向来如此,那便对么。

这个时候,无论跨域的配置还是缓存的配置,都是运维来管理,运维不懂前端。但配置方式却是前端在提供,而前端并不熟悉 nginx

使用 docker 构建镜像
docker 的引进,很大程度地解决了部署脚本跑不了这个大BUG。dockerfile 即部署脚本,部署脚本即 dockerfile。这也很大程度缓解了前端与运维的摩擦,毕竟前端越来越靠谱了,至少部署脚本没有问题了 (笑

这时候,前端不再提供静态资源,而是提供服务,一个 http 服务

前端写的 dockerfile 大致长这个样子

FROM node:alpine

代表生产环境

ENV PROJECT_ENV production

许多 package 会根据此环境变量,做出不同的行为

另外,在 webpack 中打包也会根据此卖手机游戏账号环境变量做出优化,但是 create-react-app 在打包时会写死该环境变量

ENV NODE_ENV production
WORKDIR /code
ADD . /code
RUN npm install && npm run build && npm install -g http-server
EXPOSE 80

CMD http-server ./public -p 80
复制代码
单单有 dockerfile 也跑不起来,另外前端也开始维护一个 docker-compose.yaml,交给运维执行命令 docker-compose up -d 启动前端应用。前端第一次写 dockerfile 与 docker-compose.yaml,在部署流程中扮演的角色越来越重要。想着自己基础盘进一步扩大,前端又不禁开心地笑了

version: "3"
services:
shici:

build: .
expose:
  - 80

复制代码
运维的 nginx 配置文件大致长这个样子

server {
listen 80;
server_name shanyue.tech;

location / {

proxy_pass http://static.shanyue.tech;

}

location /api {

proxy_pass http://api.shanyue.tech;

}
}
复制代码
运维除了配置 nginx 之外,还要执行一个命令: docker-compose up -d

这时候再思考文章最前面两个问题

缓存,由于从静态文件转换为服务,缓存开始交由前端控制 (但是镜像中的 http-server 不太适合做这件事情)
跨域,跨域仍由运维在 nginx 中配置
前端可以做他应该做的事情中的一部分了,这是一件令人开心的事情

当然,前端对于 dockerfile 的改进也是一个慢慢演进的过程,那这个时候镜像有什么问题呢?

构建镜像体积过大
构建镜像时间过长
使用多阶段构建优化镜像
这中间其实经历了不少坎坷,其中过程如何,详见我的另一篇文章: 如何使用 docker 部署前端应用。

其中主要的优化也是在上述所提到的两个方面

构建镜像体积由 1G+ 变为 10M+
构建镜像时间由 5min+ 变为 1min (视项目复杂程度,大部分时间在构建时间与上传静态资源时间)
FROM node:alpine as builder

ENV PROJECT_ENV production
ENV NODE_ENV production

WORKDIR /code

ADD package.json /code
RUN npm install --production

ADD . /code

npm run uploadCdn 是把静态资源上传至 oss 上的脚本文件,将来会使用 cdn 对 oss 加速

RUN npm run build && npm run uploadCdn

选择更小体积的基础镜像

FROM nginx:alpine
COPY --from=builder code/public/index.html code/public/favicon.ico /usr/share/nginx/html/
COPY --from=builder code/public/static /usr/share/nginx/html/static
复制代码
那它怎么做的

先 ADD package.json /code, 再 npm install --production 之后 Add 所有文件。充分利用镜像缓存,减少构建时间
多阶段构建,大大减小镜像体积
另外还可以有一些小优化,如

npm cache 的基础镜像或者 npm 私有仓库,减少 npm install 时间,减小构建时间
npm install --production 只装必要的包
前端看着自己优化的 dockerfile,想着前几天还被运维吵,说什么磁盘一半的空间都被前端的镜像给占了,想着自己节省了前端镜像几个数量级的体积,为公司好像省了不少服务器的开销,想着自己的基础盘进一步扩大,又不禁开心的笑了

这时候再思考文章最前面两个问题

缓存,缓存由前端控制,缓存在oss上设置,将会使用 cdn 对 oss 加速。此时缓存由前端写脚本控制
跨域,跨域仍由运维在 nginx 中配置
CI/CD 与 gitlab
此时前端成就感爆棚,运维呢?运维还在一遍一遍地上线,重复着一遍又一遍的三个动作用来部署

拉代码
docker-compose up -d
重启 nginx
运维觉得再也不能这么下去了,于是他引进了 CI: 与现有代码仓库 gitlab 配套的 gitlab ci

CI,Continuous Integration,持续集成
CD,Continuous Delivery,持续交付
重要的不是 CI/CD 是什么,重要的是现在运维不用跟着业务上线走了,不需要一直盯着前端部署了。这些都是 CI/CD 的事情了,它被用来做自动化部署。上述提到的三件事交给了 CI/CD

.gitlab-ci.yml 是 gitlab 的 CI 配置文件,它大概长这个样子

deploy:
stage: deploy
only:

- master

script:

- docker-compose up --build -d

tags:

- shell

复制代码
CI/CD 不仅仅更解放了业务项目的部署,也在交付之前大大加强了业务代码的质量,它可以用来 lint,test,package 安全检查,甚至多特性多环境部署,我将会在我以后的文章写这部分事情

我的一个服务器渲染项目 shfshanyue/shici 以前在我的服务器中就是以 docker/docker-compose/gitlab-ci 的方式部署,有兴趣的可以看看它的配置文件

shfshanyue/shici:Dockerfile
shfshanyue/shici:docker-compose.yml
shfshanyue/shici:gitlab-ci.yml
如果你有个人服务器的话,也建议你做一个自己感兴趣的前端应用和配套的后端接口服务,并且配套 CI/CD 把它部署在自己的自己服务器上

而你如果希望结合 github 做 CI/CD,那可以试一试 github + github action

另外,也可以试试 drone.ci,如何部署可以参考我以前的文章: github 上持续集成方案 drone 的简介及部署

使用 kubernetes 部署
随着业务越来越大,镜像越来越多,docker-compose 已经不太能应付,kubernetes 应时而出。这时服务器也从1台变成了多台,多台服务器就会有分布式问题

一门新技术的出现,在解决以前问题的同时也会引进复杂性。

k8s 部署的好处很明显: 健康检查,滚动升级,弹性扩容,快速回滚,资源限制,完善的监控等等

那现在遇到的新问题是什么?

构建镜像的服务器,提供容器服务的服务器,做持续集成的服务器是一台!

需要一个私有的镜像仓库,这是运维的事情,harbor 很快就被运维搭建好了,但是对于前端部署来说,复杂性又提高了

先来看看以前的流程:

前端配置 dockerfile 与 docker-compose
生产环境服务器的 CI runner 拉代码(可以看做以前的运维),docker-compose up -d 启动服务。然后再重启 nginx,做反向代理,对外提供服务
以前的流程有一个问题: 构建镜像的服务器,提供容器服务的服务器,做持续集成的服务器是一台!,所以需要一个私有的镜像仓库,一个能够访问 k8s 集群的持续集成服务器

流程改进之后结合 k8s 的流程如下

前端配置 dockerfile,构建镜像,推到镜像仓库
运维为前端应用配置 k8s 的资源配置文件,kubectl apply -f 时会重新拉取镜像,部署资源
运维问前端,需不需要再扩大下你的基础盘,写一写前端的 k8s 资源配置文件,并且列了几篇文章

使用 k8s 部署你的第一个应用: Pod,Deployment 与 Service
使用 k8s 为你的应用配置域名: Ingress
使用 k8s 为你的域名加上 https
前端看了看后端十几个 k8s 配置文件之后,摇摇头说算了算了

这个时候,gitlab-ci.yaml 差不多长这个样子,配置文件的权限由运维一人管理

deploy:
stage: deploy
only:

- master

script:

- docker build -t harbor.shanyue.tech/fe/shanyue
- docker push harbor.shanyue.tech/fe/shanyue
- kubectl apply -f https://k8s-config.default.svc.cluster.local/shanyue.yaml

tags:

- shell

复制代码
这时候再思考文章最前面两个问题

缓存,缓存由前端控制
跨域,跨域仍由运维控制,在后端 k8s 资源的配置文件中控制 Ingress
使用 helm 部署
这时前端与运维已不太往来,除了偶尔新起项目需要运维帮个忙以外

但好景不长,突然有一天,前端发现自己连个环境变量都没法传!于是经常找运维修改配置文件,运维也不胜其烦

于是有了 helm,如果用一句话解释它,那它就是一个带有模板功能的 k8s 资源配置文件。作为前端,你只需要填参数。更多详细的内容可以参考我以前的文章 使用 helm 部署 k8s 资源

假如我们使用 bitnami/nginx 作为 helm chart,前端可能写的配置文件长这个样子

image:
registry: harbor.shanyue.tech
repository: fe/shanyue
tag: 8a9ac0

ingress:
enabled: true
hosts:

  • name: shanyue.tech
    path: /

tls:

  • hosts:

    - shanyue.tech

    secretName: shanyue-tls

    # livenessProbe:
    # httpGet:
    # path: /
    # port: http
    # initialDelaySeconds: 30
    # timeoutSeconds: 5
    # failureThreshold: 6
    #
    # readinessProbe:
    # httpGet:
    # path: /
    # port: http
    # initialDelaySeconds: 5
    # timeoutSeconds: 3
    # periodSeconds: 5

复制代码
这时候再思考文章最前面两个问题

缓存,缓存由前端控制
跨域,跨域由后端控制,配置在后端 Chart 的配置文件 values.yaml 中
到了这时前端和运维的职责所在呢?

前端需要做的事情有:

写前端构建的 dockerfile,这只是一次性的工作,而且有了参考
使用 helm 部署时指定参数
那运维要做的事情呢

提供一个供所有前端项目使用的 helm chart,甚至不用提供,如果运维比较懒那就就使用 bitnami/nginx 吧。也是一次性工作
提供一个基于 helm 的工具,禁止业务过多的权限,甚至不用提供,如果运维比较懒那就直接使用 helm
这时前端可以关注于自己的业务,运维可以关注于自己的云原生,职责划分从未这般清楚

统一前端部署平台
后来运维觉得前端应用的本质是一堆静态文件,较为单一,容易统一化,来避免各个前端镜像质量的参差不齐。于是运维准备了一个统一的 node 基础镜像,做了一个前端统一部署平台,而这个平台可以做什么呢

CI/CD: 当你 push 代码到仓库的特定分支会自动部署
http headers: 你可以定制资源的 http header,从而可以做缓存优化等
http redirect/rewrite: 如果一个 nginx,这样可以配置 /api,解决跨域问题
hostname: 你可以设置域名
CDN: 把你的静态资源推到 CDN
https: 为你准备证书
Prerender: 结合 SPA,做预渲染
前端再也不需要构建镜像,上传 CDN 了,他只需要写一份配置文件就可以了,大致长这个样子

build:
command: npm run build
dist: /dist

hosts:

  • name: shanyue.tech
    path: /

headers:

  • location: /*
    values:

    • cache-control: max-age=7200
  • location: assets/*
    values:

    • cache-control: max-age=31536000

redirects:

复制代码
此时,前端只需要写一份配置文件,就可以配置缓存,配置 proxy,做应该属于前端做的一切,而运维也再也不需要操心前端部署的事情了

前端看着自己刚刚写好的配置文件,怅然若失的样子...

不过一般只有大厂会有这么完善的前端部署平台,如果你对它有兴趣,你可以尝试下 netlify,可以参考我的文章: 使用 netlify 部署你的前端应用

服务端渲染与后端部署
大部分前端应用本质上是静态资源,剩下的少部分就是服务端渲染了,服务端渲染的本质上是一个后端服务,它的部署可以视为后端部署

后端部署的情况更为复杂,比如

配置服务,后端需要访问敏感数据,但又不能把敏感数据放在代码仓库。你可以在 environment variables, consul 或者 k8s configmap 中维护
上下链路服务,你需要依赖数据库,上游服务
访问控制,限制 IP,黑白名单
RateLimit
等等
我将在以后的文章分享如何在 k8s 中部署一个后端

小结
随着 devops 的发展,前端部署越来越简单,可控性也越来越高,建议所有人都稍微学习一下 devops 的东西。

道阻且长,行则将至。

相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
目录
相关文章
|
16天前
|
缓存 前端开发 JavaScript
前端serverless探索之组件单独部署时,利用rxjs实现业务状态与vue-react-angular等框架的响应式状态映射
本文深入探讨了如何将RxJS与Vue、React、Angular三大前端框架进行集成,通过抽象出辅助方法`useRx`和`pushPipe`,实现跨框架的状态管理。具体介绍了各框架的响应式机制,展示了如何将RxJS的Observable对象转化为框架的响应式数据,并通过示例代码演示了使用方法。此外,还讨论了全局状态源与WebComponent的部署优化,以及一些实践中的改进点。这些方法不仅简化了异步编程,还提升了代码的可读性和可维护性。
|
1天前
|
前端开发 JavaScript 安全
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第7天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤。包括项目准备、安装 `javascript-obfuscator`、配置 Vite 构建以应用混淆,以及最终构建项目进行混淆。通过这些步骤,可以有效提升前端代码的安全性,防止被他人轻易分析和盗用。
|
1月前
|
前端开发 JavaScript 应用服务中间件
linux安装nginx和前端部署vue项目(实际测试react项目也可以)
本文是一篇详细的教程,介绍了如何在Linux系统上安装和配置nginx,以及如何将打包好的前端项目(如Vue或React)上传和部署到服务器上,包括了常见的错误处理方法。
179 0
linux安装nginx和前端部署vue项目(实际测试react项目也可以)
|
2月前
|
前端开发 应用服务中间件 nginx
docker部署本地前端项目思路
docker部署本地前端项目思路
37 7
|
3月前
|
前端开发 应用服务中间件 nginx
前端服务器部署方式
【8月更文挑战第25天】前端服务器部署方式
77 1
|
3月前
|
负载均衡 前端开发 应用服务中间件
使用Nginx配置SSL以及部署前端项目
本文介绍了如何使用Nginx配置SSL证书以启用HTTPS,并展示了如何通过Nginx部署前端项目,包括配置SSL证书、设置代理和负载均衡的示例。
110 2
|
3月前
|
缓存 前端开发 应用服务中间件
看看高手是怎么部署前端代码的
【8月更文挑战第8天】从简单的前端项目部署开始,构建dist文件夹并通过Nginx代理接口请求,以解决跨域问题。为进一步优化大型系统的性能及稳定性,需采用高级部署策略。例如,利用CDN分发静态资源并采用缓存控制减少带宽消耗,通过文件哈希值更新URL确保资源按需刷新。面对大规模部署挑战,采用非覆盖式发布方法避免样式错乱风险,并通过灰度部署逐步验证新版功能,确保服务平稳过渡。借助Nginx实现流量切分,可灵活调整新旧版本流量比例,有效降低上线风险。
57 3
|
4月前
|
JavaScript 前端开发 NoSQL
前端node如何学习进阶知识
【7月更文挑战第8天】 深化JavaScript基础,精通Node.js核心模块(如fs、http)与事件循环机制,学习Express框架及异步编程(回调、Promise、async/await),掌握数据库交互,参与实战项目,关注Node.js最新技术和最佳实践,以此提升进阶技能。
44 8
|
4月前
|
前端开发 应用服务中间件
前端项目部署问题总结
【7月更文挑战第13天】
58 1
|
4月前
|
缓存 前端开发 JavaScript
高级前端常见的面试题?
【7月更文挑战第11天】 **高级前端面试聚焦候选人的技术深度、项目实战、问题解决及技术趋势洞察。涉及React/Vue生命周期、Redux/Vuex状态管理、Webpack优化、HTTP/HTTPS安全、性能提升策略、PWA、GraphQL、WebAssembly、安全性议题及项目管理。通过回答,展现候选人技术广度与应对复杂场景的能力。**
95 1
下一篇
无影云桌面